diff --git a/provider/internal/resources_gen/100_openwhisk_resource.go b/provider/internal/resources_gen/100_openwhisk_resource.go
deleted file mode 100644
index c4cbf39..0000000
--- a/provider/internal/resources_gen/100_openwhisk_resource.go
+++ /dev/null
@@ -1,382 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: openwhisk
-// Service ID: 100
-
-var _ resource.Resource = &OpenwhiskResource{}
-var _ resource.ResourceWithModifyPlan = &OpenwhiskResource{}
-var _ resource.ResourceWithImportState = &OpenwhiskResource{}
-
-type OpenwhiskResource struct {
- client *core.UniversalClient
-}
-
-type OpenwhiskModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- Username types.String `tfsdk:"username"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewOpenwhiskResource() resource.Resource {
- return &OpenwhiskResource{}
-}
-
-func (r *OpenwhiskResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_openwhisk"
-}
-
-func (r *OpenwhiskResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Платформа для развертывания Не изменяется после создания."},
- "username": schema.StringAttribute{Required: true, MarkdownDescription: "Имя пользователя Openwhisk Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *OpenwhiskResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *OpenwhiskModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *OpenwhiskModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan OpenwhiskModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.Username.IsNull() && !plan.Username.IsUnknown() && !state.Username.IsNull() && !state.Username.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.Username.ValueString(), state.Username.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить username", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.ResourceRealm.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
- if config.ResourceRealm.IsUnknown() {
- return
- }
- if config.Username.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "username is required.")
- return
- }
- if config.Username.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 64: resources_core.FormatString(config.Username),
- 281: resources_core.FormatString(config.ResourceRealm),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 100, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *OpenwhiskResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data OpenwhiskModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.ResourceRealm.IsNull() || data.ResourceRealm.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
- if data.Username.IsNull() || data.Username.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "username is required.")
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 100, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 64: resources_core.FormatString(data.Username),
- 281: resources_core.FormatString(data.ResourceRealm),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 100, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 100, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "username", Field: "Username", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *OpenwhiskResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state OpenwhiskModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 100, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "username", Field: "Username", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *OpenwhiskResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan OpenwhiskModel
- var state OpenwhiskModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{}
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 100, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "username", Field: "Username", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *OpenwhiskResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state OpenwhiskModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "delete"
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *OpenwhiskResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *OpenwhiskResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/109_zones_v2_record_resource.go b/provider/internal/resources_gen/109_zones_v2_record_resource.go
deleted file mode 100644
index 9cc2073..0000000
--- a/provider/internal/resources_gen/109_zones_v2_record_resource.go
+++ /dev/null
@@ -1,362 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: zones_v2
-// Subresource: record
-
-var _ resource.Resource = &ZonesV2RecordResource{}
-
-// ZonesV2RecordResource manages a subresource via operations.
-type ZonesV2RecordResource struct {
- client *core.UniversalClient
-}
-
-type ZonesV2RecordModel struct {
- ID types.String `tfsdk:"id"`
- ZonesV2ID types.String `tfsdk:"zones_v2_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- RecordInput types.String `tfsdk:"record_input"`
- RecordName types.String `tfsdk:"record_name"`
- RecordTTL types.Int64 `tfsdk:"record_t_t_l"`
- RecordType types.String `tfsdk:"record_type"`
-}
-
-func NewZonesV2RecordResource() resource.Resource {
- return &ZonesV2RecordResource{}
-}
-
-func (r *ZonesV2RecordResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_zones_v2_record"
-}
-
-func (r *ZonesV2RecordResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "zones_v2_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "record_input": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[{}]"), MarkdownDescription: "Валидация производится только после запуска операции. Если при указанном типе будет указано некорректно значение, это будет описано в логе ошибки операции"},
- "record_name": schema.StringAttribute{Required: true, MarkdownDescription: "Имя зоны в конце проставляется автоматически Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- "record_t_t_l": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(3600), MarkdownDescription: "Time-to-Leave записи. Раз в какое время запись будет обновлена"},
- "record_type": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("A")},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *ZonesV2RecordResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan ZonesV2RecordModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.RecordName.IsNull() || plan.RecordName.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "record_name is required.")
- return
- }
-
- instanceUID := strings.TrimSpace(plan.ZonesV2ID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{
- "recordName": resources_core.FormatString(plan.RecordName),
- }
- identityCodes := []string{
- "recordName",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("record", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "record", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "recordName": resources_core.FormatString(plan.RecordName),
- "recordTTL": resources_core.FormatInt64(plan.RecordTTL),
- "recordType": resources_core.FormatString(plan.RecordType),
- "recordInput": resources_core.FormatString(plan.RecordInput),
- })
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_record", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_record", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "record", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "record", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "record", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *ZonesV2RecordResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state ZonesV2RecordModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *ZonesV2RecordResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan ZonesV2RecordModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "modify_record" == "" {
- var state ZonesV2RecordModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.ZonesV2ID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{
- "recordName": resources_core.FormatString(plan.RecordName),
- "recordTTL": resources_core.FormatInt64(plan.RecordTTL),
- "recordType": resources_core.FormatString(plan.RecordType),
- "recordInput": resources_core.FormatString(plan.RecordInput),
- })
-
- idParams := map[string]string{
- "recordName": resources_core.FormatString(plan.RecordName),
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "modify_record", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "record", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *ZonesV2RecordResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state ZonesV2RecordModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "delete_record" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.ZonesV2ID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{
- "recordName": resources_core.FormatString(state.RecordName),
- }
- identityCodes := []string{
- "recordName",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("record", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "recordName": resources_core.FormatString(state.RecordName),
- })
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "delete_record", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *ZonesV2RecordResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/109_zones_v2_resource.go b/provider/internal/resources_gen/109_zones_v2_resource.go
deleted file mode 100644
index f07aab8..0000000
--- a/provider/internal/resources_gen/109_zones_v2_resource.go
+++ /dev/null
@@ -1,484 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: zones_v2
-// Service ID: 109
-
-var _ resource.Resource = &ZonesV2Resource{}
-var _ resource.ResourceWithModifyPlan = &ZonesV2Resource{}
-var _ resource.ResourceWithImportState = &ZonesV2Resource{}
-
-type ZonesV2Resource struct {
- client *core.UniversalClient
-}
-
-type ZonesV2Model struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- Records types.String `tfsdk:"records"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- ZoneExpire types.Int64 `tfsdk:"zone_expire"`
- ZoneKind types.String `tfsdk:"zone_kind"`
- ZoneMastersForSlave types.String `tfsdk:"zone_masters_for_slave"`
- ZoneName types.String `tfsdk:"zone_name"`
- ZoneRefresh types.Int64 `tfsdk:"zone_refresh"`
- ZoneRetry types.Int64 `tfsdk:"zone_retry"`
- ZoneTTL types.Int64 `tfsdk:"zone_t_t_l"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewZonesV2Resource() resource.Resource {
- return &ZonesV2Resource{}
-}
-
-func (r *ZonesV2Resource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_zones_v2"
-}
-
-func (r *ZonesV2Resource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "records": schema.StringAttribute{Required: true},
- "resource_realm": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("powerdns"), MarkdownDescription: "Не изменяется после создания."},
- "zone_expire": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(3600000), MarkdownDescription: "Время в течение которого вторичный DNS будет пытаться завершить синхронизацию зоны с первичным Не изменяется после создания."},
- "zone_kind": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("NATIVE"), MarkdownDescription: "Тип зоны Не изменяется после создания."},
- "zone_masters_for_slave": schema.StringAttribute{Optional: true, MarkdownDescription: "Использовать если выбран тип SLAVE. IP адреса в формате через пробел для настройки Master-серверов Не изменяется после создания."},
- "zone_name": schema.StringAttribute{Required: true, MarkdownDescription: "Имя зоны Не изменяется после создания."},
- "zone_refresh": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(86400), MarkdownDescription: "Время ожидания ответа вторичного DNS перед запросом SOA-записи с первичных серверов Не изменяется после создания."},
- "zone_retry": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(7200), MarkdownDescription: "Время в течение которого сервер повторно попробует синхронизировать информацию с первичных DNS-серверов Не изменяется после создания."},
- "zone_t_t_l": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(86400), MarkdownDescription: "Время, в течение которого информация будет кешироваться другими DNS-серверами Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *ZonesV2Resource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *ZonesV2Model
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *ZonesV2Model
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan ZonesV2Model
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ZoneExpire.IsNull() && !plan.ZoneExpire.IsUnknown() && !state.ZoneExpire.IsNull() && !state.ZoneExpire.IsUnknown() {
- if plan.ZoneExpire.ValueInt64() != state.ZoneExpire.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить zone_expire", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ZoneKind.IsNull() && !plan.ZoneKind.IsUnknown() && !state.ZoneKind.IsNull() && !state.ZoneKind.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ZoneKind.ValueString(), state.ZoneKind.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить zone_kind", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ZoneMastersForSlave.IsNull() && !plan.ZoneMastersForSlave.IsUnknown() && !state.ZoneMastersForSlave.IsNull() && !state.ZoneMastersForSlave.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ZoneMastersForSlave.ValueString(), state.ZoneMastersForSlave.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить zone_masters_for_slave", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ZoneName.IsNull() && !plan.ZoneName.IsUnknown() && !state.ZoneName.IsNull() && !state.ZoneName.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ZoneName.ValueString(), state.ZoneName.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить zone_name", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ZoneRefresh.IsNull() && !plan.ZoneRefresh.IsUnknown() && !state.ZoneRefresh.IsNull() && !state.ZoneRefresh.IsUnknown() {
- if plan.ZoneRefresh.ValueInt64() != state.ZoneRefresh.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить zone_refresh", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ZoneRetry.IsNull() && !plan.ZoneRetry.IsUnknown() && !state.ZoneRetry.IsNull() && !state.ZoneRetry.IsUnknown() {
- if plan.ZoneRetry.ValueInt64() != state.ZoneRetry.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить zone_retry", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ZoneTTL.IsNull() && !plan.ZoneTTL.IsUnknown() && !state.ZoneTTL.IsNull() && !state.ZoneTTL.IsUnknown() {
- if plan.ZoneTTL.ValueInt64() != state.ZoneTTL.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить zone_t_t_l", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.Records.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "records is required.")
- return
- }
- if config.Records.IsUnknown() {
- return
- }
- if config.ZoneName.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "zone_name is required.")
- return
- }
- if config.ZoneName.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 761: resources_core.FormatString(config.ZoneName),
- 762: resources_core.FormatString(config.ZoneKind),
- 763: resources_core.FormatString(config.ZoneMastersForSlave),
- 764: resources_core.FormatInt64(config.ZoneRefresh),
- 765: resources_core.FormatInt64(config.ZoneRetry),
- 766: resources_core.FormatInt64(config.ZoneExpire),
- 767: resources_core.FormatInt64(config.ZoneTTL),
- 768: resources_core.FormatString(config.ResourceRealm),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 109, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *ZonesV2Resource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data ZonesV2Model
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.Records.IsNull() || data.Records.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "records is required.")
- return
- }
- if data.ZoneName.IsNull() || data.ZoneName.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "zone_name is required.")
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 109, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 761: resources_core.FormatString(data.ZoneName),
- 762: resources_core.FormatString(data.ZoneKind),
- 763: resources_core.FormatString(data.ZoneMastersForSlave),
- 764: resources_core.FormatInt64(data.ZoneRefresh),
- 765: resources_core.FormatInt64(data.ZoneRetry),
- 766: resources_core.FormatInt64(data.ZoneExpire),
- 767: resources_core.FormatInt64(data.ZoneTTL),
- 768: resources_core.FormatString(data.ResourceRealm),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 109, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 109, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "records", Field: "Records", Type: "array-map-fixed"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "zoneExpire", Field: "ZoneExpire", Type: "int64"},
- {Code: "zoneKind", Field: "ZoneKind", Type: "string"},
- {Code: "zoneMastersForSlave", Field: "ZoneMastersForSlave", Type: "string"},
- {Code: "zoneName", Field: "ZoneName", Type: "string"},
- {Code: "zoneRefresh", Field: "ZoneRefresh", Type: "int64"},
- {Code: "zoneRetry", Field: "ZoneRetry", Type: "int64"},
- {Code: "zoneTTL", Field: "ZoneTTL", Type: "int64"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *ZonesV2Resource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state ZonesV2Model
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 109, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "records", Field: "Records", Type: "array-map-fixed"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "zoneExpire", Field: "ZoneExpire", Type: "int64"},
- {Code: "zoneKind", Field: "ZoneKind", Type: "string"},
- {Code: "zoneMastersForSlave", Field: "ZoneMastersForSlave", Type: "string"},
- {Code: "zoneName", Field: "ZoneName", Type: "string"},
- {Code: "zoneRefresh", Field: "ZoneRefresh", Type: "int64"},
- {Code: "zoneRetry", Field: "ZoneRetry", Type: "int64"},
- {Code: "zoneTTL", Field: "ZoneTTL", Type: "int64"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *ZonesV2Resource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan ZonesV2Model
- var state ZonesV2Model
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.Records.IsNull() != state.Records.IsNull() || plan.Records.IsUnknown() != state.Records.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.Records.IsNull() && !plan.Records.IsUnknown() && !state.Records.IsNull() && !state.Records.IsUnknown() {
- if !strings.EqualFold(plan.Records.ValueString(), state.Records.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 769: resources_core.FormatString(plan.Records),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 109, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "records", Field: "Records", Type: "array-map-fixed"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "zoneExpire", Field: "ZoneExpire", Type: "int64"},
- {Code: "zoneKind", Field: "ZoneKind", Type: "string"},
- {Code: "zoneMastersForSlave", Field: "ZoneMastersForSlave", Type: "string"},
- {Code: "zoneName", Field: "ZoneName", Type: "string"},
- {Code: "zoneRefresh", Field: "ZoneRefresh", Type: "int64"},
- {Code: "zoneRetry", Field: "ZoneRetry", Type: "int64"},
- {Code: "zoneTTL", Field: "ZoneTTL", Type: "int64"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *ZonesV2Resource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state ZonesV2Model
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "delete"
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *ZonesV2Resource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *ZonesV2Resource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/110_dnszone_resource.go b/provider/internal/resources_gen/110_dnszone_resource.go
deleted file mode 100644
index fab197b..0000000
--- a/provider/internal/resources_gen/110_dnszone_resource.go
+++ /dev/null
@@ -1,495 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: dnszone
-// Service ID: 110
-
-var _ resource.Resource = &DnszoneResource{}
-var _ resource.ResourceWithModifyPlan = &DnszoneResource{}
-var _ resource.ResourceWithImportState = &DnszoneResource{}
-
-type DnszoneResource struct {
- client *core.UniversalClient
-}
-
-type DnszoneModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- ZoneEmail types.String `tfsdk:"zone_email"`
- ZoneKind types.String `tfsdk:"zone_kind"`
- ZoneMastersForSlave types.String `tfsdk:"zone_masters_for_slave"`
- ZoneName types.String `tfsdk:"zone_name"`
- ZoneTimeToExpire types.String `tfsdk:"zone_time_to_expire"`
- ZoneTimeToLive types.String `tfsdk:"zone_time_to_live"`
- ZoneTimeToRefresh types.String `tfsdk:"zone_time_to_refresh"`
- ZoneTimeToRetry types.String `tfsdk:"zone_time_to_retry"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewDnszoneResource() resource.Resource {
- return &DnszoneResource{}
-}
-
-func (r *DnszoneResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_dnszone"
-}
-
-func (r *DnszoneResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "resource_realm": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("powerdns"), MarkdownDescription: "Платформа для развертывания Не изменяется после создания."},
- "zone_email": schema.StringAttribute{Required: true, MarkdownDescription: "Контактный e-mail Не изменяется после создания."},
- "zone_kind": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("NATIVE"), MarkdownDescription: "Тип зоны Не изменяется после создания."},
- "zone_masters_for_slave": schema.StringAttribute{Optional: true, MarkdownDescription: "Использовать если выбран тип SLAVE. IP адреса в формате через пробел для настройки Master-серверов Не изменяется после создания."},
- "zone_name": schema.StringAttribute{Required: true, MarkdownDescription: "Имя зоны Не изменяется после создания."},
- "zone_time_to_expire": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("3600000"), MarkdownDescription: "Время в течение которого вторичный DNS будет пытаться завершить синхронизацию зоны с первичным Не изменяется после создания."},
- "zone_time_to_live": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("86400"), MarkdownDescription: "Время, в течение которого информация будет кешироваться другими DNS-серверами Не изменяется после создания."},
- "zone_time_to_refresh": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("86400"), MarkdownDescription: "Время ожидания ответа вторичного DNS перед запросом SOA-записи с первичных серверов Не изменяется после создания."},
- "zone_time_to_retry": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("7200"), MarkdownDescription: "Время в течение которого сервер повторно попробует синхронизировать информацию с первичных DNS-серверов Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *DnszoneResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *DnszoneModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *DnszoneModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan DnszoneModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ZoneEmail.IsNull() && !plan.ZoneEmail.IsUnknown() && !state.ZoneEmail.IsNull() && !state.ZoneEmail.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ZoneEmail.ValueString(), state.ZoneEmail.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить zone_email", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ZoneKind.IsNull() && !plan.ZoneKind.IsUnknown() && !state.ZoneKind.IsNull() && !state.ZoneKind.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ZoneKind.ValueString(), state.ZoneKind.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить zone_kind", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ZoneMastersForSlave.IsNull() && !plan.ZoneMastersForSlave.IsUnknown() && !state.ZoneMastersForSlave.IsNull() && !state.ZoneMastersForSlave.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ZoneMastersForSlave.ValueString(), state.ZoneMastersForSlave.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить zone_masters_for_slave", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ZoneName.IsNull() && !plan.ZoneName.IsUnknown() && !state.ZoneName.IsNull() && !state.ZoneName.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ZoneName.ValueString(), state.ZoneName.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить zone_name", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ZoneTimeToExpire.IsNull() && !plan.ZoneTimeToExpire.IsUnknown() && !state.ZoneTimeToExpire.IsNull() && !state.ZoneTimeToExpire.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ZoneTimeToExpire.ValueString(), state.ZoneTimeToExpire.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить zone_time_to_expire", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ZoneTimeToLive.IsNull() && !plan.ZoneTimeToLive.IsUnknown() && !state.ZoneTimeToLive.IsNull() && !state.ZoneTimeToLive.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ZoneTimeToLive.ValueString(), state.ZoneTimeToLive.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить zone_time_to_live", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ZoneTimeToRefresh.IsNull() && !plan.ZoneTimeToRefresh.IsUnknown() && !state.ZoneTimeToRefresh.IsNull() && !state.ZoneTimeToRefresh.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ZoneTimeToRefresh.ValueString(), state.ZoneTimeToRefresh.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить zone_time_to_refresh", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ZoneTimeToRetry.IsNull() && !plan.ZoneTimeToRetry.IsUnknown() && !state.ZoneTimeToRetry.IsNull() && !state.ZoneTimeToRetry.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ZoneTimeToRetry.ValueString(), state.ZoneTimeToRetry.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить zone_time_to_retry", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.ZoneEmail.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "zone_email is required.")
- return
- }
- if config.ZoneEmail.IsUnknown() {
- return
- }
- if config.ZoneName.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "zone_name is required.")
- return
- }
- if config.ZoneName.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 66: resources_core.FormatString(config.ZoneEmail),
- 67: resources_core.FormatString(config.ZoneName),
- 68: resources_core.FormatString(config.ZoneKind),
- 69: resources_core.FormatString(config.ZoneMastersForSlave),
- 70: resources_core.FormatString(config.ZoneTimeToRefresh),
- 71: resources_core.FormatString(config.ZoneTimeToRetry),
- 72: resources_core.FormatString(config.ZoneTimeToExpire),
- 73: resources_core.FormatString(config.ZoneTimeToLive),
- 284: resources_core.FormatString(config.ResourceRealm),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 110, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *DnszoneResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data DnszoneModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.ZoneEmail.IsNull() || data.ZoneEmail.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "zone_email is required.")
- return
- }
- if data.ZoneName.IsNull() || data.ZoneName.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "zone_name is required.")
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 110, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 66: resources_core.FormatString(data.ZoneEmail),
- 67: resources_core.FormatString(data.ZoneName),
- 68: resources_core.FormatString(data.ZoneKind),
- 69: resources_core.FormatString(data.ZoneMastersForSlave),
- 70: resources_core.FormatString(data.ZoneTimeToRefresh),
- 71: resources_core.FormatString(data.ZoneTimeToRetry),
- 72: resources_core.FormatString(data.ZoneTimeToExpire),
- 73: resources_core.FormatString(data.ZoneTimeToLive),
- 284: resources_core.FormatString(data.ResourceRealm),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 110, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 110, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "zoneEmail", Field: "ZoneEmail", Type: "string"},
- {Code: "zoneKind", Field: "ZoneKind", Type: "string"},
- {Code: "zoneMastersForSlave", Field: "ZoneMastersForSlave", Type: "string"},
- {Code: "zoneName", Field: "ZoneName", Type: "string"},
- {Code: "zoneTimeToExpire", Field: "ZoneTimeToExpire", Type: "string"},
- {Code: "zoneTimeToLive", Field: "ZoneTimeToLive", Type: "string"},
- {Code: "zoneTimeToRefresh", Field: "ZoneTimeToRefresh", Type: "string"},
- {Code: "zoneTimeToRetry", Field: "ZoneTimeToRetry", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *DnszoneResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state DnszoneModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 110, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "zoneEmail", Field: "ZoneEmail", Type: "string"},
- {Code: "zoneKind", Field: "ZoneKind", Type: "string"},
- {Code: "zoneMastersForSlave", Field: "ZoneMastersForSlave", Type: "string"},
- {Code: "zoneName", Field: "ZoneName", Type: "string"},
- {Code: "zoneTimeToExpire", Field: "ZoneTimeToExpire", Type: "string"},
- {Code: "zoneTimeToLive", Field: "ZoneTimeToLive", Type: "string"},
- {Code: "zoneTimeToRefresh", Field: "ZoneTimeToRefresh", Type: "string"},
- {Code: "zoneTimeToRetry", Field: "ZoneTimeToRetry", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *DnszoneResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan DnszoneModel
- var state DnszoneModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{}
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 110, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "zoneEmail", Field: "ZoneEmail", Type: "string"},
- {Code: "zoneKind", Field: "ZoneKind", Type: "string"},
- {Code: "zoneMastersForSlave", Field: "ZoneMastersForSlave", Type: "string"},
- {Code: "zoneName", Field: "ZoneName", Type: "string"},
- {Code: "zoneTimeToExpire", Field: "ZoneTimeToExpire", Type: "string"},
- {Code: "zoneTimeToLive", Field: "ZoneTimeToLive", Type: "string"},
- {Code: "zoneTimeToRefresh", Field: "ZoneTimeToRefresh", Type: "string"},
- {Code: "zoneTimeToRetry", Field: "ZoneTimeToRetry", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *DnszoneResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state DnszoneModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "delete"
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *DnszoneResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *DnszoneResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/111_dnsrecord_resource.go b/provider/internal/resources_gen/111_dnsrecord_resource.go
deleted file mode 100644
index b28d2d8..0000000
--- a/provider/internal/resources_gen/111_dnsrecord_resource.go
+++ /dev/null
@@ -1,546 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: dnsrecord
-// Service ID: 111
-
-var _ resource.Resource = &DnsrecordResource{}
-var _ resource.ResourceWithModifyPlan = &DnsrecordResource{}
-var _ resource.ResourceWithImportState = &DnsrecordResource{}
-
-type DnsrecordResource struct {
- client *core.UniversalClient
-}
-
-type DnsrecordModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- RecordInput types.String `tfsdk:"record_input"`
- RecordName types.String `tfsdk:"record_name"`
- RecordTTL types.Int64 `tfsdk:"record_t_t_l"`
- RecordType types.String `tfsdk:"record_type"`
- ZoneUid types.String `tfsdk:"zone_uid"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewDnsrecordResource() resource.Resource {
- return &DnsrecordResource{}
-}
-
-func (r *DnsrecordResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_dnsrecord"
-}
-
-func (r *DnsrecordResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "record_input": schema.StringAttribute{Required: true, MarkdownDescription: "Значение. Необходима валидация, в зависимости от типа записи. Должно быть заменено на UUID-внешнийIP"},
- "record_name": schema.StringAttribute{Required: true, MarkdownDescription: "Имя записи. Имя зоны в конце проставляется автоматически Не изменяется после создания."},
- "record_t_t_l": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(3600), MarkdownDescription: "Time-to-Leave записи. Раз в какое время запись будет обновлена Не изменяется после создания."},
- "record_type": schema.StringAttribute{Required: true, MarkdownDescription: "Тип DNS-записи Не изменяется после создания."},
- "zone_uid": schema.StringAttribute{Optional: true, Computed: true, MarkdownDescription: "UUID экземпляра услуги DNS-зоны Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *DnsrecordResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *DnsrecordModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *DnsrecordModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan DnsrecordModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- // FIX(uuid-case): resolve ref_svc params НЕ делаем в ModifyPlan.
- // Terraform правило: plan ОБЯЗАН равняться config для user-provided атрибутов.
- // Resolve (displayName → UUID или uppercase → lowercase) нужен только для
- // API-вызова в Create/Update. Делать его здесь = менять plan = ошибка
- // "Provider produced invalid plan: planned value does not match config value".
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.RecordName.IsNull() && !plan.RecordName.IsUnknown() && !state.RecordName.IsNull() && !state.RecordName.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.RecordName.ValueString(), state.RecordName.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить record_name", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.RecordTTL.IsNull() && !plan.RecordTTL.IsUnknown() && !state.RecordTTL.IsNull() && !state.RecordTTL.IsUnknown() {
- if plan.RecordTTL.ValueInt64() != state.RecordTTL.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить record_t_t_l", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.RecordType.IsNull() && !plan.RecordType.IsUnknown() && !state.RecordType.IsNull() && !state.RecordType.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.RecordType.ValueString(), state.RecordType.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить record_type", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ZoneUid.IsNull() && !plan.ZoneUid.IsUnknown() && !state.ZoneUid.IsNull() && !state.ZoneUid.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ZoneUid.ValueString(), state.ZoneUid.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить zone_uid", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.RecordInput.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "record_input is required.")
- return
- }
- if config.RecordInput.IsUnknown() {
- return
- }
- if config.RecordName.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "record_name is required.")
- return
- }
- if config.RecordName.IsUnknown() {
- return
- }
- if config.RecordType.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "record_type is required.")
- return
- }
- if config.RecordType.IsUnknown() {
- return
- }
- if config.ZoneUid.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "zone_uid is required.")
- return
- }
- if config.ZoneUid.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- if !config.ZoneUid.IsNull() && !config.ZoneUid.IsUnknown() {
- resolvedZoneUid, err := r.client.ResolveRefSvcParamValue(ctx, 109, config.ZoneUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve zone_uid", err.Error())
- } else if resolvedZoneUid != "" && resolvedZoneUid != config.ZoneUid.ValueString() {
- config.ZoneUid = types.StringValue(resolvedZoneUid)
- }
- }
- params := map[int]string{
- 75: resources_core.FormatString(config.ZoneUid),
- 76: resources_core.FormatString(config.RecordType),
- 77: resources_core.FormatString(config.RecordName),
- 78: resources_core.FormatString(config.RecordInput),
- 450: resources_core.FormatInt64(config.RecordTTL),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 111, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *DnsrecordResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data DnsrecordModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.RecordInput.IsNull() || data.RecordInput.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "record_input is required.")
- return
- }
- if data.RecordName.IsNull() || data.RecordName.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "record_name is required.")
- return
- }
- if data.RecordType.IsNull() || data.RecordType.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "record_type is required.")
- return
- }
- if data.ZoneUid.IsNull() || data.ZoneUid.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "zone_uid is required.")
- return
- }
- // ══════════════════════════════════════════════════════════════════════════
- // ПРАВИЛО TERRAFORM (официальная документация):
- // «If an attribute value is configured, it is NEVER valid to change that
- // value in the plan.» — то есть plan ОБЯЗАН равняться config (= тому что
- // написал пользователь). Менять plan запрещено на уровне фреймворка.
- //
- // ПРОБЛЕМА: API нашего облака возвращает UUID в нижнем регистре.
- // Пользователь пишет: vapp_uid = "6214BA32-..." (верхний или смешанный).
- // После apply API вернул: "6214ba32-..." → state != plan → Terraform кричит:
- // «Provider produced inconsistent result after apply».
- //
- // РЕШЕНИЕ: корректировать STATE под PLAN, а не наоборот.
- // Шаг 1 (здесь): сохраняем оригинальное значение из plan ДО того как
- // ResolveRefSvcParamValue переведёт UUID в нижний регистр (нужен для API).
- // Шаг 2 (ниже, после RefreshResourceState): восстанавливаем оригинальный
- // регистр в state через strings.EqualFold (сравниваем без учёта регистра).
- // ══════════════════════════════════════════════════════════════════════════
- originalZoneUid := data.ZoneUid
- if !data.ZoneUid.IsNull() && !data.ZoneUid.IsUnknown() {
- resolvedZoneUid, err := r.client.ResolveRefSvcParamValue(ctx, 109, data.ZoneUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if resolvedZoneUid != "" && resolvedZoneUid != data.ZoneUid.ValueString() {
- data.ZoneUid = types.StringValue(resolvedZoneUid)
- }
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 111, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 75: resources_core.FormatString(data.ZoneUid),
- 76: resources_core.FormatString(data.RecordType),
- 77: resources_core.FormatString(data.RecordName),
- 78: resources_core.FormatString(data.RecordInput),
- 450: resources_core.FormatInt64(data.RecordTTL),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 111, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 111, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "recordInput", Field: "RecordInput", Type: "string"},
- {Code: "recordName", Field: "RecordName", Type: "string"},
- {Code: "recordTTL", Field: "RecordTTL", Type: "int64"},
- {Code: "recordType", Field: "RecordType", Type: "string"},
- {Code: "zoneUid", Field: "ZoneUid", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !state.ZoneUid.IsNull() && !state.ZoneUid.IsUnknown() {
- resolvedZoneUid, err := r.client.ResolveRefSvcParamValue(ctx, 109, state.ZoneUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve zone_uid", err.Error())
- } else if resolvedZoneUid != "" && resolvedZoneUid != state.ZoneUid.ValueString() {
- state.ZoneUid = types.StringValue(resolvedZoneUid)
- }
- }
- // Restore user-provided casing в state (Create).
- // EqualFold = «совпадают ли значения без учёта регистра?»
- // Если да — значит API вернул «туже» строку, только в другом регистре.
- // Заменяем state на original (то что было в plan/config пользователя).
- // Итог: plan=="6214BA32-..." и state=="6214BA32-..." → нет diff → нет taint.
- if !originalZoneUid.IsNull() && !originalZoneUid.IsUnknown() && !state.ZoneUid.IsNull() && !state.ZoneUid.IsUnknown() {
- if strings.EqualFold(state.ZoneUid.ValueString(), originalZoneUid.ValueString()) {
- state.ZoneUid = originalZoneUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *DnsrecordResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state DnsrecordModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 111, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "recordInput", Field: "RecordInput", Type: "string"},
- {Code: "recordName", Field: "RecordName", Type: "string"},
- {Code: "recordTTL", Field: "RecordTTL", Type: "int64"},
- {Code: "recordType", Field: "RecordType", Type: "string"},
- {Code: "zoneUid", Field: "ZoneUid", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !newState.ZoneUid.IsNull() && !newState.ZoneUid.IsUnknown() {
- resolvedZoneUid, err := r.client.ResolveRefSvcParamValue(ctx, 109, newState.ZoneUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve zone_uid", err.Error())
- } else if resolvedZoneUid != "" && resolvedZoneUid != newState.ZoneUid.ValueString() {
- newState.ZoneUid = types.StringValue(resolvedZoneUid)
- }
- }
- // Restore user-provided casing в state (Read).
- // При чтении у нас нет plan — но предыдущий state уже хранит значение
- // в регистре пользователя (после первого Create оно было восстановлено).
- // Берём prior state (переменная state) как эталон регистра.
- // Если API вернул то же UUID только строчными буквами — восстанавливаем.
- if !state.ZoneUid.IsNull() && !state.ZoneUid.IsUnknown() && !newState.ZoneUid.IsNull() && !newState.ZoneUid.IsUnknown() {
- if strings.EqualFold(newState.ZoneUid.ValueString(), state.ZoneUid.ValueString()) {
- newState.ZoneUid = state.ZoneUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *DnsrecordResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan DnsrecordModel
- var state DnsrecordModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.RecordInput.IsNull() != state.RecordInput.IsNull() || plan.RecordInput.IsUnknown() != state.RecordInput.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.RecordInput.IsNull() && !plan.RecordInput.IsUnknown() && !state.RecordInput.IsNull() && !state.RecordInput.IsUnknown() {
- if !strings.EqualFold(plan.RecordInput.ValueString(), state.RecordInput.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 256: resources_core.FormatString(plan.RecordInput),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 111, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "recordInput", Field: "RecordInput", Type: "string"},
- {Code: "recordName", Field: "RecordName", Type: "string"},
- {Code: "recordTTL", Field: "RecordTTL", Type: "int64"},
- {Code: "recordType", Field: "RecordType", Type: "string"},
- {Code: "zoneUid", Field: "ZoneUid", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !state.ZoneUid.IsNull() && !state.ZoneUid.IsUnknown() {
- resolvedZoneUid, err := r.client.ResolveRefSvcParamValue(ctx, 109, state.ZoneUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve zone_uid", err.Error())
- } else if resolvedZoneUid != "" && resolvedZoneUid != state.ZoneUid.ValueString() {
- state.ZoneUid = types.StringValue(resolvedZoneUid)
- }
- }
- // Restore user-provided casing в state (Update).
- // После API-вызова modify state содержит значения в lower-case от API.
- // Plan == config == то что написал пользователь (регистр неизменён).
- // EqualFold: если UUID совпадает без учёта регистра — берём из plan.
- if !plan.ZoneUid.IsNull() && !plan.ZoneUid.IsUnknown() && !state.ZoneUid.IsNull() && !state.ZoneUid.IsUnknown() {
- if strings.EqualFold(state.ZoneUid.ValueString(), plan.ZoneUid.ValueString()) {
- state.ZoneUid = plan.ZoneUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *DnsrecordResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state DnsrecordModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "delete"
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *DnsrecordResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *DnsrecordResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/112_tenant_resource.go b/provider/internal/resources_gen/112_tenant_resource.go
deleted file mode 100644
index 57ca92c..0000000
--- a/provider/internal/resources_gen/112_tenant_resource.go
+++ /dev/null
@@ -1,372 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: tenant
-// Service ID: 112
-
-var _ resource.Resource = &TenantResource{}
-var _ resource.ResourceWithModifyPlan = &TenantResource{}
-var _ resource.ResourceWithImportState = &TenantResource{}
-
-type TenantResource struct {
- client *core.UniversalClient
-}
-
-type TenantModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- GrafanaOrgName types.String `tfsdk:"grafana_org_name"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewTenantResource() resource.Resource {
- return &TenantResource{}
-}
-
-func (r *TenantResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_tenant"
-}
-
-func (r *TenantResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "grafana_org_name": schema.StringAttribute{Required: true, MarkdownDescription: "WZ-Код клиента Не изменяется после создания."},
- "resource_realm": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("grafana.ngcloud.ru"), MarkdownDescription: "Платформа для развертывания Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *TenantResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *TenantModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *TenantModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan TenantModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.GrafanaOrgName.IsNull() && !plan.GrafanaOrgName.IsUnknown() && !state.GrafanaOrgName.IsNull() && !state.GrafanaOrgName.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.GrafanaOrgName.ValueString(), state.GrafanaOrgName.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить grafana_org_name", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.GrafanaOrgName.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "grafana_org_name is required.")
- return
- }
- if config.GrafanaOrgName.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 239: resources_core.FormatString(config.GrafanaOrgName),
- 240: resources_core.FormatString(config.ResourceRealm),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 112, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *TenantResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data TenantModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.GrafanaOrgName.IsNull() || data.GrafanaOrgName.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "grafana_org_name is required.")
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 112, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 239: resources_core.FormatString(data.GrafanaOrgName),
- 240: resources_core.FormatString(data.ResourceRealm),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 112, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 112, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "grafanaOrgName", Field: "GrafanaOrgName", Type: "string"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *TenantResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state TenantModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 112, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "grafanaOrgName", Field: "GrafanaOrgName", Type: "string"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *TenantResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan TenantModel
- var state TenantModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{}
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 112, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "grafanaOrgName", Field: "GrafanaOrgName", Type: "string"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *TenantResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state TenantModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "delete"
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *TenantResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *TenantResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/113_vc_complex_resource.go b/provider/internal/resources_gen/113_vc_complex_resource.go
deleted file mode 100644
index f8eace6..0000000
--- a/provider/internal/resources_gen/113_vc_complex_resource.go
+++ /dev/null
@@ -1,563 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: vc_complex
-// Service ID: 113
-
-var _ resource.Resource = &VcComplexResource{}
-var _ resource.ResourceWithModifyPlan = &VcComplexResource{}
-var _ resource.ResourceWithImportState = &VcComplexResource{}
-
-type VcComplexResource struct {
- client *core.UniversalClient
-}
-
-type VcComplexModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- CpuAllocated types.String `tfsdk:"cpu_allocated"`
- CpuGuaranteed types.Int64 `tfsdk:"cpu_guaranteed"`
- IpSpaceName types.String `tfsdk:"ip_space_name"`
- MemAllocated types.Int64 `tfsdk:"mem_allocated"`
- MemGuaranteed types.Int64 `tfsdk:"mem_guaranteed"`
- NeedEnableAVI types.Bool `tfsdk:"need_enable_a_v_i"`
- NeedExternalAddressSNAT types.Bool `tfsdk:"need_external_address_s_n_a_t"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- SegroupName types.String `tfsdk:"segroup_name"`
- StorageConfig types.String `tfsdk:"storage_config"`
- VIPCount types.Int64 `tfsdk:"v_i_p_count"`
- VappName types.String `tfsdk:"vapp_name"`
- VdcNetworkPool types.String `tfsdk:"vdc_network_pool"`
- VdcProviderGateway types.String `tfsdk:"vdc_provider_gateway"`
- VirtualServicesCount types.String `tfsdk:"virtual_services_count"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewVcComplexResource() resource.Resource {
- return &VcComplexResource{}
-}
-
-func (r *VcComplexResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_vc_complex"
-}
-
-func (r *VcComplexResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "cpu_allocated": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("1"), MarkdownDescription: "шт Не изменяется после создания."},
- "cpu_guaranteed": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(20), MarkdownDescription: "Не изменяется после создания."},
- "ip_space_name": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("internet-ipv4-v1"), MarkdownDescription: "Имя ip Space для внешнего IP. Целесообразнее брать самый дешёвый, так как это vip для исходящего трафика. Необходимо задавать если включен needExternalAddressSNAT Не изменяется после создания."},
- "mem_allocated": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(10), MarkdownDescription: "gb Не изменяется после создания."},
- "mem_guaranteed": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(20), MarkdownDescription: "Не изменяется после создания."},
- "need_enable_a_v_i": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Включает AVI в Cloud Director Не изменяется после создания."},
- "need_external_address_s_n_a_t": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true), MarkdownDescription: "Выделяет внешний IP на Edge. Используется для SNAT всего трафика Не изменяется после создания."},
- "resource_realm": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("sandbox.nubes.ru"), MarkdownDescription: "Платформа для развертывания Не изменяется после создания."},
- "segroup_name": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("SEGROUP-SANDBOX-CL1-SHARED-01"), MarkdownDescription: "Наименование segroup, в котором будут выделяться пулы на AVI Не изменяется после создания."},
- "storage_config": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[{\"name\": \"\", \"size\": 1024}]"), MarkdownDescription: "Описывается как массив объектов, где описывается имя политики и её размер Не изменяется после создания.", PlanModifiers: []planmodifier.String{resources_core.JsonNormalize()}},
- "v_i_p_count": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(0), MarkdownDescription: "шт Не изменяется после создания."},
- "vapp_name": schema.StringAttribute{Required: true, MarkdownDescription: "Имя vApp Не изменяется после создания."},
- "vdc_network_pool": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("nsxt-sandbox-geneve-np"), MarkdownDescription: "Не изменяется после создания."},
- "vdc_provider_gateway": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("sandbox-v1cl1-pvdc"), MarkdownDescription: "Взять из свойств ресурсной платформы.
Путь .vcd.providerVdc - взять KEY
providerGateway Cloud Director. Влияет ресурсы будут предоставлены. Является полем (List<String>) в свойствах рес. платформы ЛК, но сам параметр передаётся только как один String Не изменяется после создания."},
- "virtual_services_count": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("1"), MarkdownDescription: "Кол-во виртуальных сервисов, которые выделяются на AVI. Во избежании коллапса пока выделяется до 4 Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *VcComplexResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *VcComplexModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *VcComplexModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan VcComplexModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.CpuAllocated.IsNull() && !plan.CpuAllocated.IsUnknown() && !state.CpuAllocated.IsNull() && !state.CpuAllocated.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.CpuAllocated.ValueString(), state.CpuAllocated.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить cpu_allocated", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.CpuGuaranteed.IsNull() && !plan.CpuGuaranteed.IsUnknown() && !state.CpuGuaranteed.IsNull() && !state.CpuGuaranteed.IsUnknown() {
- if plan.CpuGuaranteed.ValueInt64() != state.CpuGuaranteed.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить cpu_guaranteed", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.IpSpaceName.IsNull() && !plan.IpSpaceName.IsUnknown() && !state.IpSpaceName.IsNull() && !state.IpSpaceName.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.IpSpaceName.ValueString(), state.IpSpaceName.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить ip_space_name", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.MemAllocated.IsNull() && !plan.MemAllocated.IsUnknown() && !state.MemAllocated.IsNull() && !state.MemAllocated.IsUnknown() {
- if plan.MemAllocated.ValueInt64() != state.MemAllocated.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить mem_allocated", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.MemGuaranteed.IsNull() && !plan.MemGuaranteed.IsUnknown() && !state.MemGuaranteed.IsNull() && !state.MemGuaranteed.IsUnknown() {
- if plan.MemGuaranteed.ValueInt64() != state.MemGuaranteed.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить mem_guaranteed", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.NeedEnableAVI.IsNull() && !plan.NeedEnableAVI.IsUnknown() && !state.NeedEnableAVI.IsNull() && !state.NeedEnableAVI.IsUnknown() {
- if plan.NeedEnableAVI.ValueBool() != state.NeedEnableAVI.ValueBool() {
- resp.Diagnostics.AddError("Нельзя изменить need_enable_a_v_i", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.NeedExternalAddressSNAT.IsNull() && !plan.NeedExternalAddressSNAT.IsUnknown() && !state.NeedExternalAddressSNAT.IsNull() && !state.NeedExternalAddressSNAT.IsUnknown() {
- if plan.NeedExternalAddressSNAT.ValueBool() != state.NeedExternalAddressSNAT.ValueBool() {
- resp.Diagnostics.AddError("Нельзя изменить need_external_address_s_n_a_t", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.SegroupName.IsNull() && !plan.SegroupName.IsUnknown() && !state.SegroupName.IsNull() && !state.SegroupName.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.SegroupName.ValueString(), state.SegroupName.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить segroup_name", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.StorageConfig.IsNull() && !plan.StorageConfig.IsUnknown() && !state.StorageConfig.IsNull() && !state.StorageConfig.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.StorageConfig.ValueString(), state.StorageConfig.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить storage_config", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.VIPCount.IsNull() && !plan.VIPCount.IsUnknown() && !state.VIPCount.IsNull() && !state.VIPCount.IsUnknown() {
- if plan.VIPCount.ValueInt64() != state.VIPCount.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить v_i_p_count", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.VappName.IsNull() && !plan.VappName.IsUnknown() && !state.VappName.IsNull() && !state.VappName.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.VappName.ValueString(), state.VappName.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить vapp_name", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.VdcNetworkPool.IsNull() && !plan.VdcNetworkPool.IsUnknown() && !state.VdcNetworkPool.IsNull() && !state.VdcNetworkPool.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.VdcNetworkPool.ValueString(), state.VdcNetworkPool.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить vdc_network_pool", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.VdcProviderGateway.IsNull() && !plan.VdcProviderGateway.IsUnknown() && !state.VdcProviderGateway.IsNull() && !state.VdcProviderGateway.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.VdcProviderGateway.ValueString(), state.VdcProviderGateway.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить vdc_provider_gateway", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.VirtualServicesCount.IsNull() && !plan.VirtualServicesCount.IsUnknown() && !state.VirtualServicesCount.IsNull() && !state.VirtualServicesCount.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.VirtualServicesCount.ValueString(), state.VirtualServicesCount.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить virtual_services_count", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.VappName.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "vapp_name is required.")
- return
- }
- if config.VappName.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 332: resources_core.FormatString(config.ResourceRealm),
- 334: resources_core.FormatString(config.VappName),
- 358: resources_core.FormatString(config.VdcProviderGateway),
- 359: resources_core.FormatString(config.VirtualServicesCount),
- 360: resources_core.FormatString(config.IpSpaceName),
- 399: resources_core.FormatString(config.StorageConfig),
- 400: resources_core.FormatString(config.VdcNetworkPool),
- 401: resources_core.FormatInt64(config.CpuGuaranteed),
- 402: resources_core.FormatInt64(config.MemGuaranteed),
- 403: resources_core.FormatString(config.SegroupName),
- 404: resources_core.FormatBool(config.NeedExternalAddressSNAT),
- 405: resources_core.FormatBool(config.NeedEnableAVI),
- 566: resources_core.FormatString(config.CpuAllocated),
- 567: resources_core.FormatInt64(config.MemAllocated),
- 568: resources_core.FormatInt64(config.VIPCount),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 113, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *VcComplexResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data VcComplexModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.VappName.IsNull() || data.VappName.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "vapp_name is required.")
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 113, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 332: resources_core.FormatString(data.ResourceRealm),
- 334: resources_core.FormatString(data.VappName),
- 358: resources_core.FormatString(data.VdcProviderGateway),
- 359: resources_core.FormatString(data.VirtualServicesCount),
- 360: resources_core.FormatString(data.IpSpaceName),
- 399: resources_core.FormatString(data.StorageConfig),
- 400: resources_core.FormatString(data.VdcNetworkPool),
- 401: resources_core.FormatInt64(data.CpuGuaranteed),
- 402: resources_core.FormatInt64(data.MemGuaranteed),
- 403: resources_core.FormatString(data.SegroupName),
- 404: resources_core.FormatBool(data.NeedExternalAddressSNAT),
- 405: resources_core.FormatBool(data.NeedEnableAVI),
- 566: resources_core.FormatString(data.CpuAllocated),
- 567: resources_core.FormatInt64(data.MemAllocated),
- 568: resources_core.FormatInt64(data.VIPCount),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 113, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 113, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "cpuAllocated", Field: "CpuAllocated", Type: "string"},
- {Code: "cpuGuaranteed", Field: "CpuGuaranteed", Type: "int64"},
- {Code: "ipSpaceName", Field: "IpSpaceName", Type: "string"},
- {Code: "memAllocated", Field: "MemAllocated", Type: "int64"},
- {Code: "memGuaranteed", Field: "MemGuaranteed", Type: "int64"},
- {Code: "needEnableAVI", Field: "NeedEnableAVI", Type: "bool"},
- {Code: "needExternalAddressSNAT", Field: "NeedExternalAddressSNAT", Type: "bool"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "segroupName", Field: "SegroupName", Type: "string"},
- {Code: "storageConfig", Field: "StorageConfig", Type: "string"},
- {Code: "vIPCount", Field: "VIPCount", Type: "int64"},
- {Code: "vappName", Field: "VappName", Type: "string"},
- {Code: "vdcNetworkPool", Field: "VdcNetworkPool", Type: "string"},
- {Code: "vdcProviderGateway", Field: "VdcProviderGateway", Type: "string"},
- {Code: "virtualServicesCount", Field: "VirtualServicesCount", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcComplexResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state VcComplexModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 113, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "cpuAllocated", Field: "CpuAllocated", Type: "string"},
- {Code: "cpuGuaranteed", Field: "CpuGuaranteed", Type: "int64"},
- {Code: "ipSpaceName", Field: "IpSpaceName", Type: "string"},
- {Code: "memAllocated", Field: "MemAllocated", Type: "int64"},
- {Code: "memGuaranteed", Field: "MemGuaranteed", Type: "int64"},
- {Code: "needEnableAVI", Field: "NeedEnableAVI", Type: "bool"},
- {Code: "needExternalAddressSNAT", Field: "NeedExternalAddressSNAT", Type: "bool"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "segroupName", Field: "SegroupName", Type: "string"},
- {Code: "storageConfig", Field: "StorageConfig", Type: "string"},
- {Code: "vIPCount", Field: "VIPCount", Type: "int64"},
- {Code: "vappName", Field: "VappName", Type: "string"},
- {Code: "vdcNetworkPool", Field: "VdcNetworkPool", Type: "string"},
- {Code: "vdcProviderGateway", Field: "VdcProviderGateway", Type: "string"},
- {Code: "virtualServicesCount", Field: "VirtualServicesCount", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *VcComplexResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan VcComplexModel
- var state VcComplexModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{}
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 113, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "cpuAllocated", Field: "CpuAllocated", Type: "string"},
- {Code: "cpuGuaranteed", Field: "CpuGuaranteed", Type: "int64"},
- {Code: "ipSpaceName", Field: "IpSpaceName", Type: "string"},
- {Code: "memAllocated", Field: "MemAllocated", Type: "int64"},
- {Code: "memGuaranteed", Field: "MemGuaranteed", Type: "int64"},
- {Code: "needEnableAVI", Field: "NeedEnableAVI", Type: "bool"},
- {Code: "needExternalAddressSNAT", Field: "NeedExternalAddressSNAT", Type: "bool"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "segroupName", Field: "SegroupName", Type: "string"},
- {Code: "storageConfig", Field: "StorageConfig", Type: "string"},
- {Code: "vIPCount", Field: "VIPCount", Type: "int64"},
- {Code: "vappName", Field: "VappName", Type: "string"},
- {Code: "vdcNetworkPool", Field: "VdcNetworkPool", Type: "string"},
- {Code: "vdcProviderGateway", Field: "VdcProviderGateway", Type: "string"},
- {Code: "virtualServicesCount", Field: "VirtualServicesCount", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcComplexResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state VcComplexModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "delete"
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *VcComplexResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *VcComplexResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/115_mariadb_database_resource.go b/provider/internal/resources_gen/115_mariadb_database_resource.go
deleted file mode 100644
index cd6dd52..0000000
--- a/provider/internal/resources_gen/115_mariadb_database_resource.go
+++ /dev/null
@@ -1,343 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: mariadb
-// Subresource: database
-
-var _ resource.Resource = &MariadbDatabaseResource{}
-
-// MariadbDatabaseResource manages a subresource via operations.
-type MariadbDatabaseResource struct {
- client *core.UniversalClient
-}
-
-type MariadbDatabaseModel struct {
- ID types.String `tfsdk:"id"`
- MariadbID types.String `tfsdk:"mariadb_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- DbName types.String `tfsdk:"db_name"`
-}
-
-func NewMariadbDatabaseResource() resource.Resource {
- return &MariadbDatabaseResource{}
-}
-
-func (r *MariadbDatabaseResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_mariadb_database"
-}
-
-func (r *MariadbDatabaseResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "mariadb_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "db_name": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("db-dxinlvxx"), MarkdownDescription: "Пример: `db01` Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *MariadbDatabaseResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan MariadbDatabaseModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceUID := strings.TrimSpace(plan.MariadbID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{
- "dbName": resources_core.FormatString(plan.DbName),
- }
- identityCodes := []string{
- "dbName",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("database", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "database", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "dbName": resources_core.FormatString(plan.DbName),
- })
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_database", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_database", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "database", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "database", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "database", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *MariadbDatabaseResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state MariadbDatabaseModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *MariadbDatabaseResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan MariadbDatabaseModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "" == "" {
- var state MariadbDatabaseModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.MariadbID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- idParams := map[string]string{
- "dbName": resources_core.FormatString(plan.DbName),
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "database", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *MariadbDatabaseResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state MariadbDatabaseModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "delete_database" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.MariadbID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{
- "dbName": resources_core.FormatString(state.DbName),
- }
- identityCodes := []string{
- "dbName",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("database", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "dbName": resources_core.FormatString(state.DbName),
- })
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "delete_database", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *MariadbDatabaseResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/115_mariadb_resource.go b/provider/internal/resources_gen/115_mariadb_resource.go
deleted file mode 100644
index 6185299..0000000
--- a/provider/internal/resources_gen/115_mariadb_resource.go
+++ /dev/null
@@ -1,447 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "fmt"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: mariadb
-// Service ID: 115
-
-var _ resource.Resource = &MariadbResource{}
-var _ resource.ResourceWithModifyPlan = &MariadbResource{}
-var _ resource.ResourceWithImportState = &MariadbResource{}
-
-type MariadbResource struct {
- client *core.UniversalClient
-}
-
-// MariadbAccessConfigurationModel — вложенная модель для map-fixed параметра accessConfiguration.
-type MariadbAccessConfigurationModel struct {
- MasterIpSpace types.String `tfsdk:"master_ip_space" json:"masterIpSpace"`
- MasterAccessList types.String `tfsdk:"master_access_list" json:"masterAccessList"`
-}
-
-// MariadbAutoscaleConfigurationModel — вложенная модель для map-fixed параметра autoscaleConfiguration.
-type MariadbAutoscaleConfigurationModel struct {
- Enabled types.Bool `tfsdk:"enabled" json:"enabled"`
- Schedule types.Int64 `tfsdk:"schedule" json:"schedule"`
- Quota types.Int64 `tfsdk:"quota" json:"quota"`
- Percent types.Int64 `tfsdk:"percent" json:"percent"`
-}
-
-// MariadbBackupConfigurationModel — вложенная модель для map-fixed параметра backupConfiguration.
-type MariadbBackupConfigurationModel struct {
- S3Uid types.String `tfsdk:"s3_uid" json:"s3Uid"`
- Retain types.Int64 `tfsdk:"retain" json:"retain"`
- Schedule types.String `tfsdk:"schedule" json:"schedule"`
-}
-
-// MariadbClusterConfigurationModel — вложенная модель для map-fixed параметра clusterConfiguration.
-type MariadbClusterConfigurationModel struct {
- Memory types.Int64 `tfsdk:"memory" json:"memory"`
- Replicas types.Int64 `tfsdk:"replicas" json:"replicas"`
- Disk types.Int64 `tfsdk:"disk" json:"disk"`
- Cpu types.Int64 `tfsdk:"cpu" json:"cpu"`
-}
-
-// MariadbMariadbConfigurationModel — вложенная модель для map-fixed параметра mariadbConfiguration.
-type MariadbMariadbConfigurationModel struct {
- Version types.String `tfsdk:"version" json:"version"`
-}
-
-// MariadbStartupConfigurationModel — вложенная модель для map-fixed параметра startupConfiguration.
-type MariadbStartupConfigurationModel struct {
- ResourceRealm types.String `tfsdk:"resource_realm" json:"resourceRealm"`
-}
-
-type MariadbModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- AccessConfiguration *MariadbAccessConfigurationModel `tfsdk:"access_configuration"`
- AutoscaleConfiguration *MariadbAutoscaleConfigurationModel `tfsdk:"autoscale_configuration"`
- BackupConfiguration *MariadbBackupConfigurationModel `tfsdk:"backup_configuration"`
- ClusterConfiguration *MariadbClusterConfigurationModel `tfsdk:"cluster_configuration"`
- MariadbConfiguration *MariadbMariadbConfigurationModel `tfsdk:"mariadb_configuration"`
- StartupConfiguration *MariadbStartupConfigurationModel `tfsdk:"startup_configuration"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewMariadbResource() resource.Resource {
- return &MariadbResource{}
-}
-
-func (r *MariadbResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_mariadb"
-}
-
-func (r *MariadbResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "access_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "master_ip_space": schema.StringAttribute{Required: true, MarkdownDescription: "Из какого Ip-Space резервировать внешний IP
Список предоставляется из Организации, в котором развёрнута ресурсная платформа"},
- "master_access_list": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[]"), MarkdownDescription: "Необходимо настраивать, когда зарезервирован внешний адрес
Если передан пустой массив, доступ выделяется всем"},
- }},
- "autoscale_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "enabled": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Включает автоскейлинг PV. При включении параметра необходимо настроить autoScalePercentage и autoScaleTechWindow. Алерт при срабатывании вызывает modify у текущей услуги"},
- "schedule": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(0), MarkdownDescription: "Требует включения autoScale. Окно обновления (пока не реализовано). Указывается час в виде Integer (0 / 5 / 12 / 23)"},
- "quota": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(100), MarkdownDescription: "До какого размера возможно увеличивать диск, когда включен Autoscale"},
- "percent": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(10), MarkdownDescription: "Требует включения autoScale. Позволяет указать в процентах расширение от текущего макс объема
Минимальный размер на который расширяется - **1Gb**"},
- }},
- "backup_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "s3_uid": schema.StringAttribute{Required: true, MarkdownDescription: "Экземпляр S3 обязателен"},
- "retain": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(720)},
- "schedule": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("0 0 * * *")},
- }},
- "cluster_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(512), MarkdownDescription: "Указывается в Megabytes"},
- "replicas": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Пока `Galera` выключена
Как будет запрос на включение и тестирование, реплики можно будет увеличивать"},
- "disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(10), MarkdownDescription: "Указывается в GIGAbytes"},
- "cpu": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(500), MarkdownDescription: "Указывается в Milicores
`1000` Mili == `1` Ядро"},
- }},
- "mariadb_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "version": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("9.4.0")},
- }},
- "startup_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Кластер Kubernetes, на котором будет развернут экземпляр"},
- }},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *MariadbResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *MariadbModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *MariadbModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan MariadbModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 877: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", config.StartupConfiguration.ResourceRealm.ValueString())}),
- 878: resources_core.BuildJSON(map[string]string{"memory": fmt.Sprintf("%d", config.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", config.ClusterConfiguration.Replicas.ValueInt64()), "disk": fmt.Sprintf("%d", config.ClusterConfiguration.Disk.ValueInt64()), "cpu": fmt.Sprintf("%d", config.ClusterConfiguration.Cpu.ValueInt64())}),
- 879: resources_core.BuildJSON(map[string]string{"masterIpSpace": fmt.Sprintf("\"%s\"", config.AccessConfiguration.MasterIpSpace.ValueString()), "masterAccessList": config.AccessConfiguration.MasterAccessList.ValueString()}),
- 880: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", config.MariadbConfiguration.Version.ValueString())}),
- 881: resources_core.BuildJSON(map[string]string{"s3Uid": fmt.Sprintf("\"%s\"", config.BackupConfiguration.S3Uid.ValueString()), "retain": fmt.Sprintf("%d", config.BackupConfiguration.Retain.ValueInt64()), "schedule": fmt.Sprintf("\"%s\"", config.BackupConfiguration.Schedule.ValueString())}),
- 882: resources_core.BuildJSON(map[string]string{"enabled": fmt.Sprintf("%v", config.AutoscaleConfiguration.Enabled.ValueBool()), "schedule": fmt.Sprintf("%d", config.AutoscaleConfiguration.Schedule.ValueInt64()), "quota": fmt.Sprintf("%d", config.AutoscaleConfiguration.Quota.ValueInt64()), "percent": fmt.Sprintf("%d", config.AutoscaleConfiguration.Percent.ValueInt64())}),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 115, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *MariadbResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data MariadbModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 115, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 877: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", data.StartupConfiguration.ResourceRealm.ValueString())}),
- 878: resources_core.BuildJSON(map[string]string{"memory": fmt.Sprintf("%d", data.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", data.ClusterConfiguration.Replicas.ValueInt64()), "disk": fmt.Sprintf("%d", data.ClusterConfiguration.Disk.ValueInt64()), "cpu": fmt.Sprintf("%d", data.ClusterConfiguration.Cpu.ValueInt64())}),
- 879: resources_core.BuildJSON(map[string]string{"masterIpSpace": fmt.Sprintf("\"%s\"", data.AccessConfiguration.MasterIpSpace.ValueString()), "masterAccessList": data.AccessConfiguration.MasterAccessList.ValueString()}),
- 880: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", data.MariadbConfiguration.Version.ValueString())}),
- 881: resources_core.BuildJSON(map[string]string{"s3Uid": fmt.Sprintf("\"%s\"", data.BackupConfiguration.S3Uid.ValueString()), "retain": fmt.Sprintf("%d", data.BackupConfiguration.Retain.ValueInt64()), "schedule": fmt.Sprintf("\"%s\"", data.BackupConfiguration.Schedule.ValueString())}),
- 882: resources_core.BuildJSON(map[string]string{"enabled": fmt.Sprintf("%v", data.AutoscaleConfiguration.Enabled.ValueBool()), "schedule": fmt.Sprintf("%d", data.AutoscaleConfiguration.Schedule.ValueInt64()), "quota": fmt.Sprintf("%d", data.AutoscaleConfiguration.Quota.ValueInt64()), "percent": fmt.Sprintf("%d", data.AutoscaleConfiguration.Percent.ValueInt64())}),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 115, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 115, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "autoscaleConfiguration", Field: "AutoscaleConfiguration", Type: "map-fixed"},
- {Code: "backupConfiguration", Field: "BackupConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "mariadbConfiguration", Field: "MariadbConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *MariadbResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state MariadbModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 115, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "autoscaleConfiguration", Field: "AutoscaleConfiguration", Type: "map-fixed"},
- {Code: "backupConfiguration", Field: "BackupConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "mariadbConfiguration", Field: "MariadbConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *MariadbResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan MariadbModel
- var state MariadbModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 883: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", plan.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", plan.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", plan.ClusterConfiguration.Replicas.ValueInt64()), "disk": fmt.Sprintf("%d", plan.ClusterConfiguration.Disk.ValueInt64())}),
- 884: resources_core.BuildJSON(map[string]string{"masterIpSpace": fmt.Sprintf("\"%s\"", plan.AccessConfiguration.MasterIpSpace.ValueString()), "masterAccessList": plan.AccessConfiguration.MasterAccessList.ValueString()}),
- 885: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", plan.MariadbConfiguration.Version.ValueString())}),
- 886: resources_core.BuildJSON(map[string]string{"s3Uid": fmt.Sprintf("\"%s\"", plan.BackupConfiguration.S3Uid.ValueString()), "retain": fmt.Sprintf("%d", plan.BackupConfiguration.Retain.ValueInt64()), "schedule": fmt.Sprintf("\"%s\"", plan.BackupConfiguration.Schedule.ValueString())}),
- 887: resources_core.BuildJSON(map[string]string{"enabled": fmt.Sprintf("%v", plan.AutoscaleConfiguration.Enabled.ValueBool()), "schedule": fmt.Sprintf("%d", plan.AutoscaleConfiguration.Schedule.ValueInt64()), "quota": fmt.Sprintf("%d", plan.AutoscaleConfiguration.Quota.ValueInt64()), "percent": fmt.Sprintf("%d", plan.AutoscaleConfiguration.Percent.ValueInt64())}),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 115, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "autoscaleConfiguration", Field: "AutoscaleConfiguration", Type: "map-fixed"},
- {Code: "backupConfiguration", Field: "BackupConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "mariadbConfiguration", Field: "MariadbConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *MariadbResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state MariadbModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *MariadbResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *MariadbResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/115_mariadb_user_resource.go b/provider/internal/resources_gen/115_mariadb_user_resource.go
deleted file mode 100644
index 5a2f790..0000000
--- a/provider/internal/resources_gen/115_mariadb_user_resource.go
+++ /dev/null
@@ -1,367 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: mariadb
-// Subresource: user
-
-var _ resource.Resource = &MariadbUserResource{}
-
-// MariadbUserResource manages a subresource via operations.
-type MariadbUserResource struct {
- client *core.UniversalClient
-}
-
-type MariadbUserModel struct {
- ID types.String `tfsdk:"id"`
- MariadbID types.String `tfsdk:"mariadb_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- AccessHosts types.String `tfsdk:"access_hosts"`
- DbName types.String `tfsdk:"db_name"`
- Password types.String `tfsdk:"password"`
- Username types.String `tfsdk:"username"`
-}
-
-func NewMariadbUserResource() resource.Resource {
- return &MariadbUserResource{}
-}
-
-func (r *MariadbUserResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_mariadb_user"
-}
-
-func (r *MariadbUserResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "mariadb_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "access_hosts": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("%"), MarkdownDescription: "Пример: `%` Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- "db_name": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[{}]"), MarkdownDescription: "Необходимо указать массив существующих баз Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- "password": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("mhs3keq0"), MarkdownDescription: "Секрет будет записан в хранилище секретов и не будет отображаться публично Не изменяется после создания. Изменение требует пересоздания.", Sensitive: true, PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- "username": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("userz2hsgoyo"), MarkdownDescription: "Пример: `myusername` Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *MariadbUserResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan MariadbUserModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceUID := strings.TrimSpace(plan.MariadbID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{
- "accessHosts": resources_core.FormatString(plan.AccessHosts),
- "dbName": resources_core.FormatString(plan.DbName),
- "password": resources_core.FormatString(plan.Password),
- "username": resources_core.FormatString(plan.Username),
- }
- identityCodes := []string{
- "accessHosts",
- "dbName",
- "password",
- "username",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("user", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "username": resources_core.FormatString(plan.Username),
- "password": resources_core.FormatString(plan.Password),
- "dbName": resources_core.FormatString(plan.DbName),
- "accessHosts": resources_core.FormatString(plan.AccessHosts),
- })
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_user", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_user", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *MariadbUserResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state MariadbUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *MariadbUserResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan MariadbUserModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "" == "" {
- var state MariadbUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.MariadbID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- idParams := map[string]string{
- "accessHosts": resources_core.FormatString(plan.AccessHosts),
- "dbName": resources_core.FormatString(plan.DbName),
- "password": resources_core.FormatString(plan.Password),
- "username": resources_core.FormatString(plan.Username),
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *MariadbUserResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state MariadbUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "delete_user" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.MariadbID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{
- "accessHosts": resources_core.FormatString(state.AccessHosts),
- "dbName": resources_core.FormatString(state.DbName),
- "password": resources_core.FormatString(state.Password),
- "username": resources_core.FormatString(state.Username),
- }
- identityCodes := []string{
- "accessHosts",
- "dbName",
- "password",
- "username",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("user", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "username": resources_core.FormatString(state.Username),
- })
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "delete_user", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *MariadbUserResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/116_kafka_resource.go b/provider/internal/resources_gen/116_kafka_resource.go
deleted file mode 100644
index 108ee87..0000000
--- a/provider/internal/resources_gen/116_kafka_resource.go
+++ /dev/null
@@ -1,389 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "fmt"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: kafka
-// Service ID: 116
-
-var _ resource.Resource = &KafkaResource{}
-var _ resource.ResourceWithModifyPlan = &KafkaResource{}
-var _ resource.ResourceWithImportState = &KafkaResource{}
-
-type KafkaResource struct {
- client *core.UniversalClient
-}
-
-// KafkaAccessConfigurationModel — вложенная модель для map-fixed параметра accessConfiguration.
-type KafkaAccessConfigurationModel struct {
- AllocationExternal types.Bool `tfsdk:"allocation_external" json:"allocationExternal"`
- MasterAccessList types.String `tfsdk:"master_access_list" json:"masterAccessList"`
-}
-
-// KafkaClusterConfigurationModel — вложенная модель для map-fixed параметра clusterConfiguration.
-type KafkaClusterConfigurationModel struct {
- Cpu types.Int64 `tfsdk:"cpu" json:"cpu"`
- Memory types.Int64 `tfsdk:"memory" json:"memory"`
- Replicas types.Int64 `tfsdk:"replicas" json:"replicas"`
- Disk types.Int64 `tfsdk:"disk" json:"disk"`
-}
-
-// KafkaStartupConfigurationModel — вложенная модель для map-fixed параметра startupConfiguration.
-type KafkaStartupConfigurationModel struct {
- ResourceRealm types.String `tfsdk:"resource_realm" json:"resourceRealm"`
-}
-
-type KafkaModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- AccessConfiguration *KafkaAccessConfigurationModel `tfsdk:"access_configuration"`
- ClusterConfiguration *KafkaClusterConfigurationModel `tfsdk:"cluster_configuration"`
- StartupConfiguration *KafkaStartupConfigurationModel `tfsdk:"startup_configuration"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewKafkaResource() resource.Resource {
- return &KafkaResource{}
-}
-
-func (r *KafkaResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_kafka"
-}
-
-func (r *KafkaResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "access_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "allocation_external": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "master_access_list": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[]"), MarkdownDescription: "Необходимо настраивать, когда зарезервирован внешний адрес
Если передан пустой массив, доступ выделяется всем"},
- }},
- "cluster_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "cpu": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(2000), MarkdownDescription: "Указывается в Milicores
`1000` Mili == `1` Ядро"},
- "memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(2048)},
- "replicas": schema.Int64Attribute{Required: true},
- "disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1)},
- }},
- "startup_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Кластер Kubernetes, на котором будет развернут экземпляр"},
- }},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *KafkaResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *KafkaModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *KafkaModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan KafkaModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 1084: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", config.StartupConfiguration.ResourceRealm.ValueString())}),
- 1085: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", config.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", config.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", config.ClusterConfiguration.Replicas.ValueInt64()), "disk": fmt.Sprintf("%d", config.ClusterConfiguration.Disk.ValueInt64())}),
- 1086: resources_core.BuildJSON(map[string]string{"allocationExternal": fmt.Sprintf("%v", config.AccessConfiguration.AllocationExternal.ValueBool()), "masterAccessList": config.AccessConfiguration.MasterAccessList.ValueString()}),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 116, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *KafkaResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data KafkaModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 116, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 1084: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", data.StartupConfiguration.ResourceRealm.ValueString())}),
- 1085: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", data.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", data.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", data.ClusterConfiguration.Replicas.ValueInt64()), "disk": fmt.Sprintf("%d", data.ClusterConfiguration.Disk.ValueInt64())}),
- 1086: resources_core.BuildJSON(map[string]string{"allocationExternal": fmt.Sprintf("%v", data.AccessConfiguration.AllocationExternal.ValueBool()), "masterAccessList": data.AccessConfiguration.MasterAccessList.ValueString()}),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 116, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 116, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *KafkaResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state KafkaModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 116, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *KafkaResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan KafkaModel
- var state KafkaModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 1087: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", plan.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", plan.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", plan.ClusterConfiguration.Replicas.ValueInt64()), "disk": fmt.Sprintf("%d", plan.ClusterConfiguration.Disk.ValueInt64())}),
- 1088: resources_core.BuildJSON(map[string]string{"allocationExternal": fmt.Sprintf("%v", plan.AccessConfiguration.AllocationExternal.ValueBool()), "masterAccessList": plan.AccessConfiguration.MasterAccessList.ValueString()}),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 116, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *KafkaResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state KafkaModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *KafkaResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *KafkaResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/116_kafka_topic_resource.go b/provider/internal/resources_gen/116_kafka_topic_resource.go
deleted file mode 100644
index 3f289b3..0000000
--- a/provider/internal/resources_gen/116_kafka_topic_resource.go
+++ /dev/null
@@ -1,364 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: kafka
-// Subresource: topic
-
-var _ resource.Resource = &KafkaTopicResource{}
-
-// KafkaTopicResource manages a subresource via operations.
-type KafkaTopicResource struct {
- client *core.UniversalClient
-}
-
-type KafkaTopicModel struct {
- ID types.String `tfsdk:"id"`
- KafkaID types.String `tfsdk:"kafka_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- NameTopic types.String `tfsdk:"name_topic"`
- Partitions types.Int64 `tfsdk:"partitions"`
- Replicas types.Int64 `tfsdk:"replicas"`
-}
-
-func NewKafkaTopicResource() resource.Resource {
- return &KafkaTopicResource{}
-}
-
-func (r *KafkaTopicResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_kafka_topic"
-}
-
-func (r *KafkaTopicResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "kafka_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "name_topic": schema.StringAttribute{Required: true, MarkdownDescription: "Пример: `orders-events` Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- "partitions": schema.Int64Attribute{Required: true, MarkdownDescription: "Число партиций можно увеличить, но уменьшить их нельзя."},
- "replicas": schema.Int64Attribute{Required: true, MarkdownDescription: "Количество реплик не может привышать количество реплик брокера"},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *KafkaTopicResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan KafkaTopicModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.NameTopic.IsNull() || plan.NameTopic.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "name_topic is required.")
- return
- }
- if plan.Partitions.IsNull() || plan.Partitions.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "partitions is required.")
- return
- }
- if plan.Replicas.IsNull() || plan.Replicas.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "replicas is required.")
- return
- }
-
- instanceUID := strings.TrimSpace(plan.KafkaID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{
- "nameTopic": resources_core.FormatString(plan.NameTopic),
- }
- identityCodes := []string{
- "nameTopic",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("topic", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "topic", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "nameTopic": resources_core.FormatString(plan.NameTopic),
- "partitions": resources_core.FormatInt64(plan.Partitions),
- "replicas": resources_core.FormatInt64(plan.Replicas),
- })
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_topic", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_topic", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "topic", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "topic", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "topic", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *KafkaTopicResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state KafkaTopicModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *KafkaTopicResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan KafkaTopicModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "modify_topic" == "" {
- var state KafkaTopicModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.KafkaID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{
- "nameTopic": resources_core.FormatString(plan.NameTopic),
- "partitions": resources_core.FormatInt64(plan.Partitions),
- "replicas": resources_core.FormatInt64(plan.Replicas),
- })
-
- idParams := map[string]string{
- "nameTopic": resources_core.FormatString(plan.NameTopic),
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "modify_topic", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "topic", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *KafkaTopicResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state KafkaTopicModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "delete_topic" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.KafkaID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{
- "nameTopic": resources_core.FormatString(state.NameTopic),
- }
- identityCodes := []string{
- "nameTopic",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("topic", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "nameTopic": resources_core.FormatString(state.NameTopic),
- })
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "delete_topic", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *KafkaTopicResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/116_kafka_user_resource.go b/provider/internal/resources_gen/116_kafka_user_resource.go
deleted file mode 100644
index 52ea73c..0000000
--- a/provider/internal/resources_gen/116_kafka_user_resource.go
+++ /dev/null
@@ -1,373 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: kafka
-// Subresource: user
-
-var _ resource.Resource = &KafkaUserResource{}
-
-// KafkaUserResource manages a subresource via operations.
-type KafkaUserResource struct {
- client *core.UniversalClient
-}
-
-type KafkaUserModel struct {
- ID types.String `tfsdk:"id"`
- KafkaID types.String `tfsdk:"kafka_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- AccessHosts types.String `tfsdk:"access_hosts"`
- Group types.String `tfsdk:"group"`
- NameTopic types.String `tfsdk:"name_topic"`
- Operations types.String `tfsdk:"operations"`
- Username types.String `tfsdk:"username"`
-}
-
-func NewKafkaUserResource() resource.Resource {
- return &KafkaUserResource{}
-}
-
-func (r *KafkaUserResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_kafka_user"
-}
-
-func (r *KafkaUserResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "kafka_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "access_hosts": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("*"), MarkdownDescription: "Пример: `192.168.1.0/24` или `*`"},
- "group": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("*"), MarkdownDescription: "Пример: `order-consumers` или `*`"},
- "name_topic": schema.StringAttribute{Required: true, MarkdownDescription: "Пример: `orders-events`. Использовать маску нельзя(`orders*`), только полное название или `*`"},
- "operations": schema.StringAttribute{Required: true, MarkdownDescription: "Пример: `Create, Describe, Read, Write`"},
- "username": schema.StringAttribute{Required: true, MarkdownDescription: "Пример: `username-admin` Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *KafkaUserResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan KafkaUserModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.NameTopic.IsNull() || plan.NameTopic.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "name_topic is required.")
- return
- }
- if plan.Operations.IsNull() || plan.Operations.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "operations is required.")
- return
- }
- if plan.Username.IsNull() || plan.Username.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "username is required.")
- return
- }
-
- instanceUID := strings.TrimSpace(plan.KafkaID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{
- "username": resources_core.FormatString(plan.Username),
- }
- identityCodes := []string{
- "username",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("user", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "username": resources_core.FormatString(plan.Username),
- "nameTopic": resources_core.FormatString(plan.NameTopic),
- "operations": resources_core.FormatString(plan.Operations),
- "group": resources_core.FormatString(plan.Group),
- "accessHosts": resources_core.FormatString(plan.AccessHosts),
- })
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_user", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_user", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *KafkaUserResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state KafkaUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *KafkaUserResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan KafkaUserModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "modify_user" == "" {
- var state KafkaUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.KafkaID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{
- "nameTopic": resources_core.FormatString(plan.NameTopic),
- "operations": resources_core.FormatString(plan.Operations),
- "group": resources_core.FormatString(plan.Group),
- "accessHosts": resources_core.FormatString(plan.AccessHosts),
- "username": resources_core.FormatString(plan.Username),
- })
-
- idParams := map[string]string{
- "username": resources_core.FormatString(plan.Username),
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "modify_user", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *KafkaUserResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state KafkaUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "delete_user" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.KafkaID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{
- "username": resources_core.FormatString(state.Username),
- }
- identityCodes := []string{
- "username",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("user", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "username": resources_core.FormatString(state.Username),
- })
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "delete_user", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *KafkaUserResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/119_akhq_resource.go b/provider/internal/resources_gen/119_akhq_resource.go
deleted file mode 100644
index 101c30a..0000000
--- a/provider/internal/resources_gen/119_akhq_resource.go
+++ /dev/null
@@ -1,554 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: akhq
-// Service ID: 119
-
-var _ resource.Resource = &AkhqResource{}
-var _ resource.ResourceWithModifyPlan = &AkhqResource{}
-var _ resource.ResourceWithImportState = &AkhqResource{}
-
-type AkhqResource struct {
- client *core.UniversalClient
-}
-
-type AkhqModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- Domain types.String `tfsdk:"domain"`
- KafkaUid types.String `tfsdk:"kafka_uid"`
- ResourceCPU types.Int64 `tfsdk:"resource_c_p_u"`
- ResourceInstances types.Int64 `tfsdk:"resource_instances"`
- ResourceMemory types.Int64 `tfsdk:"resource_memory"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewAkhqResource() resource.Resource {
- return &AkhqResource{}
-}
-
-func (r *AkhqResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_akhq"
-}
-
-func (r *AkhqResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "domain": schema.StringAttribute{Required: true, MarkdownDescription: "Если будет указан FQDN, то происходят проверки DNS на валидность А-записи, или будет добавлено в зону resourceRealm Не изменяется после создания."},
- "kafka_uid": schema.StringAttribute{Optional: true, Computed: true, MarkdownDescription: "Выбрать кластер из списка"},
- "resource_c_p_u": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(500), MarkdownDescription: "Пример: `1000` Не изменяется после создания."},
- "resource_instances": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Не изменяется после создания."},
- "resource_memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(512), MarkdownDescription: "Пример: `1024` Не изменяется после создания."},
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Выбрать платформу из списка Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *AkhqResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *AkhqModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *AkhqModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan AkhqModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- // FIX(uuid-case): resolve ref_svc params НЕ делаем в ModifyPlan.
- // Terraform правило: plan ОБЯЗАН равняться config для user-provided атрибутов.
- // Resolve (displayName → UUID или uppercase → lowercase) нужен только для
- // API-вызова в Create/Update. Делать его здесь = менять plan = ошибка
- // "Provider produced invalid plan: planned value does not match config value".
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.Domain.IsNull() && !plan.Domain.IsUnknown() && !state.Domain.IsNull() && !state.Domain.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.Domain.ValueString(), state.Domain.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить domain", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceCPU.IsNull() && !plan.ResourceCPU.IsUnknown() && !state.ResourceCPU.IsNull() && !state.ResourceCPU.IsUnknown() {
- if plan.ResourceCPU.ValueInt64() != state.ResourceCPU.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить resource_c_p_u", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceInstances.IsNull() && !plan.ResourceInstances.IsUnknown() && !state.ResourceInstances.IsNull() && !state.ResourceInstances.IsUnknown() {
- if plan.ResourceInstances.ValueInt64() != state.ResourceInstances.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить resource_instances", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceMemory.IsNull() && !plan.ResourceMemory.IsUnknown() && !state.ResourceMemory.IsNull() && !state.ResourceMemory.IsUnknown() {
- if plan.ResourceMemory.ValueInt64() != state.ResourceMemory.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить resource_memory", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.Domain.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "domain is required.")
- return
- }
- if config.Domain.IsUnknown() {
- return
- }
- if config.KafkaUid.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "kafka_uid is required.")
- return
- }
- if config.KafkaUid.IsUnknown() {
- return
- }
- if config.ResourceRealm.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
- if config.ResourceRealm.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- if !config.KafkaUid.IsNull() && !config.KafkaUid.IsUnknown() {
- resolvedKafkaUid, err := r.client.ResolveRefSvcParamValue(ctx, 116, config.KafkaUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve kafka_uid", err.Error())
- } else if resolvedKafkaUid != "" && resolvedKafkaUid != config.KafkaUid.ValueString() {
- config.KafkaUid = types.StringValue(resolvedKafkaUid)
- }
- }
- params := map[int]string{
- 550: resources_core.FormatString(config.ResourceRealm),
- 551: resources_core.FormatInt64(config.ResourceMemory),
- 552: resources_core.FormatInt64(config.ResourceCPU),
- 553: resources_core.FormatString(config.Domain),
- 554: resources_core.FormatInt64(config.ResourceInstances),
- 555: resources_core.FormatString(config.KafkaUid),
- }
- desiredDomain := ""
- if !config.Domain.IsNull() && !config.Domain.IsUnknown() {
- desiredDomain = config.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 119, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *AkhqResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data AkhqModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.Domain.IsNull() || data.Domain.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "domain is required.")
- return
- }
- if data.KafkaUid.IsNull() || data.KafkaUid.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "kafka_uid is required.")
- return
- }
- if data.ResourceRealm.IsNull() || data.ResourceRealm.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
- // ══════════════════════════════════════════════════════════════════════════
- // ПРАВИЛО TERRAFORM (официальная документация):
- // «If an attribute value is configured, it is NEVER valid to change that
- // value in the plan.» — то есть plan ОБЯЗАН равняться config (= тому что
- // написал пользователь). Менять plan запрещено на уровне фреймворка.
- //
- // ПРОБЛЕМА: API нашего облака возвращает UUID в нижнем регистре.
- // Пользователь пишет: vapp_uid = "6214BA32-..." (верхний или смешанный).
- // После apply API вернул: "6214ba32-..." → state != plan → Terraform кричит:
- // «Provider produced inconsistent result after apply».
- //
- // РЕШЕНИЕ: корректировать STATE под PLAN, а не наоборот.
- // Шаг 1 (здесь): сохраняем оригинальное значение из plan ДО того как
- // ResolveRefSvcParamValue переведёт UUID в нижний регистр (нужен для API).
- // Шаг 2 (ниже, после RefreshResourceState): восстанавливаем оригинальный
- // регистр в state через strings.EqualFold (сравниваем без учёта регистра).
- // ══════════════════════════════════════════════════════════════════════════
- originalKafkaUid := data.KafkaUid
- if !data.KafkaUid.IsNull() && !data.KafkaUid.IsUnknown() {
- resolvedKafkaUid, err := r.client.ResolveRefSvcParamValue(ctx, 116, data.KafkaUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if resolvedKafkaUid != "" && resolvedKafkaUid != data.KafkaUid.ValueString() {
- data.KafkaUid = types.StringValue(resolvedKafkaUid)
- }
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- if !data.Domain.IsNull() && !data.Domain.IsUnknown() {
- desiredDomain = data.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 119, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 550: resources_core.FormatString(data.ResourceRealm),
- 551: resources_core.FormatInt64(data.ResourceMemory),
- 552: resources_core.FormatInt64(data.ResourceCPU),
- 553: resources_core.FormatString(data.Domain),
- 554: resources_core.FormatInt64(data.ResourceInstances),
- 555: resources_core.FormatString(data.KafkaUid),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 119, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 119, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "kafkaUid", Field: "KafkaUid", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !state.KafkaUid.IsNull() && !state.KafkaUid.IsUnknown() {
- resolvedKafkaUid, err := r.client.ResolveRefSvcParamValue(ctx, 116, state.KafkaUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve kafka_uid", err.Error())
- } else if resolvedKafkaUid != "" && resolvedKafkaUid != state.KafkaUid.ValueString() {
- state.KafkaUid = types.StringValue(resolvedKafkaUid)
- }
- }
- // Restore user-provided casing в state (Create).
- // EqualFold = «совпадают ли значения без учёта регистра?»
- // Если да — значит API вернул «туже» строку, только в другом регистре.
- // Заменяем state на original (то что было в plan/config пользователя).
- // Итог: plan=="6214BA32-..." и state=="6214BA32-..." → нет diff → нет taint.
- if !originalKafkaUid.IsNull() && !originalKafkaUid.IsUnknown() && !state.KafkaUid.IsNull() && !state.KafkaUid.IsUnknown() {
- if strings.EqualFold(state.KafkaUid.ValueString(), originalKafkaUid.ValueString()) {
- state.KafkaUid = originalKafkaUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *AkhqResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state AkhqModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 119, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "kafkaUid", Field: "KafkaUid", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !newState.KafkaUid.IsNull() && !newState.KafkaUid.IsUnknown() {
- resolvedKafkaUid, err := r.client.ResolveRefSvcParamValue(ctx, 116, newState.KafkaUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve kafka_uid", err.Error())
- } else if resolvedKafkaUid != "" && resolvedKafkaUid != newState.KafkaUid.ValueString() {
- newState.KafkaUid = types.StringValue(resolvedKafkaUid)
- }
- }
- // Restore user-provided casing в state (Read).
- // При чтении у нас нет plan — но предыдущий state уже хранит значение
- // в регистре пользователя (после первого Create оно было восстановлено).
- // Берём prior state (переменная state) как эталон регистра.
- // Если API вернул то же UUID только строчными буквами — восстанавливаем.
- if !state.KafkaUid.IsNull() && !state.KafkaUid.IsUnknown() && !newState.KafkaUid.IsNull() && !newState.KafkaUid.IsUnknown() {
- if strings.EqualFold(newState.KafkaUid.ValueString(), state.KafkaUid.ValueString()) {
- newState.KafkaUid = state.KafkaUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *AkhqResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan AkhqModel
- var state AkhqModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.KafkaUid.IsNull() != state.KafkaUid.IsNull() || plan.KafkaUid.IsUnknown() != state.KafkaUid.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.KafkaUid.IsNull() && !plan.KafkaUid.IsUnknown() && !state.KafkaUid.IsNull() && !state.KafkaUid.IsUnknown() {
- if !strings.EqualFold(plan.KafkaUid.ValueString(), state.KafkaUid.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 565: resources_core.FormatString(plan.KafkaUid),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 119, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "kafkaUid", Field: "KafkaUid", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !state.KafkaUid.IsNull() && !state.KafkaUid.IsUnknown() {
- resolvedKafkaUid, err := r.client.ResolveRefSvcParamValue(ctx, 116, state.KafkaUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve kafka_uid", err.Error())
- } else if resolvedKafkaUid != "" && resolvedKafkaUid != state.KafkaUid.ValueString() {
- state.KafkaUid = types.StringValue(resolvedKafkaUid)
- }
- }
- // Restore user-provided casing в state (Update).
- // После API-вызова modify state содержит значения в lower-case от API.
- // Plan == config == то что написал пользователь (регистр неизменён).
- // EqualFold: если UUID совпадает без учёта регистра — берём из plan.
- if !plan.KafkaUid.IsNull() && !plan.KafkaUid.IsUnknown() && !state.KafkaUid.IsNull() && !state.KafkaUid.IsUnknown() {
- if strings.EqualFold(state.KafkaUid.ValueString(), plan.KafkaUid.ValueString()) {
- state.KafkaUid = plan.KafkaUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *AkhqResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state AkhqModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *AkhqResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *AkhqResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/120_clickhouse_database_resource.go b/provider/internal/resources_gen/120_clickhouse_database_resource.go
deleted file mode 100644
index cc5c42e..0000000
--- a/provider/internal/resources_gen/120_clickhouse_database_resource.go
+++ /dev/null
@@ -1,343 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: clickhouse
-// Subresource: database
-
-var _ resource.Resource = &ClickhouseDatabaseResource{}
-
-// ClickhouseDatabaseResource manages a subresource via operations.
-type ClickhouseDatabaseResource struct {
- client *core.UniversalClient
-}
-
-type ClickhouseDatabaseModel struct {
- ID types.String `tfsdk:"id"`
- ClickhouseID types.String `tfsdk:"clickhouse_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- DbName types.String `tfsdk:"db_name"`
-}
-
-func NewClickhouseDatabaseResource() resource.Resource {
- return &ClickhouseDatabaseResource{}
-}
-
-func (r *ClickhouseDatabaseResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_clickhouse_database"
-}
-
-func (r *ClickhouseDatabaseResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "clickhouse_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "db_name": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("db01"), MarkdownDescription: "Пример: `db01` Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *ClickhouseDatabaseResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan ClickhouseDatabaseModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceUID := strings.TrimSpace(plan.ClickhouseID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{
- "dbName": resources_core.FormatString(plan.DbName),
- }
- identityCodes := []string{
- "dbName",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("database", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "database", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "dbName": resources_core.FormatString(plan.DbName),
- })
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_database", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_database", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "database", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "database", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "database", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *ClickhouseDatabaseResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state ClickhouseDatabaseModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *ClickhouseDatabaseResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan ClickhouseDatabaseModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "" == "" {
- var state ClickhouseDatabaseModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.ClickhouseID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- idParams := map[string]string{
- "dbName": resources_core.FormatString(plan.DbName),
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "database", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *ClickhouseDatabaseResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state ClickhouseDatabaseModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "delete_database" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.ClickhouseID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{
- "dbName": resources_core.FormatString(state.DbName),
- }
- identityCodes := []string{
- "dbName",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("database", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "dbName": resources_core.FormatString(state.DbName),
- })
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "delete_database", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *ClickhouseDatabaseResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/120_clickhouse_resource.go b/provider/internal/resources_gen/120_clickhouse_resource.go
deleted file mode 100644
index 27781cb..0000000
--- a/provider/internal/resources_gen/120_clickhouse_resource.go
+++ /dev/null
@@ -1,487 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "fmt"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: clickhouse
-// Service ID: 120
-
-var _ resource.Resource = &ClickhouseResource{}
-var _ resource.ResourceWithModifyPlan = &ClickhouseResource{}
-var _ resource.ResourceWithImportState = &ClickhouseResource{}
-
-type ClickhouseResource struct {
- client *core.UniversalClient
-}
-
-// ClickhouseAccessConfigurationModel — вложенная модель для map-fixed параметра accessConfiguration.
-type ClickhouseAccessConfigurationModel struct {
- MasterIpSpace types.String `tfsdk:"master_ip_space" json:"masterIpSpace"`
- MasterAccessList types.String `tfsdk:"master_access_list" json:"masterAccessList"`
-}
-
-// ClickhouseAutoscaleConfigurationModel — вложенная модель для map-fixed параметра autoscaleConfiguration.
-type ClickhouseAutoscaleConfigurationModel struct {
- Enabled types.Bool `tfsdk:"enabled" json:"enabled"`
- Schedule types.Int64 `tfsdk:"schedule" json:"schedule"`
- Quota types.Int64 `tfsdk:"quota" json:"quota"`
- Percent types.Int64 `tfsdk:"percent" json:"percent"`
-}
-
-// ClickhouseBackupConfigurationModel — вложенная модель для map-fixed параметра backupConfiguration.
-type ClickhouseBackupConfigurationModel struct {
- S3Uid types.String `tfsdk:"s3_uid" json:"s3Uid"`
- Retain types.Int64 `tfsdk:"retain" json:"retain"`
- Schedule types.String `tfsdk:"schedule" json:"schedule"`
-}
-
-// ClickhouseClickhouseConfigurationModel — вложенная модель для map-fixed параметра clickhouseConfiguration.
-type ClickhouseClickhouseConfigurationModel struct {
- Version types.String `tfsdk:"version" json:"version"`
-}
-
-// ClickhouseClickhouseKeeperConfigurationModel — вложенная модель для map-fixed параметра clickhouseKeeperConfiguration.
-type ClickhouseClickhouseKeeperConfigurationModel struct {
- Cpu types.Int64 `tfsdk:"cpu" json:"cpu"`
- Memory types.Int64 `tfsdk:"memory" json:"memory"`
- Replicas types.Int64 `tfsdk:"replicas" json:"replicas"`
-}
-
-// ClickhouseClusterConfigurationModel — вложенная модель для map-fixed параметра clusterConfiguration.
-type ClickhouseClusterConfigurationModel struct {
- Memory types.Int64 `tfsdk:"memory" json:"memory"`
- Replicas types.Int64 `tfsdk:"replicas" json:"replicas"`
- Shards types.Int64 `tfsdk:"shards" json:"shards"`
- Disk types.Int64 `tfsdk:"disk" json:"disk"`
- Cpu types.Int64 `tfsdk:"cpu" json:"cpu"`
-}
-
-// ClickhouseStartupConfigurationModel — вложенная модель для map-fixed параметра startupConfiguration.
-type ClickhouseStartupConfigurationModel struct {
- ResourceRealm types.String `tfsdk:"resource_realm" json:"resourceRealm"`
-}
-
-type ClickhouseModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- AccessConfiguration *ClickhouseAccessConfigurationModel `tfsdk:"access_configuration"`
- AutoscaleConfiguration *ClickhouseAutoscaleConfigurationModel `tfsdk:"autoscale_configuration"`
- BackupConfiguration *ClickhouseBackupConfigurationModel `tfsdk:"backup_configuration"`
- ClickhouseConfiguration *ClickhouseClickhouseConfigurationModel `tfsdk:"clickhouse_configuration"`
- ClickhouseFilesConfiguration types.String `tfsdk:"clickhouse_files_configuration"`
- ClickhouseKeeperConfiguration *ClickhouseClickhouseKeeperConfigurationModel `tfsdk:"clickhouse_keeper_configuration"`
- ClusterConfiguration *ClickhouseClusterConfigurationModel `tfsdk:"cluster_configuration"`
- StartupConfiguration *ClickhouseStartupConfigurationModel `tfsdk:"startup_configuration"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewClickhouseResource() resource.Resource {
- return &ClickhouseResource{}
-}
-
-func (r *ClickhouseResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_clickhouse"
-}
-
-func (r *ClickhouseResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "access_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "master_ip_space": schema.StringAttribute{Required: true, MarkdownDescription: "Из какого Ip-Space резервировать внешний IP
Список предоставляется из Организации, в котором развёрнута ресурсная платформа"},
- "master_access_list": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[]"), MarkdownDescription: "Необходимо настраивать, когда зарезервирован внешний адрес
Если передан пустой массив, доступ выделяется всем"},
- }},
- "autoscale_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "enabled": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Включает автоскейлинг PV. При включении параметра необходимо настроить autoScalePercentage и autoScaleTechWindow. Алерт при срабатывании вызывает modify у текущей услуги"},
- "schedule": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(0), MarkdownDescription: "Требует включения autoScale. Окно обновления (пока не реализовано). Указывается час в виде Integer (0 / 5 / 12 / 23)"},
- "quota": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(100), MarkdownDescription: "До какого размера возможно увеличивать диск, когда включен Autoscale"},
- "percent": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(10), MarkdownDescription: "Требует включения autoScale. Позволяет указать в процентах расширение от текущего макс объема
Минимальный размер на который расширяется - **1Gb**"},
- }},
- "backup_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "s3_uid": schema.StringAttribute{Required: true, MarkdownDescription: "Экземпляр S3 обязателен"},
- "retain": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(7)},
- "schedule": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("0 0 * * *")},
- }},
- "clickhouse_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "version": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("25.10")},
- }},
- "clickhouse_files_configuration": schema.StringAttribute{Optional: true, MarkdownDescription: "Формат:
- path: somethings3.xml
xmlConfig: '<clickhouse>......</clickhouse>'"},
- "clickhouse_keeper_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "cpu": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(500), MarkdownDescription: "Указывается в Milicores
`1000` Mili == `1` Ядро"},
- "memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(512), MarkdownDescription: "Указывается в Megabytes"},
- "replicas": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(0), MarkdownDescription: "Если указан 0, то инстансы ClickHouse Keeper развёрнуты не будут"},
- }},
- "cluster_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(2048), MarkdownDescription: "Указывается в Megabytes"},
- "replicas": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1)},
- "shards": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "**Шард** - это часть данных, разделенная на разные узлы (серверы) для горизонтального масштабирования и обработки больших объемов информации.
**Реплика** - это точная копия данных внутри одного шарда"},
- "disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(10), MarkdownDescription: "Указывается в GIGAbytes"},
- "cpu": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1000), MarkdownDescription: "Указывается в Milicores
`1000` Mili == `1` Ядро"},
- }},
- "startup_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Кластер Kubernetes, на котором будет развернут экземпляр"},
- }},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *ClickhouseResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *ClickhouseModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *ClickhouseModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan ClickhouseModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 837: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", config.StartupConfiguration.ResourceRealm.ValueString())}),
- 838: resources_core.BuildJSON(map[string]string{"memory": fmt.Sprintf("%d", config.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", config.ClusterConfiguration.Replicas.ValueInt64()), "shards": fmt.Sprintf("%d", config.ClusterConfiguration.Shards.ValueInt64()), "disk": fmt.Sprintf("%d", config.ClusterConfiguration.Disk.ValueInt64()), "cpu": fmt.Sprintf("%d", config.ClusterConfiguration.Cpu.ValueInt64())}),
- 839: resources_core.BuildJSON(map[string]string{"masterIpSpace": fmt.Sprintf("\"%s\"", config.AccessConfiguration.MasterIpSpace.ValueString()), "masterAccessList": config.AccessConfiguration.MasterAccessList.ValueString()}),
- 840: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", config.ClickhouseKeeperConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", config.ClickhouseKeeperConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", config.ClickhouseKeeperConfiguration.Replicas.ValueInt64())}),
- 841: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", config.ClickhouseConfiguration.Version.ValueString())}),
- 842: resources_core.BuildJSON(map[string]string{"s3Uid": fmt.Sprintf("\"%s\"", config.BackupConfiguration.S3Uid.ValueString()), "retain": fmt.Sprintf("%d", config.BackupConfiguration.Retain.ValueInt64()), "schedule": fmt.Sprintf("\"%s\"", config.BackupConfiguration.Schedule.ValueString())}),
- 843: resources_core.BuildJSON(map[string]string{"enabled": fmt.Sprintf("%v", config.AutoscaleConfiguration.Enabled.ValueBool()), "schedule": fmt.Sprintf("%d", config.AutoscaleConfiguration.Schedule.ValueInt64()), "quota": fmt.Sprintf("%d", config.AutoscaleConfiguration.Quota.ValueInt64()), "percent": fmt.Sprintf("%d", config.AutoscaleConfiguration.Percent.ValueInt64())}),
- 851: resources_core.FormatString(config.ClickhouseFilesConfiguration),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 120, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *ClickhouseResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data ClickhouseModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 120, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 837: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", data.StartupConfiguration.ResourceRealm.ValueString())}),
- 838: resources_core.BuildJSON(map[string]string{"memory": fmt.Sprintf("%d", data.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", data.ClusterConfiguration.Replicas.ValueInt64()), "shards": fmt.Sprintf("%d", data.ClusterConfiguration.Shards.ValueInt64()), "disk": fmt.Sprintf("%d", data.ClusterConfiguration.Disk.ValueInt64()), "cpu": fmt.Sprintf("%d", data.ClusterConfiguration.Cpu.ValueInt64())}),
- 839: resources_core.BuildJSON(map[string]string{"masterIpSpace": fmt.Sprintf("\"%s\"", data.AccessConfiguration.MasterIpSpace.ValueString()), "masterAccessList": data.AccessConfiguration.MasterAccessList.ValueString()}),
- 840: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", data.ClickhouseKeeperConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", data.ClickhouseKeeperConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", data.ClickhouseKeeperConfiguration.Replicas.ValueInt64())}),
- 841: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", data.ClickhouseConfiguration.Version.ValueString())}),
- 842: resources_core.BuildJSON(map[string]string{"s3Uid": fmt.Sprintf("\"%s\"", data.BackupConfiguration.S3Uid.ValueString()), "retain": fmt.Sprintf("%d", data.BackupConfiguration.Retain.ValueInt64()), "schedule": fmt.Sprintf("\"%s\"", data.BackupConfiguration.Schedule.ValueString())}),
- 843: resources_core.BuildJSON(map[string]string{"enabled": fmt.Sprintf("%v", data.AutoscaleConfiguration.Enabled.ValueBool()), "schedule": fmt.Sprintf("%d", data.AutoscaleConfiguration.Schedule.ValueInt64()), "quota": fmt.Sprintf("%d", data.AutoscaleConfiguration.Quota.ValueInt64()), "percent": fmt.Sprintf("%d", data.AutoscaleConfiguration.Percent.ValueInt64())}),
- 851: resources_core.FormatString(data.ClickhouseFilesConfiguration),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 120, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 120, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "autoscaleConfiguration", Field: "AutoscaleConfiguration", Type: "map-fixed"},
- {Code: "backupConfiguration", Field: "BackupConfiguration", Type: "map-fixed"},
- {Code: "clickhouseConfiguration", Field: "ClickhouseConfiguration", Type: "map-fixed"},
- {Code: "clickhouseFilesConfiguration", Field: "ClickhouseFilesConfiguration", Type: "array-map-fixed"},
- {Code: "clickhouseKeeperConfiguration", Field: "ClickhouseKeeperConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *ClickhouseResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state ClickhouseModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 120, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "autoscaleConfiguration", Field: "AutoscaleConfiguration", Type: "map-fixed"},
- {Code: "backupConfiguration", Field: "BackupConfiguration", Type: "map-fixed"},
- {Code: "clickhouseConfiguration", Field: "ClickhouseConfiguration", Type: "map-fixed"},
- {Code: "clickhouseFilesConfiguration", Field: "ClickhouseFilesConfiguration", Type: "array-map-fixed"},
- {Code: "clickhouseKeeperConfiguration", Field: "ClickhouseKeeperConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *ClickhouseResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan ClickhouseModel
- var state ClickhouseModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.ClickhouseFilesConfiguration.IsNull() != state.ClickhouseFilesConfiguration.IsNull() || plan.ClickhouseFilesConfiguration.IsUnknown() != state.ClickhouseFilesConfiguration.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ClickhouseFilesConfiguration.IsNull() && !plan.ClickhouseFilesConfiguration.IsUnknown() && !state.ClickhouseFilesConfiguration.IsNull() && !state.ClickhouseFilesConfiguration.IsUnknown() {
- if !strings.EqualFold(plan.ClickhouseFilesConfiguration.ValueString(), state.ClickhouseFilesConfiguration.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 844: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", plan.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", plan.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", plan.ClusterConfiguration.Replicas.ValueInt64()), "shards": fmt.Sprintf("%d", plan.ClusterConfiguration.Shards.ValueInt64()), "disk": fmt.Sprintf("%d", plan.ClusterConfiguration.Disk.ValueInt64())}),
- 845: resources_core.BuildJSON(map[string]string{"replicas": fmt.Sprintf("%d", plan.ClickhouseKeeperConfiguration.Replicas.ValueInt64()), "cpu": fmt.Sprintf("%d", plan.ClickhouseKeeperConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", plan.ClickhouseKeeperConfiguration.Memory.ValueInt64())}),
- 846: resources_core.BuildJSON(map[string]string{"masterIpSpace": fmt.Sprintf("\"%s\"", plan.AccessConfiguration.MasterIpSpace.ValueString()), "masterAccessList": plan.AccessConfiguration.MasterAccessList.ValueString()}),
- 847: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", plan.ClickhouseConfiguration.Version.ValueString())}),
- 848: resources_core.BuildJSON(map[string]string{"s3Uid": fmt.Sprintf("\"%s\"", plan.BackupConfiguration.S3Uid.ValueString()), "retain": fmt.Sprintf("%d", plan.BackupConfiguration.Retain.ValueInt64()), "schedule": fmt.Sprintf("\"%s\"", plan.BackupConfiguration.Schedule.ValueString())}),
- 849: resources_core.BuildJSON(map[string]string{"enabled": fmt.Sprintf("%v", plan.AutoscaleConfiguration.Enabled.ValueBool()), "schedule": fmt.Sprintf("%d", plan.AutoscaleConfiguration.Schedule.ValueInt64()), "quota": fmt.Sprintf("%d", plan.AutoscaleConfiguration.Quota.ValueInt64()), "percent": fmt.Sprintf("%d", plan.AutoscaleConfiguration.Percent.ValueInt64())}),
- 850: resources_core.FormatString(plan.ClickhouseFilesConfiguration),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 120, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "autoscaleConfiguration", Field: "AutoscaleConfiguration", Type: "map-fixed"},
- {Code: "backupConfiguration", Field: "BackupConfiguration", Type: "map-fixed"},
- {Code: "clickhouseConfiguration", Field: "ClickhouseConfiguration", Type: "map-fixed"},
- {Code: "clickhouseFilesConfiguration", Field: "ClickhouseFilesConfiguration", Type: "array-map-fixed"},
- {Code: "clickhouseKeeperConfiguration", Field: "ClickhouseKeeperConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *ClickhouseResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state ClickhouseModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *ClickhouseResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *ClickhouseResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/120_clickhouse_user_resource.go b/provider/internal/resources_gen/120_clickhouse_user_resource.go
deleted file mode 100644
index 8dc28f7..0000000
--- a/provider/internal/resources_gen/120_clickhouse_user_resource.go
+++ /dev/null
@@ -1,359 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: clickhouse
-// Subresource: user
-
-var _ resource.Resource = &ClickhouseUserResource{}
-
-// ClickhouseUserResource manages a subresource via operations.
-type ClickhouseUserResource struct {
- client *core.UniversalClient
-}
-
-type ClickhouseUserModel struct {
- ID types.String `tfsdk:"id"`
- ClickhouseID types.String `tfsdk:"clickhouse_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- AccessHosts types.String `tfsdk:"access_hosts"`
- DbName types.String `tfsdk:"db_name"`
- Username types.String `tfsdk:"username"`
-}
-
-func NewClickhouseUserResource() resource.Resource {
- return &ClickhouseUserResource{}
-}
-
-func (r *ClickhouseUserResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_clickhouse_user"
-}
-
-func (r *ClickhouseUserResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "clickhouse_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "access_hosts": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("::/0"), MarkdownDescription: "Пример: `::/0` Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- "db_name": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[{}]"), MarkdownDescription: "Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- "username": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("myusername"), MarkdownDescription: "Пример: `myusername` Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *ClickhouseUserResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan ClickhouseUserModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceUID := strings.TrimSpace(plan.ClickhouseID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{
- "accessHosts": resources_core.FormatString(plan.AccessHosts),
- "dbName": resources_core.FormatString(plan.DbName),
- "username": resources_core.FormatString(plan.Username),
- }
- identityCodes := []string{
- "accessHosts",
- "dbName",
- "username",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("user", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "username": resources_core.FormatString(plan.Username),
- "dbName": resources_core.FormatString(plan.DbName),
- "accessHosts": resources_core.FormatString(plan.AccessHosts),
- })
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_user", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_user", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *ClickhouseUserResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state ClickhouseUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *ClickhouseUserResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan ClickhouseUserModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "" == "" {
- var state ClickhouseUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.ClickhouseID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- idParams := map[string]string{
- "accessHosts": resources_core.FormatString(plan.AccessHosts),
- "dbName": resources_core.FormatString(plan.DbName),
- "username": resources_core.FormatString(plan.Username),
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *ClickhouseUserResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state ClickhouseUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "delete_user" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.ClickhouseID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{
- "accessHosts": resources_core.FormatString(state.AccessHosts),
- "dbName": resources_core.FormatString(state.DbName),
- "username": resources_core.FormatString(state.Username),
- }
- identityCodes := []string{
- "accessHosts",
- "dbName",
- "username",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("user", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "username": resources_core.FormatString(state.Username),
- })
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "delete_user", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *ClickhouseUserResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/12_s3_resource.go b/provider/internal/resources_gen/12_s3_resource.go
deleted file mode 100644
index f4db5ce..0000000
--- a/provider/internal/resources_gen/12_s3_resource.go
+++ /dev/null
@@ -1,421 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: s3
-// Service ID: 12
-
-var _ resource.Resource = &S3Resource{}
-var _ resource.ResourceWithModifyPlan = &S3Resource{}
-var _ resource.ResourceWithImportState = &S3Resource{}
-
-type S3Resource struct {
- client *core.UniversalClient
-}
-
-type S3Model struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- DisplayName types.String `tfsdk:"display_name"`
- MaxBucketsPerUser types.Int64 `tfsdk:"max_buckets_per_user"`
- MaxObjectsPerBucket types.Int64 `tfsdk:"max_objects_per_bucket"`
- MaxSizeGbPerUser types.Int64 `tfsdk:"max_size_gb_per_user"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewS3Resource() resource.Resource {
- return &S3Resource{}
-}
-
-func (r *S3Resource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_s3"
-}
-
-func (r *S3Resource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "display_name": schema.StringAttribute{Required: true, MarkdownDescription: "Человеко-читаемое имя (транслит из Elma) - передаётся имя клиента Не изменяется после создания."},
- "max_buckets_per_user": schema.Int64Attribute{Optional: true, MarkdownDescription: "Квота на пользователя. Количество бакетов пользователя. Передаём руками"},
- "max_objects_per_bucket": schema.Int64Attribute{Optional: true, MarkdownDescription: "Квота на бакет. Кол-во объектов. Передаём руками"},
- "max_size_gb_per_user": schema.Int64Attribute{Optional: true, MarkdownDescription: "maxSizeGb. Передаём руками"},
- "resource_realm": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("ceph.tst.nubes.ru"), MarkdownDescription: "Платформа для развертывания Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *S3Resource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *S3Model
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *S3Model
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan S3Model
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.DisplayName.IsNull() && !plan.DisplayName.IsUnknown() && !state.DisplayName.IsNull() && !state.DisplayName.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.DisplayName.ValueString(), state.DisplayName.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить display_name", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.DisplayName.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "display_name is required.")
- return
- }
- if config.DisplayName.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 163: resources_core.FormatString(config.ResourceRealm),
- 320: resources_core.FormatString(config.DisplayName),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 12, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *S3Resource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data S3Model
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.DisplayName.IsNull() || data.DisplayName.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "display_name is required.")
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 12, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 163: resources_core.FormatString(data.ResourceRealm),
- 320: resources_core.FormatString(data.DisplayName),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 12, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 12, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "displayName", Field: "DisplayName", Type: "string"},
- {Code: "maxBucketsPerUser", Field: "MaxBucketsPerUser", Type: "int64"},
- {Code: "maxObjectsPerBucket", Field: "MaxObjectsPerBucket", Type: "int64"},
- {Code: "maxSizeGbPerUser", Field: "MaxSizeGbPerUser", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *S3Resource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state S3Model
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 12, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "displayName", Field: "DisplayName", Type: "string"},
- {Code: "maxBucketsPerUser", Field: "MaxBucketsPerUser", Type: "int64"},
- {Code: "maxObjectsPerBucket", Field: "MaxObjectsPerBucket", Type: "int64"},
- {Code: "maxSizeGbPerUser", Field: "MaxSizeGbPerUser", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *S3Resource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan S3Model
- var state S3Model
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.MaxSizeGbPerUser.IsNull() != state.MaxSizeGbPerUser.IsNull() || plan.MaxSizeGbPerUser.IsUnknown() != state.MaxSizeGbPerUser.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.MaxSizeGbPerUser.IsNull() && !plan.MaxSizeGbPerUser.IsUnknown() && !state.MaxSizeGbPerUser.IsNull() && !state.MaxSizeGbPerUser.IsUnknown() {
- if plan.MaxSizeGbPerUser.ValueInt64() != state.MaxSizeGbPerUser.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.MaxObjectsPerBucket.IsNull() != state.MaxObjectsPerBucket.IsNull() || plan.MaxObjectsPerBucket.IsUnknown() != state.MaxObjectsPerBucket.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.MaxObjectsPerBucket.IsNull() && !plan.MaxObjectsPerBucket.IsUnknown() && !state.MaxObjectsPerBucket.IsNull() && !state.MaxObjectsPerBucket.IsUnknown() {
- if plan.MaxObjectsPerBucket.ValueInt64() != state.MaxObjectsPerBucket.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.MaxBucketsPerUser.IsNull() != state.MaxBucketsPerUser.IsNull() || plan.MaxBucketsPerUser.IsUnknown() != state.MaxBucketsPerUser.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.MaxBucketsPerUser.IsNull() && !plan.MaxBucketsPerUser.IsUnknown() && !state.MaxBucketsPerUser.IsNull() && !state.MaxBucketsPerUser.IsUnknown() {
- if plan.MaxBucketsPerUser.ValueInt64() != state.MaxBucketsPerUser.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 50: resources_core.FormatInt64(plan.MaxSizeGbPerUser),
- 51: resources_core.FormatInt64(plan.MaxObjectsPerBucket),
- 52: resources_core.FormatInt64(plan.MaxBucketsPerUser),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 12, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "displayName", Field: "DisplayName", Type: "string"},
- {Code: "maxBucketsPerUser", Field: "MaxBucketsPerUser", Type: "int64"},
- {Code: "maxObjectsPerBucket", Field: "MaxObjectsPerBucket", Type: "int64"},
- {Code: "maxSizeGbPerUser", Field: "MaxSizeGbPerUser", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *S3Resource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state S3Model
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *S3Resource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *S3Resource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/12_s3_sub_user_resource.go b/provider/internal/resources_gen/12_s3_sub_user_resource.go
deleted file mode 100644
index b8e0168..0000000
--- a/provider/internal/resources_gen/12_s3_sub_user_resource.go
+++ /dev/null
@@ -1,358 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: s3
-// Subresource: sub_user
-
-var _ resource.Resource = &S3SubUserResource{}
-
-// S3SubUserResource manages a subresource via operations.
-type S3SubUserResource struct {
- client *core.UniversalClient
-}
-
-type S3SubUserModel struct {
- ID types.String `tfsdk:"id"`
- S3ID types.String `tfsdk:"s3_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- SubUserAccess types.String `tfsdk:"sub_user_access"`
- SubUserName types.String `tfsdk:"sub_user_name"`
-}
-
-func NewS3SubUserResource() resource.Resource {
- return &S3SubUserResource{}
-}
-
-func (r *S3SubUserResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_s3_sub_user"
-}
-
-func (r *S3SubUserResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "s3_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "sub_user_access": schema.StringAttribute{Required: true, MarkdownDescription: "Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- "sub_user_name": schema.StringAttribute{Required: true, MarkdownDescription: "Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *S3SubUserResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan S3SubUserModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.SubUserAccess.IsNull() || plan.SubUserAccess.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "sub_user_access is required.")
- return
- }
- if plan.SubUserName.IsNull() || plan.SubUserName.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "sub_user_name is required.")
- return
- }
-
- instanceUID := strings.TrimSpace(plan.S3ID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{
- "subUserAccess": resources_core.FormatString(plan.SubUserAccess),
- "subUserName": resources_core.FormatString(plan.SubUserName),
- }
- identityCodes := []string{
- "subUserAccess",
- "subUserName",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("sub_user", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "sub_user", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "subUserName": resources_core.FormatString(plan.SubUserName),
- "subUserAccess": resources_core.FormatString(plan.SubUserAccess),
- })
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_sub_user", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_sub_user", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "sub_user", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "sub_user", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "sub_user", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *S3SubUserResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state S3SubUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *S3SubUserResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan S3SubUserModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "" == "" {
- var state S3SubUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.S3ID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- idParams := map[string]string{
- "subUserAccess": resources_core.FormatString(plan.SubUserAccess),
- "subUserName": resources_core.FormatString(plan.SubUserName),
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "sub_user", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *S3SubUserResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state S3SubUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "delete_sub_user" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.S3ID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{
- "subUserAccess": resources_core.FormatString(state.SubUserAccess),
- "subUserName": resources_core.FormatString(state.SubUserName),
- }
- identityCodes := []string{
- "subUserAccess",
- "subUserName",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("sub_user", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "subUserName": resources_core.FormatString(state.SubUserName),
- })
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "delete_sub_user", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *S3SubUserResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/13_s3bucket_resource.go b/provider/internal/resources_gen/13_s3bucket_resource.go
deleted file mode 100644
index deb2272..0000000
--- a/provider/internal/resources_gen/13_s3bucket_resource.go
+++ /dev/null
@@ -1,478 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: s3bucket
-// Service ID: 13
-
-var _ resource.Resource = &S3bucketResource{}
-var _ resource.ResourceWithModifyPlan = &S3bucketResource{}
-var _ resource.ResourceWithImportState = &S3bucketResource{}
-
-type S3bucketResource struct {
- client *core.UniversalClient
-}
-
-type S3bucketModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- BucketName types.String `tfsdk:"bucket_name"`
- CorsAll types.Bool `tfsdk:"cors_all"`
- ListAll types.Bool `tfsdk:"list_all"`
- MaxSize types.String `tfsdk:"max_size"`
- Placement types.String `tfsdk:"placement"`
- ReadAll types.Bool `tfsdk:"read_all"`
- S3UserUid types.String `tfsdk:"s3_user_uid"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewS3bucketResource() resource.Resource {
- return &S3bucketResource{}
-}
-
-func (r *S3bucketResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_s3bucket"
-}
-
-func (r *S3bucketResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "bucket_name": schema.StringAttribute{Required: true, MarkdownDescription: "Имя бакета s3 Не изменяется после создания."},
- "cors_all": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Публичный доступ к чтению настроек позволяет любому пользователю интернета читать конфигурации CORS Не изменяется после создания."},
- "list_all": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Публичный доступ к листингу позволяет любому пользователю интернета получить список объектов в бакете. Не изменяется после создания."},
- "max_size": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("-1"), MarkdownDescription: "Максимальный размер бакета s3. Если поставить -1, будет безлимит. Размер указывается в Bytes Не изменяется после создания."},
- "placement": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("HOT"), MarkdownDescription: "Класс хранилища, который используется по умолчанию при загрузке объектов. Чем холоднее, тем дешевле место, но дороже обращения Не изменяется после создания."},
- "read_all": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Публичный доступ на чтение позволяет любому пользователю интернета скачивать объекты из бакета. Не изменяется после создания."},
- "s3_user_uid": schema.StringAttribute{Optional: true, Computed: true, MarkdownDescription: "UID Корневой услуги S3. На основе него будет создан бакет. Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *S3bucketResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *S3bucketModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *S3bucketModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan S3bucketModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- // FIX(uuid-case): resolve ref_svc params НЕ делаем в ModifyPlan.
- // Terraform правило: plan ОБЯЗАН равняться config для user-provided атрибутов.
- // Resolve (displayName → UUID или uppercase → lowercase) нужен только для
- // API-вызова в Create/Update. Делать его здесь = менять plan = ошибка
- // "Provider produced invalid plan: planned value does not match config value".
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.BucketName.IsNull() && !plan.BucketName.IsUnknown() && !state.BucketName.IsNull() && !state.BucketName.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.BucketName.ValueString(), state.BucketName.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить bucket_name", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.CorsAll.IsNull() && !plan.CorsAll.IsUnknown() && !state.CorsAll.IsNull() && !state.CorsAll.IsUnknown() {
- if plan.CorsAll.ValueBool() != state.CorsAll.ValueBool() {
- resp.Diagnostics.AddError("Нельзя изменить cors_all", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ListAll.IsNull() && !plan.ListAll.IsUnknown() && !state.ListAll.IsNull() && !state.ListAll.IsUnknown() {
- if plan.ListAll.ValueBool() != state.ListAll.ValueBool() {
- resp.Diagnostics.AddError("Нельзя изменить list_all", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.MaxSize.IsNull() && !plan.MaxSize.IsUnknown() && !state.MaxSize.IsNull() && !state.MaxSize.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.MaxSize.ValueString(), state.MaxSize.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить max_size", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.Placement.IsNull() && !plan.Placement.IsUnknown() && !state.Placement.IsNull() && !state.Placement.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.Placement.ValueString(), state.Placement.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить placement", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ReadAll.IsNull() && !plan.ReadAll.IsUnknown() && !state.ReadAll.IsNull() && !state.ReadAll.IsUnknown() {
- if plan.ReadAll.ValueBool() != state.ReadAll.ValueBool() {
- resp.Diagnostics.AddError("Нельзя изменить read_all", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.S3UserUid.IsNull() && !plan.S3UserUid.IsUnknown() && !state.S3UserUid.IsNull() && !state.S3UserUid.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.S3UserUid.ValueString(), state.S3UserUid.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить s3_user_uid", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.BucketName.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "bucket_name is required.")
- return
- }
- if config.BucketName.IsUnknown() {
- return
- }
- if config.S3UserUid.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "s3_user_uid is required.")
- return
- }
- if config.S3UserUid.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- if !config.S3UserUid.IsNull() && !config.S3UserUid.IsUnknown() {
- resolvedS3UserUid, err := r.client.ResolveRefSvcParamValue(ctx, 12, config.S3UserUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve s3_user_uid", err.Error())
- } else if resolvedS3UserUid != "" && resolvedS3UserUid != config.S3UserUid.ValueString() {
- config.S3UserUid = types.StringValue(resolvedS3UserUid)
- }
- }
- params := map[int]string{
- 124: resources_core.FormatString(config.S3UserUid),
- 125: resources_core.FormatString(config.BucketName),
- 126: resources_core.FormatString(config.MaxSize),
- 127: resources_core.FormatBool(config.ReadAll),
- 128: resources_core.FormatBool(config.ListAll),
- 129: resources_core.FormatBool(config.CorsAll),
- 130: resources_core.FormatString(config.Placement),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 13, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *S3bucketResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data S3bucketModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.BucketName.IsNull() || data.BucketName.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "bucket_name is required.")
- return
- }
- if data.S3UserUid.IsNull() || data.S3UserUid.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "s3_user_uid is required.")
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 13, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 124: resources_core.FormatString(data.S3UserUid),
- 125: resources_core.FormatString(data.BucketName),
- 126: resources_core.FormatString(data.MaxSize),
- 127: resources_core.FormatBool(data.ReadAll),
- 128: resources_core.FormatBool(data.ListAll),
- 129: resources_core.FormatBool(data.CorsAll),
- 130: resources_core.FormatString(data.Placement),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 13, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 13, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "bucketName", Field: "BucketName", Type: "string"},
- {Code: "corsAll", Field: "CorsAll", Type: "bool"},
- {Code: "listAll", Field: "ListAll", Type: "bool"},
- {Code: "maxSize", Field: "MaxSize", Type: "string"},
- {Code: "placement", Field: "Placement", Type: "string"},
- {Code: "readAll", Field: "ReadAll", Type: "bool"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- // Restore user-provided casing в state (Create).
- // EqualFold = «совпадают ли значения без учёта регистра?»
- // Если да — значит API вернул «туже» строку, только в другом регистре.
- // Заменяем state на original (то что было в plan/config пользователя).
- // Итог: plan=="6214BA32-..." и state=="6214BA32-..." → нет diff → нет taint.
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *S3bucketResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state S3bucketModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 13, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "bucketName", Field: "BucketName", Type: "string"},
- {Code: "corsAll", Field: "CorsAll", Type: "bool"},
- {Code: "listAll", Field: "ListAll", Type: "bool"},
- {Code: "maxSize", Field: "MaxSize", Type: "string"},
- {Code: "placement", Field: "Placement", Type: "string"},
- {Code: "readAll", Field: "ReadAll", Type: "bool"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- // Restore user-provided casing в state (Read).
- // При чтении у нас нет plan — но предыдущий state уже хранит значение
- // в регистре пользователя (после первого Create оно было восстановлено).
- // Берём prior state (переменная state) как эталон регистра.
- // Если API вернул то же UUID только строчными буквами — восстанавливаем.
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *S3bucketResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan S3bucketModel
- var state S3bucketModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{}
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 13, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "bucketName", Field: "BucketName", Type: "string"},
- {Code: "corsAll", Field: "CorsAll", Type: "bool"},
- {Code: "listAll", Field: "ListAll", Type: "bool"},
- {Code: "maxSize", Field: "MaxSize", Type: "string"},
- {Code: "placement", Field: "Placement", Type: "string"},
- {Code: "readAll", Field: "ReadAll", Type: "bool"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- // Restore user-provided casing в state (Update).
- // После API-вызова modify state содержит значения в lower-case от API.
- // Plan == config == то что написал пользователь (регистр неизменён).
- // EqualFold: если UUID совпадает без учёта регистра — берём из plan.
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *S3bucketResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state S3bucketModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "delete"
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *S3bucketResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *S3bucketResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/148_vc_mgmt_sthutrval_cluster_resource.go b/provider/internal/resources_gen/148_vc_mgmt_sthutrval_cluster_resource.go
deleted file mode 100644
index 92d35cd..0000000
--- a/provider/internal/resources_gen/148_vc_mgmt_sthutrval_cluster_resource.go
+++ /dev/null
@@ -1,419 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "fmt"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: vc_mgmt_sthutrval_cluster
-// Service ID: 148
-
-var _ resource.Resource = &VcMgmtSthutrvalClusterResource{}
-var _ resource.ResourceWithModifyPlan = &VcMgmtSthutrvalClusterResource{}
-var _ resource.ResourceWithImportState = &VcMgmtSthutrvalClusterResource{}
-
-type VcMgmtSthutrvalClusterResource struct {
- client *core.UniversalClient
-}
-
-// VcMgmtSthutrvalClusterAccessConfigurationModel — вложенная модель для map-fixed параметра accessConfiguration.
-type VcMgmtSthutrvalClusterAccessConfigurationModel struct {
- AccessIpListAPI types.String `tfsdk:"access_ip_list_a_p_i" json:"accessIpListAPI"`
- NeedExternalAddressIngress types.Bool `tfsdk:"need_external_address_ingress" json:"needExternalAddressIngress"`
- AccessIpListIngress types.String `tfsdk:"access_ip_list_ingress" json:"accessIpListIngress"`
- NeedExternalAddressAPI types.Bool `tfsdk:"need_external_address_a_p_i" json:"needExternalAddressAPI"`
-}
-
-// VcMgmtSthutrvalClusterClusterConfigurationModel — вложенная модель для map-fixed параметра clusterConfiguration.
-type VcMgmtSthutrvalClusterClusterConfigurationModel struct {
- AppVersion types.String `tfsdk:"app_version" json:"appVersion"`
-}
-
-// VcMgmtSthutrvalClusterControlPlaneConfigurationModel — вложенная модель для map-fixed параметра controlPlaneConfiguration.
-type VcMgmtSthutrvalClusterControlPlaneConfigurationModel struct {
- SizingDisk types.Int64 `tfsdk:"sizing_disk" json:"sizingDisk"`
- Count types.Int64 `tfsdk:"count" json:"count"`
- SizingPolicy types.String `tfsdk:"sizing_policy" json:"sizingPolicy"`
-}
-
-// VcMgmtSthutrvalClusterStartupConfigurationModel — вложенная модель для map-fixed параметра startupConfiguration.
-type VcMgmtSthutrvalClusterStartupConfigurationModel struct {
- ResourceRealm types.String `tfsdk:"resource_realm" json:"resourceRealm"`
- ClusterName types.String `tfsdk:"cluster_name" json:"clusterName"`
-}
-
-type VcMgmtSthutrvalClusterModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- AccessConfiguration *VcMgmtSthutrvalClusterAccessConfigurationModel `tfsdk:"access_configuration"`
- ClusterConfiguration *VcMgmtSthutrvalClusterClusterConfigurationModel `tfsdk:"cluster_configuration"`
- ControlPlaneConfiguration *VcMgmtSthutrvalClusterControlPlaneConfigurationModel `tfsdk:"control_plane_configuration"`
- StartupConfiguration *VcMgmtSthutrvalClusterStartupConfigurationModel `tfsdk:"startup_configuration"`
- WorkerConfiguration types.String `tfsdk:"worker_configuration"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewVcMgmtSthutrvalClusterResource() resource.Resource {
- return &VcMgmtSthutrvalClusterResource{}
-}
-
-func (r *VcMgmtSthutrvalClusterResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_vc_mgmt_sthutrval_cluster"
-}
-
-func (r *VcMgmtSthutrvalClusterResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "access_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "access_ip_list_a_p_i": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[]"), MarkdownDescription: "Access IP List для подключения к Kubernetes API. Указывается массив. Если передан пустой массив, доступ выделяется всем
Пример: **["0.0.0.0/0"]** или **[]** или **["178.4.13.2", "178.4.14.0/24"]**"},
- "need_external_address_ingress": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true), MarkdownDescription: "Выделяет внешний IP для доступа к Ingress"},
- "access_ip_list_ingress": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[]"), MarkdownDescription: "Access IP List для подключения к Ingress. Указывается массив. Если передан пустой массив, доступ выделяется всем
Пример: **["0.0.0.0/0"]** или **[]** или **["178.4.13.2", "178.4.14.0/24"]**"},
- "need_external_address_a_p_i": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true), MarkdownDescription: "Выделяет внешний IP для доступа к kubernetes API. Пока нельзя выставить false"},
- }},
- "cluster_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "app_version": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("2.13.1")},
- }},
- "control_plane_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "sizing_disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(50)},
- "count": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1)},
- "sizing_policy": schema.StringAttribute{Required: true, MarkdownDescription: "Доступные sizing Policy представлены исходя из ресурсной платформы, которая была выбрана"},
- }},
- "startup_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "resource_realm": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("sandbox.nubes.ru"), MarkdownDescription: "Облако в котором будет развёрнут тенант"},
- "cluster_name": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("example-e5uamzll")},
- }},
- "worker_configuration": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[{}]"), MarkdownDescription: "Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *VcMgmtSthutrvalClusterResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *VcMgmtSthutrvalClusterModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *VcMgmtSthutrvalClusterModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan VcMgmtSthutrvalClusterModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.WorkerConfiguration.IsNull() && !plan.WorkerConfiguration.IsUnknown() && !state.WorkerConfiguration.IsNull() && !state.WorkerConfiguration.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.WorkerConfiguration.ValueString(), state.WorkerConfiguration.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить worker_configuration", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 771: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", config.StartupConfiguration.ResourceRealm.ValueString()), "clusterName": fmt.Sprintf("\"%s\"", config.StartupConfiguration.ClusterName.ValueString())}),
- 772: resources_core.BuildJSON(map[string]string{"appVersion": fmt.Sprintf("\"%s\"", config.ClusterConfiguration.AppVersion.ValueString())}),
- 773: resources_core.BuildJSON(map[string]string{"sizingDisk": fmt.Sprintf("%d", config.ControlPlaneConfiguration.SizingDisk.ValueInt64()), "count": fmt.Sprintf("%d", config.ControlPlaneConfiguration.Count.ValueInt64()), "sizingPolicy": fmt.Sprintf("\"%s\"", config.ControlPlaneConfiguration.SizingPolicy.ValueString())}),
- 774: resources_core.FormatString(config.WorkerConfiguration),
- 775: resources_core.BuildJSON(map[string]string{"accessIpListAPI": config.AccessConfiguration.AccessIpListAPI.ValueString(), "needExternalAddressIngress": fmt.Sprintf("%v", config.AccessConfiguration.NeedExternalAddressIngress.ValueBool()), "accessIpListIngress": config.AccessConfiguration.AccessIpListIngress.ValueString(), "needExternalAddressAPI": fmt.Sprintf("%v", config.AccessConfiguration.NeedExternalAddressAPI.ValueBool())}),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 148, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *VcMgmtSthutrvalClusterResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data VcMgmtSthutrvalClusterModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 148, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 771: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", data.StartupConfiguration.ResourceRealm.ValueString()), "clusterName": fmt.Sprintf("\"%s\"", data.StartupConfiguration.ClusterName.ValueString())}),
- 772: resources_core.BuildJSON(map[string]string{"appVersion": fmt.Sprintf("\"%s\"", data.ClusterConfiguration.AppVersion.ValueString())}),
- 773: resources_core.BuildJSON(map[string]string{"sizingDisk": fmt.Sprintf("%d", data.ControlPlaneConfiguration.SizingDisk.ValueInt64()), "count": fmt.Sprintf("%d", data.ControlPlaneConfiguration.Count.ValueInt64()), "sizingPolicy": fmt.Sprintf("\"%s\"", data.ControlPlaneConfiguration.SizingPolicy.ValueString())}),
- 774: resources_core.FormatString(data.WorkerConfiguration),
- 775: resources_core.BuildJSON(map[string]string{"accessIpListAPI": data.AccessConfiguration.AccessIpListAPI.ValueString(), "needExternalAddressIngress": fmt.Sprintf("%v", data.AccessConfiguration.NeedExternalAddressIngress.ValueBool()), "accessIpListIngress": data.AccessConfiguration.AccessIpListIngress.ValueString(), "needExternalAddressAPI": fmt.Sprintf("%v", data.AccessConfiguration.NeedExternalAddressAPI.ValueBool())}),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 148, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 148, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "controlPlaneConfiguration", Field: "ControlPlaneConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- {Code: "workerConfiguration", Field: "WorkerConfiguration", Type: "array-map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcMgmtSthutrvalClusterResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state VcMgmtSthutrvalClusterModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 148, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "controlPlaneConfiguration", Field: "ControlPlaneConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- {Code: "workerConfiguration", Field: "WorkerConfiguration", Type: "array-map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *VcMgmtSthutrvalClusterResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan VcMgmtSthutrvalClusterModel
- var state VcMgmtSthutrvalClusterModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{}
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 148, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "controlPlaneConfiguration", Field: "ControlPlaneConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- {Code: "workerConfiguration", Field: "WorkerConfiguration", Type: "array-map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcMgmtSthutrvalClusterResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state VcMgmtSthutrvalClusterModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "delete"
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *VcMgmtSthutrvalClusterResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *VcMgmtSthutrvalClusterResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/149_valo_tenant_resource.go b/provider/internal/resources_gen/149_valo_tenant_resource.go
deleted file mode 100644
index a3c1a9f..0000000
--- a/provider/internal/resources_gen/149_valo_tenant_resource.go
+++ /dev/null
@@ -1,431 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "fmt"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: valo_tenant
-// Service ID: 149
-
-var _ resource.Resource = &ValoTenantResource{}
-var _ resource.ResourceWithModifyPlan = &ValoTenantResource{}
-var _ resource.ResourceWithImportState = &ValoTenantResource{}
-
-type ValoTenantResource struct {
- client *core.UniversalClient
-}
-
-// ValoTenantValoOptionsModel — вложенная модель для map-fixed параметра valoOptions.
-type ValoTenantValoOptionsModel struct {
- UserCount types.Int64 `tfsdk:"user_count" json:"userCount"`
- RequestApproveMaxPeriod types.Int64 `tfsdk:"request_approve_max_period" json:"requestApproveMaxPeriod"`
- FfOnlineEditor types.Bool `tfsdk:"ff_online_editor" json:"ffOnlineEditor"`
- FfWatermark types.Bool `tfsdk:"ff_watermark" json:"ffWatermark"`
- FfUserImport types.Bool `tfsdk:"ff_user_import" json:"ffUserImport"`
- FfThemes types.Bool `tfsdk:"ff_themes" json:"ffThemes"`
- FfPublicLink types.Bool `tfsdk:"ff_public_link" json:"ffPublicLink"`
- FfLogging types.Bool `tfsdk:"ff_logging" json:"ffLogging"`
-}
-
-type ValoTenantModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- Domain types.String `tfsdk:"domain"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- S3Storage types.Int64 `tfsdk:"s3_storage"`
- ValoOptions *ValoTenantValoOptionsModel `tfsdk:"valo_options"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewValoTenantResource() resource.Resource {
- return &ValoTenantResource{}
-}
-
-func (r *ValoTenantResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_valo_tenant"
-}
-
-func (r *ValoTenantResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "domain": schema.StringAttribute{Required: true, MarkdownDescription: "Будет добавлено в зону valo.ngcloud.ru Не изменяется после создания."},
- "resource_realm": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("valo.ngcloud.ru"), MarkdownDescription: "Не изменяется после создания."},
- "s3_storage": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(10), MarkdownDescription: "Параметр указывается в `Gb`"},
- "valo_options": schema.SingleNestedAttribute{Optional: true, Computed: true,
- Attributes: map[string]schema.Attribute{
- "user_count": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(10)},
- "request_approve_max_period": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(2), MarkdownDescription: "Максимальное значение периода согласования (в днях)"},
- "ff_online_editor": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true), MarkdownDescription: "Тарифная опция"},
- "ff_watermark": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true), MarkdownDescription: "Тарифная опция"},
- "ff_user_import": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true), MarkdownDescription: "Тарифная опция"},
- "ff_themes": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true), MarkdownDescription: "Тарифная опция"},
- "ff_public_link": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true), MarkdownDescription: "Тарифная опция"},
- "ff_logging": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true), MarkdownDescription: "Тарифная опция"},
- }},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *ValoTenantResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *ValoTenantModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *ValoTenantModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan ValoTenantModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.Domain.IsNull() && !plan.Domain.IsUnknown() && !state.Domain.IsNull() && !state.Domain.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.Domain.ValueString(), state.Domain.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить domain", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.Domain.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "domain is required.")
- return
- }
- if config.Domain.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 655: resources_core.FormatString(config.ResourceRealm),
- 656: resources_core.FormatString(config.Domain),
- 657: resources_core.BuildJSON(map[string]string{"userCount": fmt.Sprintf("%d", config.ValoOptions.UserCount.ValueInt64()), "requestApproveMaxPeriod": fmt.Sprintf("%d", config.ValoOptions.RequestApproveMaxPeriod.ValueInt64()), "ffOnlineEditor": fmt.Sprintf("%v", config.ValoOptions.FfOnlineEditor.ValueBool()), "ffWatermark": fmt.Sprintf("%v", config.ValoOptions.FfWatermark.ValueBool()), "ffUserImport": fmt.Sprintf("%v", config.ValoOptions.FfUserImport.ValueBool()), "ffThemes": fmt.Sprintf("%v", config.ValoOptions.FfThemes.ValueBool()), "ffPublicLink": fmt.Sprintf("%v", config.ValoOptions.FfPublicLink.ValueBool()), "ffLogging": fmt.Sprintf("%v", config.ValoOptions.FfLogging.ValueBool())}),
- 658: resources_core.FormatInt64(config.S3Storage),
- }
- desiredDomain := ""
- if !config.Domain.IsNull() && !config.Domain.IsUnknown() {
- desiredDomain = config.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 149, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *ValoTenantResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data ValoTenantModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.Domain.IsNull() || data.Domain.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "domain is required.")
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- if !data.Domain.IsNull() && !data.Domain.IsUnknown() {
- desiredDomain = data.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 149, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 655: resources_core.FormatString(data.ResourceRealm),
- 656: resources_core.FormatString(data.Domain),
- 657: resources_core.BuildJSON(map[string]string{"userCount": fmt.Sprintf("%d", data.ValoOptions.UserCount.ValueInt64()), "requestApproveMaxPeriod": fmt.Sprintf("%d", data.ValoOptions.RequestApproveMaxPeriod.ValueInt64()), "ffOnlineEditor": fmt.Sprintf("%v", data.ValoOptions.FfOnlineEditor.ValueBool()), "ffWatermark": fmt.Sprintf("%v", data.ValoOptions.FfWatermark.ValueBool()), "ffUserImport": fmt.Sprintf("%v", data.ValoOptions.FfUserImport.ValueBool()), "ffThemes": fmt.Sprintf("%v", data.ValoOptions.FfThemes.ValueBool()), "ffPublicLink": fmt.Sprintf("%v", data.ValoOptions.FfPublicLink.ValueBool()), "ffLogging": fmt.Sprintf("%v", data.ValoOptions.FfLogging.ValueBool())}),
- 658: resources_core.FormatInt64(data.S3Storage),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 149, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 149, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "s3Storage", Field: "S3Storage", Type: "int64"},
- {Code: "valoOptions", Field: "ValoOptions", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *ValoTenantResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state ValoTenantModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 149, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "s3Storage", Field: "S3Storage", Type: "int64"},
- {Code: "valoOptions", Field: "ValoOptions", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *ValoTenantResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan ValoTenantModel
- var state ValoTenantModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.S3Storage.IsNull() != state.S3Storage.IsNull() || plan.S3Storage.IsUnknown() != state.S3Storage.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.S3Storage.IsNull() && !plan.S3Storage.IsUnknown() && !state.S3Storage.IsNull() && !state.S3Storage.IsUnknown() {
- if plan.S3Storage.ValueInt64() != state.S3Storage.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 659: resources_core.BuildJSON(map[string]string{"ffUserImport": fmt.Sprintf("%v", plan.ValoOptions.FfUserImport.ValueBool()), "ffThemes": fmt.Sprintf("%v", plan.ValoOptions.FfThemes.ValueBool()), "ffPublicLink": fmt.Sprintf("%v", plan.ValoOptions.FfPublicLink.ValueBool()), "ffLogging": fmt.Sprintf("%v", plan.ValoOptions.FfLogging.ValueBool()), "userCount": fmt.Sprintf("%d", plan.ValoOptions.UserCount.ValueInt64()), "requestApproveMaxPeriod": fmt.Sprintf("%d", plan.ValoOptions.RequestApproveMaxPeriod.ValueInt64()), "ffOnlineEditor": fmt.Sprintf("%v", plan.ValoOptions.FfOnlineEditor.ValueBool()), "ffWatermark": fmt.Sprintf("%v", plan.ValoOptions.FfWatermark.ValueBool())}),
- 660: resources_core.FormatInt64(plan.S3Storage),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 149, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "s3Storage", Field: "S3Storage", Type: "int64"},
- {Code: "valoOptions", Field: "ValoOptions", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *ValoTenantResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state ValoTenantModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *ValoTenantResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *ValoTenantResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/150_k8s_sthutrval_cluster_resource.go b/provider/internal/resources_gen/150_k8s_sthutrval_cluster_resource.go
deleted file mode 100644
index 256cb6c..0000000
--- a/provider/internal/resources_gen/150_k8s_sthutrval_cluster_resource.go
+++ /dev/null
@@ -1,429 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "fmt"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: k8s_sthutrval_cluster
-// Service ID: 150
-
-var _ resource.Resource = &K8sSthutrvalClusterResource{}
-var _ resource.ResourceWithModifyPlan = &K8sSthutrvalClusterResource{}
-var _ resource.ResourceWithImportState = &K8sSthutrvalClusterResource{}
-
-type K8sSthutrvalClusterResource struct {
- client *core.UniversalClient
-}
-
-// K8sSthutrvalClusterAccessConfigurationModel — вложенная модель для map-fixed параметра accessConfiguration.
-type K8sSthutrvalClusterAccessConfigurationModel struct {
- NeedExternalAddressIngress types.Bool `tfsdk:"need_external_address_ingress" json:"needExternalAddressIngress"`
- AccessIpListIngress types.String `tfsdk:"access_ip_list_ingress" json:"accessIpListIngress"`
- NeedExternalAddressAPI types.Bool `tfsdk:"need_external_address_a_p_i" json:"needExternalAddressAPI"`
- AccessIpListAPI types.String `tfsdk:"access_ip_list_a_p_i" json:"accessIpListAPI"`
-}
-
-// K8sSthutrvalClusterClusterConfigurationModel — вложенная модель для map-fixed параметра clusterConfiguration.
-type K8sSthutrvalClusterClusterConfigurationModel struct {
- AppVersion types.String `tfsdk:"app_version" json:"appVersion"`
-}
-
-// K8sSthutrvalClusterControlPlaneConfigurationModel — вложенная модель для map-fixed параметра controlPlaneConfiguration.
-type K8sSthutrvalClusterControlPlaneConfigurationModel struct {
- SizingDisk types.Int64 `tfsdk:"sizing_disk" json:"sizingDisk"`
- Count types.Int64 `tfsdk:"count" json:"count"`
- SizingPolicy types.String `tfsdk:"sizing_policy" json:"sizingPolicy"`
-}
-
-// K8sSthutrvalClusterStartupConfigurationModel — вложенная модель для map-fixed параметра startupConfiguration.
-type K8sSthutrvalClusterStartupConfigurationModel struct {
- ClusterName types.String `tfsdk:"cluster_name" json:"clusterName"`
- VdcUid types.String `tfsdk:"vdc_uid" json:"vdcUid"`
- NsxtUid types.String `tfsdk:"nsxt_uid" json:"nsxtUid"`
-}
-
-type K8sSthutrvalClusterModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- AccessConfiguration *K8sSthutrvalClusterAccessConfigurationModel `tfsdk:"access_configuration"`
- ClusterConfiguration *K8sSthutrvalClusterClusterConfigurationModel `tfsdk:"cluster_configuration"`
- ControlPlaneConfiguration *K8sSthutrvalClusterControlPlaneConfigurationModel `tfsdk:"control_plane_configuration"`
- StartupConfiguration *K8sSthutrvalClusterStartupConfigurationModel `tfsdk:"startup_configuration"`
- WorkerConfiguration types.String `tfsdk:"worker_configuration"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewK8sSthutrvalClusterResource() resource.Resource {
- return &K8sSthutrvalClusterResource{}
-}
-
-func (r *K8sSthutrvalClusterResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_k8s_sthutrval_cluster"
-}
-
-func (r *K8sSthutrvalClusterResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "access_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "need_external_address_ingress": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true), MarkdownDescription: "Выделяет внешний IP для доступа к Ingress"},
- "access_ip_list_ingress": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[]"), MarkdownDescription: "Access IP List для подключения к Ingress. Указывается массив. Если передан пустой массив, доступ выделяется всем"},
- "need_external_address_a_p_i": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true), MarkdownDescription: "Выделяет внешний IP для доступа к kubernetes API. Пока нельзя выставить false"},
- "access_ip_list_a_p_i": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[]"), MarkdownDescription: "Access IP List для подключения к Kubernetes API. Указывается массив. Если передан пустой массив, доступ выделяется всем"},
- }},
- "cluster_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "app_version": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("2.13.1")},
- }},
- "control_plane_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "sizing_disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(50), MarkdownDescription: "Дисковая политика берётся из услуги VDC, первый в списке"},
- "count": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1)},
- "sizing_policy": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[]"), MarkdownDescription: "Доступные sizing Policy можно обновлять через услугу `Виртуальный датацентр`"},
- }},
- "startup_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "cluster_name": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("example-vlzeyhxy")},
- "vdc_uid": schema.StringAttribute{Required: true},
- "nsxt_uid": schema.StringAttribute{Required: true},
- }},
- "worker_configuration": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[{}]")},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *K8sSthutrvalClusterResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *K8sSthutrvalClusterModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *K8sSthutrvalClusterModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan K8sSthutrvalClusterModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 750: resources_core.BuildJSON(map[string]string{"clusterName": fmt.Sprintf("\"%s\"", config.StartupConfiguration.ClusterName.ValueString()), "vdcUid": fmt.Sprintf("\"%s\"", config.StartupConfiguration.VdcUid.ValueString()), "nsxtUid": fmt.Sprintf("\"%s\"", config.StartupConfiguration.NsxtUid.ValueString())}),
- 751: resources_core.BuildJSON(map[string]string{"sizingDisk": fmt.Sprintf("%d", config.ControlPlaneConfiguration.SizingDisk.ValueInt64()), "count": fmt.Sprintf("%d", config.ControlPlaneConfiguration.Count.ValueInt64()), "sizingPolicy": fmt.Sprintf("\"%s\"", config.ControlPlaneConfiguration.SizingPolicy.ValueString())}),
- 752: resources_core.FormatString(config.WorkerConfiguration),
- 753: resources_core.BuildJSON(map[string]string{"needExternalAddressIngress": fmt.Sprintf("%v", config.AccessConfiguration.NeedExternalAddressIngress.ValueBool()), "accessIpListIngress": config.AccessConfiguration.AccessIpListIngress.ValueString(), "needExternalAddressAPI": fmt.Sprintf("%v", config.AccessConfiguration.NeedExternalAddressAPI.ValueBool()), "accessIpListAPI": config.AccessConfiguration.AccessIpListAPI.ValueString()}),
- 755: resources_core.BuildJSON(map[string]string{"appVersion": fmt.Sprintf("\"%s\"", config.ClusterConfiguration.AppVersion.ValueString())}),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 150, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *K8sSthutrvalClusterResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data K8sSthutrvalClusterModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 150, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 750: resources_core.BuildJSON(map[string]string{"clusterName": fmt.Sprintf("\"%s\"", data.StartupConfiguration.ClusterName.ValueString()), "vdcUid": fmt.Sprintf("\"%s\"", data.StartupConfiguration.VdcUid.ValueString()), "nsxtUid": fmt.Sprintf("\"%s\"", data.StartupConfiguration.NsxtUid.ValueString())}),
- 751: resources_core.BuildJSON(map[string]string{"sizingDisk": fmt.Sprintf("%d", data.ControlPlaneConfiguration.SizingDisk.ValueInt64()), "count": fmt.Sprintf("%d", data.ControlPlaneConfiguration.Count.ValueInt64()), "sizingPolicy": fmt.Sprintf("\"%s\"", data.ControlPlaneConfiguration.SizingPolicy.ValueString())}),
- 752: resources_core.FormatString(data.WorkerConfiguration),
- 753: resources_core.BuildJSON(map[string]string{"needExternalAddressIngress": fmt.Sprintf("%v", data.AccessConfiguration.NeedExternalAddressIngress.ValueBool()), "accessIpListIngress": data.AccessConfiguration.AccessIpListIngress.ValueString(), "needExternalAddressAPI": fmt.Sprintf("%v", data.AccessConfiguration.NeedExternalAddressAPI.ValueBool()), "accessIpListAPI": data.AccessConfiguration.AccessIpListAPI.ValueString()}),
- 755: resources_core.BuildJSON(map[string]string{"appVersion": fmt.Sprintf("\"%s\"", data.ClusterConfiguration.AppVersion.ValueString())}),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 150, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 150, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "controlPlaneConfiguration", Field: "ControlPlaneConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- {Code: "workerConfiguration", Field: "WorkerConfiguration", Type: "array-map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *K8sSthutrvalClusterResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state K8sSthutrvalClusterModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 150, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "controlPlaneConfiguration", Field: "ControlPlaneConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- {Code: "workerConfiguration", Field: "WorkerConfiguration", Type: "array-map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *K8sSthutrvalClusterResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan K8sSthutrvalClusterModel
- var state K8sSthutrvalClusterModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.WorkerConfiguration.IsNull() != state.WorkerConfiguration.IsNull() || plan.WorkerConfiguration.IsUnknown() != state.WorkerConfiguration.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.WorkerConfiguration.IsNull() && !plan.WorkerConfiguration.IsUnknown() && !state.WorkerConfiguration.IsNull() && !state.WorkerConfiguration.IsUnknown() {
- if !strings.EqualFold(plan.WorkerConfiguration.ValueString(), state.WorkerConfiguration.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 756: resources_core.BuildJSON(map[string]string{"appVersion": fmt.Sprintf("\"%s\"", plan.ClusterConfiguration.AppVersion.ValueString())}),
- 757: resources_core.BuildJSON(map[string]string{"sizingPolicy": fmt.Sprintf("\"%s\"", plan.ControlPlaneConfiguration.SizingPolicy.ValueString()), "sizingDisk": fmt.Sprintf("%d", plan.ControlPlaneConfiguration.SizingDisk.ValueInt64()), "count": fmt.Sprintf("%d", plan.ControlPlaneConfiguration.Count.ValueInt64())}),
- 758: resources_core.FormatString(plan.WorkerConfiguration),
- 759: resources_core.BuildJSON(map[string]string{"needExternalAddressIngress": fmt.Sprintf("%v", plan.AccessConfiguration.NeedExternalAddressIngress.ValueBool()), "accessIpListIngress": plan.AccessConfiguration.AccessIpListIngress.ValueString(), "needExternalAddressAPI": fmt.Sprintf("%v", plan.AccessConfiguration.NeedExternalAddressAPI.ValueBool()), "accessIpListAPI": plan.AccessConfiguration.AccessIpListAPI.ValueString()}),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 150, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "controlPlaneConfiguration", Field: "ControlPlaneConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- {Code: "workerConfiguration", Field: "WorkerConfiguration", Type: "array-map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *K8sSthutrvalClusterResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state K8sSthutrvalClusterModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *K8sSthutrvalClusterResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *K8sSthutrvalClusterResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/150_k8s_sthutrval_cluster_user_resource.go b/provider/internal/resources_gen/150_k8s_sthutrval_cluster_user_resource.go
deleted file mode 100644
index 55faf0e..0000000
--- a/provider/internal/resources_gen/150_k8s_sthutrval_cluster_user_resource.go
+++ /dev/null
@@ -1,343 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: k8s_sthutrval_cluster
-// Subresource: user
-
-var _ resource.Resource = &K8sSthutrvalClusterUserResource{}
-
-// K8sSthutrvalClusterUserResource manages a subresource via operations.
-type K8sSthutrvalClusterUserResource struct {
- client *core.UniversalClient
-}
-
-type K8sSthutrvalClusterUserModel struct {
- ID types.String `tfsdk:"id"`
- K8sSthutrvalClusterID types.String `tfsdk:"k8s_sthutrval_cluster_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- Admins types.String `tfsdk:"admins"`
-}
-
-func NewK8sSthutrvalClusterUserResource() resource.Resource {
- return &K8sSthutrvalClusterUserResource{}
-}
-
-func (r *K8sSthutrvalClusterUserResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_k8s_sthutrval_cluster_user"
-}
-
-func (r *K8sSthutrvalClusterUserResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "k8s_sthutrval_cluster_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "admins": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[{}]"), MarkdownDescription: "Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *K8sSthutrvalClusterUserResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan K8sSthutrvalClusterUserModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceUID := strings.TrimSpace(plan.K8sSthutrvalClusterID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{
- "admins": resources_core.FormatString(plan.Admins),
- }
- identityCodes := []string{
- "admins",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("user", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "admins": resources_core.FormatString(plan.Admins),
- })
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_user", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_user", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *K8sSthutrvalClusterUserResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state K8sSthutrvalClusterUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *K8sSthutrvalClusterUserResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan K8sSthutrvalClusterUserModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "" == "" {
- var state K8sSthutrvalClusterUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.K8sSthutrvalClusterID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- idParams := map[string]string{
- "admins": resources_core.FormatString(plan.Admins),
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *K8sSthutrvalClusterUserResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state K8sSthutrvalClusterUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "delete_user" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.K8sSthutrvalClusterID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{
- "admins": resources_core.FormatString(state.Admins),
- }
- identityCodes := []string{
- "admins",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("user", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "admins": resources_core.FormatString(state.Admins),
- })
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "delete_user", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *K8sSthutrvalClusterUserResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/151_k8s_openbao_kv_resource.go b/provider/internal/resources_gen/151_k8s_openbao_kv_resource.go
deleted file mode 100644
index 773a5c2..0000000
--- a/provider/internal/resources_gen/151_k8s_openbao_kv_resource.go
+++ /dev/null
@@ -1,343 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: k8s_openbao
-// Subresource: kv
-
-var _ resource.Resource = &K8sOpenbaoKvResource{}
-
-// K8sOpenbaoKvResource manages a subresource via operations.
-type K8sOpenbaoKvResource struct {
- client *core.UniversalClient
-}
-
-type K8sOpenbaoKvModel struct {
- ID types.String `tfsdk:"id"`
- K8sOpenbaoID types.String `tfsdk:"k8s_openbao_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- KvName types.String `tfsdk:"kv_name"`
-}
-
-func NewK8sOpenbaoKvResource() resource.Resource {
- return &K8sOpenbaoKvResource{}
-}
-
-func (r *K8sOpenbaoKvResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_k8s_openbao_kv"
-}
-
-func (r *K8sOpenbaoKvResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "k8s_openbao_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "kv_name": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("kvname-ldnwybqu"), MarkdownDescription: "Будет создан `v2 тип движка`
Уникальное в рамках услуги Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *K8sOpenbaoKvResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan K8sOpenbaoKvModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceUID := strings.TrimSpace(plan.K8sOpenbaoID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{
- "kvName": resources_core.FormatString(plan.KvName),
- }
- identityCodes := []string{
- "kvName",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("kv", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "kv", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "kvName": resources_core.FormatString(plan.KvName),
- })
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_kv", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_kv", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "kv", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "kv", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "kv", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *K8sOpenbaoKvResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state K8sOpenbaoKvModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *K8sOpenbaoKvResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan K8sOpenbaoKvModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "" == "" {
- var state K8sOpenbaoKvModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.K8sOpenbaoID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- idParams := map[string]string{
- "kvName": resources_core.FormatString(plan.KvName),
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "kv", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *K8sOpenbaoKvResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state K8sOpenbaoKvModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "delete_kv" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.K8sOpenbaoID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{
- "kvName": resources_core.FormatString(state.KvName),
- }
- identityCodes := []string{
- "kvName",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("kv", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "kvName": resources_core.FormatString(state.KvName),
- })
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "delete_kv", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *K8sOpenbaoKvResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/151_k8s_openbao_policy_resource.go b/provider/internal/resources_gen/151_k8s_openbao_policy_resource.go
deleted file mode 100644
index 668ed29..0000000
--- a/provider/internal/resources_gen/151_k8s_openbao_policy_resource.go
+++ /dev/null
@@ -1,355 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: k8s_openbao
-// Subresource: policy
-
-var _ resource.Resource = &K8sOpenbaoPolicyResource{}
-
-// K8sOpenbaoPolicyResource manages a subresource via operations.
-type K8sOpenbaoPolicyResource struct {
- client *core.UniversalClient
-}
-
-type K8sOpenbaoPolicyModel struct {
- ID types.String `tfsdk:"id"`
- K8sOpenbaoID types.String `tfsdk:"k8s_openbao_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- PolicyName types.String `tfsdk:"policy_name"`
- PolicySettings types.String `tfsdk:"policy_settings"`
-}
-
-func NewK8sOpenbaoPolicyResource() resource.Resource {
- return &K8sOpenbaoPolicyResource{}
-}
-
-func (r *K8sOpenbaoPolicyResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_k8s_openbao_policy"
-}
-
-func (r *K8sOpenbaoPolicyResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "k8s_openbao_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "policy_name": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("policy-re1w8vbp"), MarkdownDescription: "Сделано для дальнейшего удобного использования Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- "policy_settings": schema.StringAttribute{Required: true, MarkdownDescription: "Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *K8sOpenbaoPolicyResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan K8sOpenbaoPolicyModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.PolicySettings.IsNull() || plan.PolicySettings.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "policy_settings is required.")
- return
- }
-
- instanceUID := strings.TrimSpace(plan.K8sOpenbaoID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{
- "policyName": resources_core.FormatString(plan.PolicyName),
- "policySettings": resources_core.FormatString(plan.PolicySettings),
- }
- identityCodes := []string{
- "policyName",
- "policySettings",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("policy", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "policy", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "policySettings": resources_core.FormatString(plan.PolicySettings),
- "policyName": resources_core.FormatString(plan.PolicyName),
- })
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_policy", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_policy", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "policy", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "policy", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "policy", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *K8sOpenbaoPolicyResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state K8sOpenbaoPolicyModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *K8sOpenbaoPolicyResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan K8sOpenbaoPolicyModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "" == "" {
- var state K8sOpenbaoPolicyModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.K8sOpenbaoID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- idParams := map[string]string{
- "policyName": resources_core.FormatString(plan.PolicyName),
- "policySettings": resources_core.FormatString(plan.PolicySettings),
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "policy", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *K8sOpenbaoPolicyResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state K8sOpenbaoPolicyModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "delete_policy" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.K8sOpenbaoID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{
- "policyName": resources_core.FormatString(state.PolicyName),
- "policySettings": resources_core.FormatString(state.PolicySettings),
- }
- identityCodes := []string{
- "policyName",
- "policySettings",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("policy", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "policyName": resources_core.FormatString(state.PolicyName),
- })
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "delete_policy", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *K8sOpenbaoPolicyResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/151_k8s_openbao_resource.go b/provider/internal/resources_gen/151_k8s_openbao_resource.go
deleted file mode 100644
index 821648e..0000000
--- a/provider/internal/resources_gen/151_k8s_openbao_resource.go
+++ /dev/null
@@ -1,468 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: k8s_openbao
-// Service ID: 151
-
-var _ resource.Resource = &K8sOpenbaoResource{}
-var _ resource.ResourceWithModifyPlan = &K8sOpenbaoResource{}
-var _ resource.ResourceWithImportState = &K8sOpenbaoResource{}
-
-type K8sOpenbaoResource struct {
- client *core.UniversalClient
-}
-
-type K8sOpenbaoModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- AppVersion types.String `tfsdk:"app_version"`
- Domain types.String `tfsdk:"domain"`
- ResourceCPU types.Int64 `tfsdk:"resource_c_p_u"`
- ResourceDisk types.Int64 `tfsdk:"resource_disk"`
- ResourceInstances types.Int64 `tfsdk:"resource_instances"`
- ResourceMemory types.Int64 `tfsdk:"resource_memory"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewK8sOpenbaoResource() resource.Resource {
- return &K8sOpenbaoResource{}
-}
-
-func (r *K8sOpenbaoResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_k8s_openbao"
-}
-
-func (r *K8sOpenbaoResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "app_version": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("2.5.2"), MarkdownDescription: "Выбрать из списка"},
- "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("bao-pasczlik"), MarkdownDescription: "Если будет указан FQDN, то происходят проверки DNS на валидность А-записи, или будет добавлено в зону resourceRealm Не изменяется после создания."},
- "resource_c_p_u": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(500), MarkdownDescription: "Пример: `500`"},
- "resource_disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(10), MarkdownDescription: "Пример: `10`"},
- "resource_instances": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(3), MarkdownDescription: "Пример: `3`"},
- "resource_memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(512), MarkdownDescription: "Пример: `2048`"},
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Кластер Kubernetes в котором будет развёрнуто приложение Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *K8sOpenbaoResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *K8sOpenbaoModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *K8sOpenbaoModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan K8sOpenbaoModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.Domain.IsNull() && !plan.Domain.IsUnknown() && !state.Domain.IsNull() && !state.Domain.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.Domain.ValueString(), state.Domain.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить domain", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.ResourceRealm.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
- if config.ResourceRealm.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 663: resources_core.FormatString(config.ResourceRealm),
- 664: resources_core.FormatInt64(config.ResourceCPU),
- 665: resources_core.FormatInt64(config.ResourceInstances),
- 666: resources_core.FormatInt64(config.ResourceMemory),
- 667: resources_core.FormatInt64(config.ResourceDisk),
- 668: resources_core.FormatString(config.AppVersion),
- 669: resources_core.FormatString(config.Domain),
- }
- desiredDomain := ""
- if !config.Domain.IsNull() && !config.Domain.IsUnknown() {
- desiredDomain = config.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 151, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *K8sOpenbaoResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data K8sOpenbaoModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.ResourceRealm.IsNull() || data.ResourceRealm.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- if !data.Domain.IsNull() && !data.Domain.IsUnknown() {
- desiredDomain = data.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 151, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 663: resources_core.FormatString(data.ResourceRealm),
- 664: resources_core.FormatInt64(data.ResourceCPU),
- 665: resources_core.FormatInt64(data.ResourceInstances),
- 666: resources_core.FormatInt64(data.ResourceMemory),
- 667: resources_core.FormatInt64(data.ResourceDisk),
- 668: resources_core.FormatString(data.AppVersion),
- 669: resources_core.FormatString(data.Domain),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 151, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 151, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "appVersion", Field: "AppVersion", Type: "string"},
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *K8sOpenbaoResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state K8sOpenbaoModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 151, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "appVersion", Field: "AppVersion", Type: "string"},
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *K8sOpenbaoResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan K8sOpenbaoModel
- var state K8sOpenbaoModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.ResourceInstances.IsNull() != state.ResourceInstances.IsNull() || plan.ResourceInstances.IsUnknown() != state.ResourceInstances.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceInstances.IsNull() && !plan.ResourceInstances.IsUnknown() && !state.ResourceInstances.IsNull() && !state.ResourceInstances.IsUnknown() {
- if plan.ResourceInstances.ValueInt64() != state.ResourceInstances.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.ResourceCPU.IsNull() != state.ResourceCPU.IsNull() || plan.ResourceCPU.IsUnknown() != state.ResourceCPU.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceCPU.IsNull() && !plan.ResourceCPU.IsUnknown() && !state.ResourceCPU.IsNull() && !state.ResourceCPU.IsUnknown() {
- if plan.ResourceCPU.ValueInt64() != state.ResourceCPU.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.ResourceMemory.IsNull() != state.ResourceMemory.IsNull() || plan.ResourceMemory.IsUnknown() != state.ResourceMemory.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceMemory.IsNull() && !plan.ResourceMemory.IsUnknown() && !state.ResourceMemory.IsNull() && !state.ResourceMemory.IsUnknown() {
- if plan.ResourceMemory.ValueInt64() != state.ResourceMemory.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.ResourceDisk.IsNull() != state.ResourceDisk.IsNull() || plan.ResourceDisk.IsUnknown() != state.ResourceDisk.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceDisk.IsNull() && !plan.ResourceDisk.IsUnknown() && !state.ResourceDisk.IsNull() && !state.ResourceDisk.IsUnknown() {
- if plan.ResourceDisk.ValueInt64() != state.ResourceDisk.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.AppVersion.IsNull() != state.AppVersion.IsNull() || plan.AppVersion.IsUnknown() != state.AppVersion.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.AppVersion.IsNull() && !plan.AppVersion.IsUnknown() && !state.AppVersion.IsNull() && !state.AppVersion.IsUnknown() {
- if !strings.EqualFold(plan.AppVersion.ValueString(), state.AppVersion.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 670: resources_core.FormatInt64(plan.ResourceInstances),
- 671: resources_core.FormatInt64(plan.ResourceCPU),
- 672: resources_core.FormatInt64(plan.ResourceMemory),
- 673: resources_core.FormatInt64(plan.ResourceDisk),
- 674: resources_core.FormatString(plan.AppVersion),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 151, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "appVersion", Field: "AppVersion", Type: "string"},
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *K8sOpenbaoResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state K8sOpenbaoModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *K8sOpenbaoResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *K8sOpenbaoResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/151_k8s_openbao_secrets_resource.go b/provider/internal/resources_gen/151_k8s_openbao_secrets_resource.go
deleted file mode 100644
index 161164e..0000000
--- a/provider/internal/resources_gen/151_k8s_openbao_secrets_resource.go
+++ /dev/null
@@ -1,368 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: k8s_openbao
-// Subresource: secrets
-
-var _ resource.Resource = &K8sOpenbaoSecretsResource{}
-
-// K8sOpenbaoSecretsResource manages a subresource via operations.
-type K8sOpenbaoSecretsResource struct {
- client *core.UniversalClient
-}
-
-type K8sOpenbaoSecretsModel struct {
- ID types.String `tfsdk:"id"`
- K8sOpenbaoID types.String `tfsdk:"k8s_openbao_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- KvName types.String `tfsdk:"kv_name"`
- SecretData types.String `tfsdk:"secret_data"`
- SecretPath types.String `tfsdk:"secret_path"`
-}
-
-func NewK8sOpenbaoSecretsResource() resource.Resource {
- return &K8sOpenbaoSecretsResource{}
-}
-
-func (r *K8sOpenbaoSecretsResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_k8s_openbao_secrets"
-}
-
-func (r *K8sOpenbaoSecretsResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "k8s_openbao_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "kv_name": schema.StringAttribute{Required: true, MarkdownDescription: "Выберите из списка Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- "secret_data": schema.StringAttribute{Required: true, MarkdownDescription: "Хотя бы один секрет необходимо добавить Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- "secret_path": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("path/to/mysecret"), MarkdownDescription: "Пример: `path` или `road/to/path` Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *K8sOpenbaoSecretsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan K8sOpenbaoSecretsModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.KvName.IsNull() || plan.KvName.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "kv_name is required.")
- return
- }
- if plan.SecretData.IsNull() || plan.SecretData.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "secret_data is required.")
- return
- }
-
- instanceUID := strings.TrimSpace(plan.K8sOpenbaoID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{
- "kvName": resources_core.FormatString(plan.KvName),
- "secretData": resources_core.FormatString(plan.SecretData),
- "secretPath": resources_core.FormatString(plan.SecretPath),
- }
- identityCodes := []string{
- "kvName",
- "secretData",
- "secretPath",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("secrets", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "secrets", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "kvName": resources_core.FormatString(plan.KvName),
- "secretPath": resources_core.FormatString(plan.SecretPath),
- "secretData": resources_core.FormatString(plan.SecretData),
- })
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_secrets", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_secrets", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "secrets", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "secrets", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "secrets", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *K8sOpenbaoSecretsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state K8sOpenbaoSecretsModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *K8sOpenbaoSecretsResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan K8sOpenbaoSecretsModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "" == "" {
- var state K8sOpenbaoSecretsModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.K8sOpenbaoID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- idParams := map[string]string{
- "kvName": resources_core.FormatString(plan.KvName),
- "secretData": resources_core.FormatString(plan.SecretData),
- "secretPath": resources_core.FormatString(plan.SecretPath),
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "secrets", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *K8sOpenbaoSecretsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state K8sOpenbaoSecretsModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "delete_secrets" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.K8sOpenbaoID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{
- "kvName": resources_core.FormatString(state.KvName),
- "secretData": resources_core.FormatString(state.SecretData),
- "secretPath": resources_core.FormatString(state.SecretPath),
- }
- identityCodes := []string{
- "kvName",
- "secretData",
- "secretPath",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("secrets", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "kvName": resources_core.FormatString(state.KvName),
- "secretPath": resources_core.FormatString(state.SecretPath),
- })
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "delete_secrets", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *K8sOpenbaoSecretsResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/153_nifi_resource.go b/provider/internal/resources_gen/153_nifi_resource.go
deleted file mode 100644
index 12049ba..0000000
--- a/provider/internal/resources_gen/153_nifi_resource.go
+++ /dev/null
@@ -1,474 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: nifi
-// Service ID: 153
-
-var _ resource.Resource = &NifiResource{}
-var _ resource.ResourceWithModifyPlan = &NifiResource{}
-var _ resource.ResourceWithImportState = &NifiResource{}
-
-type NifiResource struct {
- client *core.UniversalClient
-}
-
-type NifiModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- AppVersion types.String `tfsdk:"app_version"`
- Domain types.String `tfsdk:"domain"`
- JdbcDrivers types.String `tfsdk:"jdbc_drivers"`
- ResourceCPU types.Int64 `tfsdk:"resource_c_p_u"`
- ResourceDisk types.Int64 `tfsdk:"resource_disk"`
- ResourceInstances types.Int64 `tfsdk:"resource_instances"`
- ResourceMemory types.Int64 `tfsdk:"resource_memory"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewNifiResource() resource.Resource {
- return &NifiResource{}
-}
-
-func (r *NifiResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_nifi"
-}
-
-func (r *NifiResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "app_version": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("2.6.0"), MarkdownDescription: "Выбрать из списка Не изменяется после создания."},
- "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("nifi-lvu4xj7j"), MarkdownDescription: "Если будет указан FQDN, то происходят проверки DNS на валидность А-записи, или будет добавлено в зону resourceRealm Не изменяется после создания."},
- "jdbc_drivers": schema.StringAttribute{Required: true, MarkdownDescription: "Пример: `https://jdbc.postgresql.org/download/postgresql-42.7.8.jar` Не изменяется после создания."},
- "resource_c_p_u": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(2000), MarkdownDescription: "Пример: `2000` Не изменяется после создания."},
- "resource_disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(10), MarkdownDescription: "Пример: `10` Не изменяется после создания."},
- "resource_instances": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Пример: `1` Не изменяется после создания."},
- "resource_memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(4096), MarkdownDescription: "Пример: `2048` Не изменяется после создания."},
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Кластер Kubernetes в котором будет развёрнуто приложение Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *NifiResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *NifiModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *NifiModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan NifiModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.AppVersion.IsNull() && !plan.AppVersion.IsUnknown() && !state.AppVersion.IsNull() && !state.AppVersion.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.AppVersion.ValueString(), state.AppVersion.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить app_version", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.Domain.IsNull() && !plan.Domain.IsUnknown() && !state.Domain.IsNull() && !state.Domain.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.Domain.ValueString(), state.Domain.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить domain", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.JdbcDrivers.IsNull() && !plan.JdbcDrivers.IsUnknown() && !state.JdbcDrivers.IsNull() && !state.JdbcDrivers.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.JdbcDrivers.ValueString(), state.JdbcDrivers.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить jdbc_drivers", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceCPU.IsNull() && !plan.ResourceCPU.IsUnknown() && !state.ResourceCPU.IsNull() && !state.ResourceCPU.IsUnknown() {
- if plan.ResourceCPU.ValueInt64() != state.ResourceCPU.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить resource_c_p_u", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceDisk.IsNull() && !plan.ResourceDisk.IsUnknown() && !state.ResourceDisk.IsNull() && !state.ResourceDisk.IsUnknown() {
- if plan.ResourceDisk.ValueInt64() != state.ResourceDisk.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить resource_disk", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceInstances.IsNull() && !plan.ResourceInstances.IsUnknown() && !state.ResourceInstances.IsNull() && !state.ResourceInstances.IsUnknown() {
- if plan.ResourceInstances.ValueInt64() != state.ResourceInstances.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить resource_instances", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceMemory.IsNull() && !plan.ResourceMemory.IsUnknown() && !state.ResourceMemory.IsNull() && !state.ResourceMemory.IsUnknown() {
- if plan.ResourceMemory.ValueInt64() != state.ResourceMemory.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить resource_memory", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.JdbcDrivers.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "jdbc_drivers is required.")
- return
- }
- if config.JdbcDrivers.IsUnknown() {
- return
- }
- if config.ResourceRealm.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
- if config.ResourceRealm.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 711: resources_core.FormatString(config.Domain),
- 712: resources_core.FormatInt64(config.ResourceCPU),
- 713: resources_core.FormatInt64(config.ResourceMemory),
- 714: resources_core.FormatInt64(config.ResourceInstances),
- 715: resources_core.FormatInt64(config.ResourceDisk),
- 716: resources_core.FormatString(config.AppVersion),
- 717: resources_core.FormatString(config.ResourceRealm),
- 718: resources_core.FormatString(config.JdbcDrivers),
- }
- desiredDomain := ""
- if !config.Domain.IsNull() && !config.Domain.IsUnknown() {
- desiredDomain = config.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 153, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *NifiResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data NifiModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.JdbcDrivers.IsNull() || data.JdbcDrivers.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "jdbc_drivers is required.")
- return
- }
- if data.ResourceRealm.IsNull() || data.ResourceRealm.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- if !data.Domain.IsNull() && !data.Domain.IsUnknown() {
- desiredDomain = data.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 153, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 711: resources_core.FormatString(data.Domain),
- 712: resources_core.FormatInt64(data.ResourceCPU),
- 713: resources_core.FormatInt64(data.ResourceMemory),
- 714: resources_core.FormatInt64(data.ResourceInstances),
- 715: resources_core.FormatInt64(data.ResourceDisk),
- 716: resources_core.FormatString(data.AppVersion),
- 717: resources_core.FormatString(data.ResourceRealm),
- 718: resources_core.FormatString(data.JdbcDrivers),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 153, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 153, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "appVersion", Field: "AppVersion", Type: "string"},
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "jdbcDrivers", Field: "JdbcDrivers", Type: "array-map-fixed"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *NifiResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state NifiModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 153, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "appVersion", Field: "AppVersion", Type: "string"},
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "jdbcDrivers", Field: "JdbcDrivers", Type: "array-map-fixed"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *NifiResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan NifiModel
- var state NifiModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{}
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 153, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "appVersion", Field: "AppVersion", Type: "string"},
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "jdbcDrivers", Field: "JdbcDrivers", Type: "array-map-fixed"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *NifiResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state NifiModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "delete"
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *NifiResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *NifiResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/163_llm_ai_resource.go b/provider/internal/resources_gen/163_llm_ai_resource.go
deleted file mode 100644
index 22a1d70..0000000
--- a/provider/internal/resources_gen/163_llm_ai_resource.go
+++ /dev/null
@@ -1,345 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: llm_ai
-// Service ID: 163
-
-var _ resource.Resource = &LlmAiResource{}
-var _ resource.ResourceWithModifyPlan = &LlmAiResource{}
-var _ resource.ResourceWithImportState = &LlmAiResource{}
-
-type LlmAiResource struct {
- client *core.UniversalClient
-}
-
-type LlmAiModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewLlmAiResource() resource.Resource {
- return &LlmAiResource{}
-}
-
-func (r *LlmAiResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_llm_ai"
-}
-
-func (r *LlmAiResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "resource_realm": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("llmAi.aillm.ru"), MarkdownDescription: "Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *LlmAiResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *LlmAiModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *LlmAiModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan LlmAiModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 826: resources_core.FormatString(config.ResourceRealm),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 163, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *LlmAiResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data LlmAiModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 163, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 826: resources_core.FormatString(data.ResourceRealm),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 163, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 163, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *LlmAiResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state LlmAiModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 163, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *LlmAiResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan LlmAiModel
- var state LlmAiModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{}
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 163, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *LlmAiResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state LlmAiModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "delete"
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *LlmAiResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *LlmAiResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/163_llm_ai_secrets_resource.go b/provider/internal/resources_gen/163_llm_ai_secrets_resource.go
deleted file mode 100644
index 0525342..0000000
--- a/provider/internal/resources_gen/163_llm_ai_secrets_resource.go
+++ /dev/null
@@ -1,401 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: llm_ai
-// Subresource: secrets
-
-var _ resource.Resource = &LlmAiSecretsResource{}
-
-// LlmAiSecretsResource manages a subresource via operations.
-type LlmAiSecretsResource struct {
- client *core.UniversalClient
-}
-
-type LlmAiSecretsModel struct {
- ID types.String `tfsdk:"id"`
- LlmAiID types.String `tfsdk:"llm_ai_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- KeyName types.String `tfsdk:"key_name"`
- Models types.String `tfsdk:"models"`
- RpmLimit types.Int64 `tfsdk:"rpm_limit"`
- TeamName types.String `tfsdk:"team_name"`
- TpmLimit types.Int64 `tfsdk:"tpm_limit"`
- VariablesKeys types.String `tfsdk:"variables_keys"`
-}
-
-func NewLlmAiSecretsResource() resource.Resource {
- return &LlmAiSecretsResource{}
-}
-
-func (r *LlmAiSecretsResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_llm_ai_secrets"
-}
-
-func (r *LlmAiSecretsResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "llm_ai_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "key_name": schema.StringAttribute{Required: true, MarkdownDescription: "Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- "models": schema.StringAttribute{Required: true, MarkdownDescription: "Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- "rpm_limit": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(60), MarkdownDescription: "Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.Int64{int64planmodifier.RequiresReplace()}},
- "team_name": schema.StringAttribute{Required: true, MarkdownDescription: "Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- "tpm_limit": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(100000), MarkdownDescription: "Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.Int64{int64planmodifier.RequiresReplace()}},
- "variables_keys": schema.StringAttribute{Required: true, MarkdownDescription: "Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *LlmAiSecretsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan LlmAiSecretsModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.KeyName.IsNull() || plan.KeyName.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "key_name is required.")
- return
- }
- if plan.Models.IsNull() || plan.Models.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "models is required.")
- return
- }
- if plan.TeamName.IsNull() || plan.TeamName.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "team_name is required.")
- return
- }
- if plan.VariablesKeys.IsNull() || plan.VariablesKeys.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "variables_keys is required.")
- return
- }
-
- instanceUID := strings.TrimSpace(plan.LlmAiID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{
- "keyName": resources_core.FormatString(plan.KeyName),
- "models": resources_core.FormatString(plan.Models),
- "rpmLimit": resources_core.FormatInt64(plan.RpmLimit),
- "teamName": resources_core.FormatString(plan.TeamName),
- "tpmLimit": resources_core.FormatInt64(plan.TpmLimit),
- "variablesKeys": resources_core.FormatString(plan.VariablesKeys),
- }
- identityCodes := []string{
- "keyName",
- "models",
- "rpmLimit",
- "teamName",
- "tpmLimit",
- "variablesKeys",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("secrets", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "secrets", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "models": resources_core.FormatString(plan.Models),
- "rpmLimit": resources_core.FormatInt64(plan.RpmLimit),
- "tpmLimit": resources_core.FormatInt64(plan.TpmLimit),
- "keyName": resources_core.FormatString(plan.KeyName),
- "teamName": resources_core.FormatString(plan.TeamName),
- "variablesKeys": resources_core.FormatString(plan.VariablesKeys),
- })
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_secrets", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_secrets", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "secrets", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "secrets", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "secrets", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *LlmAiSecretsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state LlmAiSecretsModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *LlmAiSecretsResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan LlmAiSecretsModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "" == "" {
- var state LlmAiSecretsModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.LlmAiID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- idParams := map[string]string{
- "keyName": resources_core.FormatString(plan.KeyName),
- "models": resources_core.FormatString(plan.Models),
- "rpmLimit": resources_core.FormatInt64(plan.RpmLimit),
- "teamName": resources_core.FormatString(plan.TeamName),
- "tpmLimit": resources_core.FormatInt64(plan.TpmLimit),
- "variablesKeys": resources_core.FormatString(plan.VariablesKeys),
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "secrets", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *LlmAiSecretsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state LlmAiSecretsModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "delete_secrets" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.LlmAiID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{
- "keyName": resources_core.FormatString(state.KeyName),
- "models": resources_core.FormatString(state.Models),
- "rpmLimit": resources_core.FormatInt64(state.RpmLimit),
- "teamName": resources_core.FormatString(state.TeamName),
- "tpmLimit": resources_core.FormatInt64(state.TpmLimit),
- "variablesKeys": resources_core.FormatString(state.VariablesKeys),
- }
- identityCodes := []string{
- "keyName",
- "models",
- "rpmLimit",
- "teamName",
- "tpmLimit",
- "variablesKeys",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("secrets", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "keyName": resources_core.FormatString(state.KeyName),
- "teamName": resources_core.FormatString(state.TeamName),
- })
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "delete_secrets", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *LlmAiSecretsResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/163_llm_ai_team_resource.go b/provider/internal/resources_gen/163_llm_ai_team_resource.go
deleted file mode 100644
index e411362..0000000
--- a/provider/internal/resources_gen/163_llm_ai_team_resource.go
+++ /dev/null
@@ -1,365 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: llm_ai
-// Subresource: team
-
-var _ resource.Resource = &LlmAiTeamResource{}
-
-// LlmAiTeamResource manages a subresource via operations.
-type LlmAiTeamResource struct {
- client *core.UniversalClient
-}
-
-type LlmAiTeamModel struct {
- ID types.String `tfsdk:"id"`
- LlmAiID types.String `tfsdk:"llm_ai_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- Models types.String `tfsdk:"models"`
- RpmLimit types.Int64 `tfsdk:"rpm_limit"`
- TeamName types.String `tfsdk:"team_name"`
- TpmLimit types.Int64 `tfsdk:"tpm_limit"`
-}
-
-func NewLlmAiTeamResource() resource.Resource {
- return &LlmAiTeamResource{}
-}
-
-func (r *LlmAiTeamResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_llm_ai_team"
-}
-
-func (r *LlmAiTeamResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "llm_ai_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "models": schema.StringAttribute{Required: true},
- "rpm_limit": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(60)},
- "team_name": schema.StringAttribute{Required: true, MarkdownDescription: "Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- "tpm_limit": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(100000)},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *LlmAiTeamResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan LlmAiTeamModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.Models.IsNull() || plan.Models.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "models is required.")
- return
- }
- if plan.TeamName.IsNull() || plan.TeamName.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "team_name is required.")
- return
- }
-
- instanceUID := strings.TrimSpace(plan.LlmAiID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{
- "teamName": resources_core.FormatString(plan.TeamName),
- }
- identityCodes := []string{
- "teamName",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("team", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "team", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "teamName": resources_core.FormatString(plan.TeamName),
- "models": resources_core.FormatString(plan.Models),
- "rpmLimit": resources_core.FormatInt64(plan.RpmLimit),
- "tpmLimit": resources_core.FormatInt64(plan.TpmLimit),
- })
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_team", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_team", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "team", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "team", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "team", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *LlmAiTeamResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state LlmAiTeamModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *LlmAiTeamResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan LlmAiTeamModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "modify_team" == "" {
- var state LlmAiTeamModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.LlmAiID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{
- "teamName": resources_core.FormatString(plan.TeamName),
- "models": resources_core.FormatString(plan.Models),
- "rpmLimit": resources_core.FormatInt64(plan.RpmLimit),
- "tpmLimit": resources_core.FormatInt64(plan.TpmLimit),
- })
-
- idParams := map[string]string{
- "teamName": resources_core.FormatString(plan.TeamName),
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "modify_team", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "team", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *LlmAiTeamResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state LlmAiTeamModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "delete_team" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.LlmAiID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{
- "teamName": resources_core.FormatString(state.TeamName),
- }
- identityCodes := []string{
- "teamName",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("team", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "teamName": resources_core.FormatString(state.TeamName),
- })
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "delete_team", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *LlmAiTeamResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/175_k8s_go_resource.go b/provider/internal/resources_gen/175_k8s_go_resource.go
deleted file mode 100644
index f6cc30f..0000000
--- a/provider/internal/resources_gen/175_k8s_go_resource.go
+++ /dev/null
@@ -1,422 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "fmt"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: k8s_go
-// Service ID: 175
-
-var _ resource.Resource = &K8sGoResource{}
-var _ resource.ResourceWithModifyPlan = &K8sGoResource{}
-var _ resource.ResourceWithImportState = &K8sGoResource{}
-
-type K8sGoResource struct {
- client *core.UniversalClient
-}
-
-// K8sGoAccessConfigurationModel — вложенная модель для map-fixed параметра accessConfiguration.
-type K8sGoAccessConfigurationModel struct {
- Domain types.String `tfsdk:"domain" json:"domain"`
-}
-
-// K8sGoAppConfigurationModel — вложенная модель для map-fixed параметра appConfiguration.
-type K8sGoAppConfigurationModel struct {
- Version types.String `tfsdk:"version" json:"version"`
- GitPath types.String `tfsdk:"git_path" json:"gitPath"`
- HealthPath types.String `tfsdk:"health_path" json:"healthPath"`
-}
-
-// K8sGoClusterConfigurationModel — вложенная модель для map-fixed параметра clusterConfiguration.
-type K8sGoClusterConfigurationModel struct {
- Cpu types.Int64 `tfsdk:"cpu" json:"cpu"`
- Memory types.Int64 `tfsdk:"memory" json:"memory"`
- Replicas types.Int64 `tfsdk:"replicas" json:"replicas"`
-}
-
-// K8sGoStartupConfigurationModel — вложенная модель для map-fixed параметра startupConfiguration.
-type K8sGoStartupConfigurationModel struct {
- ResourceRealm types.String `tfsdk:"resource_realm" json:"resourceRealm"`
-}
-
-type K8sGoModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- AccessConfiguration *K8sGoAccessConfigurationModel `tfsdk:"access_configuration"`
- AppConfiguration *K8sGoAppConfigurationModel `tfsdk:"app_configuration"`
- ClusterConfiguration *K8sGoClusterConfigurationModel `tfsdk:"cluster_configuration"`
- JsonEnv types.String `tfsdk:"json_env"`
- StartupConfiguration *K8sGoStartupConfigurationModel `tfsdk:"startup_configuration"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewK8sGoResource() resource.Resource {
- return &K8sGoResource{}
-}
-
-func (r *K8sGoResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_k8s_go"
-}
-
-func (r *K8sGoResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "access_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("lucee-utovgtao"), MarkdownDescription: "Если указан FQDN в формате: `myapp.example.com`, предварительно будет проверяться DNS-запись (А-запись **должна смотреть на IP Ingress кластера ресурсной платформы**)
Если указан в формате `myapp`, DNS-запись будет автоматически создана в служебной DNS-зоне"},
- }},
- "app_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "version": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("6.0")},
- "git_path": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("https://github.com/xahys/testlucee"), MarkdownDescription: "Путь до репозитория приложения
Обязательно должен быть передан как URL: `https://....`
Должен быть сетевой доступ до URL для скачивания исходников"},
- "health_path": schema.StringAttribute{Optional: true, MarkdownDescription: "Путь до healtcheck для запуска пода в Kubernetes, который отдаст 200 код
Пустое значение означает, что будет проверяться исключительно доступность приложения по порту"},
- }},
- "cluster_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "cpu": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(200), MarkdownDescription: "Указывается в Milicores
`1000` Mili == `1` Ядро"},
- "memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(256), MarkdownDescription: "Указывается в Megabytes"},
- "replicas": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1)},
- }},
- "json_env": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("{}")},
- "startup_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Кластер Kubernetes, на котором будет развернут экземпляр"},
- }},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *K8sGoResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *K8sGoModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *K8sGoModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan K8sGoModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 1046: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", config.StartupConfiguration.ResourceRealm.ValueString())}),
- 1047: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", config.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", config.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", config.ClusterConfiguration.Replicas.ValueInt64())}),
- 1048: resources_core.BuildJSON(map[string]string{"domain": fmt.Sprintf("\"%s\"", config.AccessConfiguration.Domain.ValueString())}),
- 1049: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", config.AppConfiguration.Version.ValueString()), "gitPath": fmt.Sprintf("\"%s\"", config.AppConfiguration.GitPath.ValueString()), "healthPath": fmt.Sprintf("\"%s\"", config.AppConfiguration.HealthPath.ValueString())}),
- 1050: resources_core.FormatString(config.JsonEnv),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 175, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *K8sGoResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data K8sGoModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 175, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 1046: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", data.StartupConfiguration.ResourceRealm.ValueString())}),
- 1047: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", data.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", data.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", data.ClusterConfiguration.Replicas.ValueInt64())}),
- 1048: resources_core.BuildJSON(map[string]string{"domain": fmt.Sprintf("\"%s\"", data.AccessConfiguration.Domain.ValueString())}),
- 1049: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", data.AppConfiguration.Version.ValueString()), "gitPath": fmt.Sprintf("\"%s\"", data.AppConfiguration.GitPath.ValueString()), "healthPath": fmt.Sprintf("\"%s\"", data.AppConfiguration.HealthPath.ValueString())}),
- 1050: resources_core.FormatString(data.JsonEnv),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 175, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 175, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "appConfiguration", Field: "AppConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "jsonEnv", Field: "JsonEnv", Type: "string"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *K8sGoResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state K8sGoModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 175, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "appConfiguration", Field: "AppConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "jsonEnv", Field: "JsonEnv", Type: "string"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *K8sGoResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan K8sGoModel
- var state K8sGoModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.JsonEnv.IsNull() != state.JsonEnv.IsNull() || plan.JsonEnv.IsUnknown() != state.JsonEnv.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.JsonEnv.IsNull() && !plan.JsonEnv.IsUnknown() && !state.JsonEnv.IsNull() && !state.JsonEnv.IsUnknown() {
- if !strings.EqualFold(plan.JsonEnv.ValueString(), state.JsonEnv.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 1051: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", plan.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", plan.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", plan.ClusterConfiguration.Replicas.ValueInt64())}),
- 1052: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", plan.AppConfiguration.Version.ValueString()), "gitPath": fmt.Sprintf("\"%s\"", plan.AppConfiguration.GitPath.ValueString()), "healthPath": fmt.Sprintf("\"%s\"", plan.AppConfiguration.HealthPath.ValueString())}),
- 1053: resources_core.FormatString(plan.JsonEnv),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 175, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "appConfiguration", Field: "AppConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "jsonEnv", Field: "JsonEnv", Type: "string"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *K8sGoResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state K8sGoModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *K8sGoResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *K8sGoResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/19_vc_org_resource.go b/provider/internal/resources_gen/19_vc_org_resource.go
deleted file mode 100644
index c2e768b..0000000
--- a/provider/internal/resources_gen/19_vc_org_resource.go
+++ /dev/null
@@ -1,391 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: vc_org
-// Service ID: 19
-
-var _ resource.Resource = &VcOrgResource{}
-var _ resource.ResourceWithModifyPlan = &VcOrgResource{}
-var _ resource.ResourceWithImportState = &VcOrgResource{}
-
-type VcOrgResource struct {
- client *core.UniversalClient
-}
-
-type VcOrgModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- OrganizationType types.String `tfsdk:"organization_type"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- VIPConfigure types.String `tfsdk:"v_i_p_configure"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewVcOrgResource() resource.Resource {
- return &VcOrgResource{}
-}
-
-func (r *VcOrgResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_vc_org"
-}
-
-func (r *VcOrgResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "organization_type": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("iaas"), MarkdownDescription: "Доступ к организации предоставляется только при выборе `iaas` Не изменяется после создания."},
- "resource_realm": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("sandbox.nubes.ru"), MarkdownDescription: "Облако в котором будет развёрнут тенант Не изменяется после создания."},
- "v_i_p_configure": schema.StringAttribute{Required: true},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *VcOrgResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *VcOrgModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *VcOrgModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan VcOrgModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.OrganizationType.IsNull() && !plan.OrganizationType.IsUnknown() && !state.OrganizationType.IsNull() && !state.OrganizationType.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.OrganizationType.ValueString(), state.OrganizationType.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить organization_type", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.VIPConfigure.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "v_i_p_configure is required.")
- return
- }
- if config.VIPConfigure.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 418: resources_core.FormatString(config.ResourceRealm),
- 556: resources_core.FormatString(config.OrganizationType),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 19, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *VcOrgResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data VcOrgModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.VIPConfigure.IsNull() || data.VIPConfigure.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "v_i_p_configure is required.")
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 19, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 418: resources_core.FormatString(data.ResourceRealm),
- 556: resources_core.FormatString(data.OrganizationType),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 19, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 19, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "organizationType", Field: "OrganizationType", Type: "string"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "vIPConfigure", Field: "VIPConfigure", Type: "array-map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcOrgResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state VcOrgModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 19, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "organizationType", Field: "OrganizationType", Type: "string"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "vIPConfigure", Field: "VIPConfigure", Type: "array-map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *VcOrgResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan VcOrgModel
- var state VcOrgModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.VIPConfigure.IsNull() != state.VIPConfigure.IsNull() || plan.VIPConfigure.IsUnknown() != state.VIPConfigure.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.VIPConfigure.IsNull() && !plan.VIPConfigure.IsUnknown() && !state.VIPConfigure.IsNull() && !state.VIPConfigure.IsUnknown() {
- if !strings.EqualFold(plan.VIPConfigure.ValueString(), state.VIPConfigure.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 662: resources_core.FormatString(plan.VIPConfigure),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 19, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "organizationType", Field: "OrganizationType", Type: "string"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "vIPConfigure", Field: "VIPConfigure", Type: "array-map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcOrgResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state VcOrgModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *VcOrgResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *VcOrgResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/19_vc_org_user_resource.go b/provider/internal/resources_gen/19_vc_org_user_resource.go
deleted file mode 100644
index b18fcdd..0000000
--- a/provider/internal/resources_gen/19_vc_org_user_resource.go
+++ /dev/null
@@ -1,343 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: vc_org
-// Subresource: user
-
-var _ resource.Resource = &VcOrgUserResource{}
-
-// VcOrgUserResource manages a subresource via operations.
-type VcOrgUserResource struct {
- client *core.UniversalClient
-}
-
-type VcOrgUserModel struct {
- ID types.String `tfsdk:"id"`
- VcOrgID types.String `tfsdk:"vc_org_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- Admins types.String `tfsdk:"admins"`
-}
-
-func NewVcOrgUserResource() resource.Resource {
- return &VcOrgUserResource{}
-}
-
-func (r *VcOrgUserResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_vc_org_user"
-}
-
-func (r *VcOrgUserResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "vc_org_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "admins": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[{}]"), MarkdownDescription: "Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *VcOrgUserResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan VcOrgUserModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceUID := strings.TrimSpace(plan.VcOrgID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{
- "admins": resources_core.FormatString(plan.Admins),
- }
- identityCodes := []string{
- "admins",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("user", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "admins": resources_core.FormatString(plan.Admins),
- })
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_user", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_user", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *VcOrgUserResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state VcOrgUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcOrgUserResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan VcOrgUserModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "" == "" {
- var state VcOrgUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.VcOrgID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- idParams := map[string]string{
- "admins": resources_core.FormatString(plan.Admins),
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *VcOrgUserResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state VcOrgUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "delete_user" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.VcOrgID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{
- "admins": resources_core.FormatString(state.Admins),
- }
- identityCodes := []string{
- "admins",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("user", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "admins": resources_core.FormatString(state.Admins),
- })
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "delete_user", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *VcOrgUserResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/1_dummy_resource.go b/provider/internal/resources_gen/1_dummy_resource.go
deleted file mode 100644
index e2070da..0000000
--- a/provider/internal/resources_gen/1_dummy_resource.go
+++ /dev/null
@@ -1,582 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "fmt"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: dummy
-// Service ID: 1
-
-var _ resource.Resource = &DummyResource{}
-var _ resource.ResourceWithModifyPlan = &DummyResource{}
-var _ resource.ResourceWithImportState = &DummyResource{}
-
-type DummyResource struct {
- client *core.UniversalClient
-}
-
-// DummyMapExampleModel — вложенная модель для map-fixed параметра mapExample.
-type DummyMapExampleModel struct {
- Subparam1 types.String `tfsdk:"subparam1" json:"subparam1"`
- Secret types.String `tfsdk:"secret" json:"secret"`
- Subparam2 types.String `tfsdk:"subparam2" json:"subparam2"`
-}
-
-// DummyMapFixedModel — вложенная модель для map-fixed параметра mapFixed.
-type DummyMapFixedModel struct {
- Bol1 types.Bool `tfsdk:"bol1" json:"bol1"`
- MinStr1 types.String `tfsdk:"min_str1" json:"minStr1"`
- Param1 types.Int64 `tfsdk:"param1" json:"param1"`
- Param2 types.String `tfsdk:"param2" json:"param2"`
- Param3 types.Int64 `tfsdk:"param3" json:"param3"`
-}
-
-type DummyModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- // --- Redeploy support (ARCHITECTURE.md) ---
- // git_revision: при изменении вызывает redeploy вместо modify.
- // Опциональное поле — если не задано, modify работает как обычно.
- GitRevision types.String `tfsdk:"git_revision"`
- Arr types.String `tfsdk:"arr"`
- ArrayMapFixedExample types.String `tfsdk:"array_map_fixed_example"`
- Bodymessage types.String `tfsdk:"bodymessage"`
- DurationMs types.Int64 `tfsdk:"duration_ms"`
- FailAtStart types.Bool `tfsdk:"fail_at_start"`
- FailInProgress types.Bool `tfsdk:"fail_in_progress"`
- JsonExample types.String `tfsdk:"json_example"`
- MapExample *DummyMapExampleModel `tfsdk:"map_example"`
- MapFixed *DummyMapFixedModel `tfsdk:"map_fixed"`
- NestedRefExample types.String `tfsdk:"nested_ref_example"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- WhereFail types.Int64 `tfsdk:"where_fail"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewDummyResource() resource.Resource {
- return &DummyResource{}
-}
-
-func (r *DummyResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_dummy"
-}
-
-func (r *DummyResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "arr": schema.StringAttribute{Required: true, MarkdownDescription: "Не изменяется после создания."},
- "array_map_fixed_example": schema.StringAttribute{Optional: true, MarkdownDescription: "Array of map-fixed Не изменяется после создания."},
- "bodymessage": schema.StringAttribute{Optional: true, MarkdownDescription: "Дата, уходящая в Vault"},
- "duration_ms": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(0), MarkdownDescription: "перед завершением подождать (sleep) столько миллисекунд"},
- "fail_at_start": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "если true, завершить джоб, ничего не записывая в cmdb"},
- "fail_in_progress": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "если true, корректно начать выполнение джоба, но в процессе завершить аварийно, ничего не записывая в cmdb"},
- "json_example": schema.StringAttribute{Optional: true, Computed: true, MarkdownDescription: "Для тестирования интерфейса", PlanModifiers: []planmodifier.String{resources_core.JsonNormalize()}},
- "map_example": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "subparam1": schema.StringAttribute{Optional: true, MarkdownDescription: "это для администратора"},
- "secret": schema.StringAttribute{Optional: true, MarkdownDescription: "это секрет"},
- "subparam2": schema.StringAttribute{Optional: true},
- }},
- "map_fixed": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "bol1": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Булевский, обязательный"},
- "min_str1": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("abracadabra"), MarkdownDescription: "не меньше 10 символов"},
- "param1": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Integer, secret"},
- "param2": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("1"), MarkdownDescription: "Дескрипшен"},
- "param3": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "целое положительное"},
- }},
- "nested_ref_example": schema.StringAttribute{Optional: true, MarkdownDescription: "Не изменяется после создания."},
- "resource_realm": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("dummy"), MarkdownDescription: "Платформа для развертывания Не изменяется после создания."},
- "where_fail": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "принимает 1,2,3. Работает с failInProgress. 1 - упасть в prepare. 2 - упасть внутри блока Data fill. 3 - упасть после vault write"},
- // --- Redeploy support (ARCHITECTURE.md) ---
- // При изменении git_revision вызывается redeploy вместо modify.
- // Если не задано — modify работает без изменений.
- "git_revision": schema.StringAttribute{Optional: true, MarkdownDescription: "Git revision (commit hash/tag). Changing this triggers redeploy instead of modify."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *DummyResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *DummyModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *DummyModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan DummyModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.Arr.IsNull() && !plan.Arr.IsUnknown() && !state.Arr.IsNull() && !state.Arr.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.Arr.ValueString(), state.Arr.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить arr", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ArrayMapFixedExample.IsNull() && !plan.ArrayMapFixedExample.IsUnknown() && !state.ArrayMapFixedExample.IsNull() && !state.ArrayMapFixedExample.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ArrayMapFixedExample.ValueString(), state.ArrayMapFixedExample.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить array_map_fixed_example", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.NestedRefExample.IsNull() && !plan.NestedRefExample.IsUnknown() && !state.NestedRefExample.IsNull() && !state.NestedRefExample.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.NestedRefExample.ValueString(), state.NestedRefExample.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить nested_ref_example", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.Arr.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "arr is required.")
- return
- }
- if config.Arr.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 198: resources_core.FormatInt64(config.DurationMs),
- 199: resources_core.FormatBool(config.FailAtStart),
- 200: resources_core.FormatBool(config.FailInProgress),
- 201: resources_core.FormatInt64(config.WhereFail),
- 242: resources_core.FormatString(config.ResourceRealm),
- 286: resources_core.FormatString(config.Bodymessage),
- 321: resources_core.BuildJSON(map[string]string{"subparam1": fmt.Sprintf("\"%s\"", config.MapExample.Subparam1.ValueString()), "secret": fmt.Sprintf("\"%s\"", config.MapExample.Secret.ValueString()), "subparam2": fmt.Sprintf("\"%s\"", config.MapExample.Subparam2.ValueString())}),
- 322: resources_core.FormatString(config.JsonExample),
- 396: resources_core.FormatString(config.NestedRefExample),
- 647: resources_core.BuildJSON(map[string]string{"bol1": fmt.Sprintf("%v", config.MapFixed.Bol1.ValueBool()), "minStr1": fmt.Sprintf("\"%s\"", config.MapFixed.MinStr1.ValueString()), "param1": fmt.Sprintf("%d", config.MapFixed.Param1.ValueInt64()), "param2": fmt.Sprintf("\"%s\"", config.MapFixed.Param2.ValueString()), "param3": fmt.Sprintf("%d", config.MapFixed.Param3.ValueInt64())}),
- 654: resources_core.FormatString(config.ArrayMapFixedExample),
- 863: resources_core.FormatString(config.Arr),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 1, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *DummyResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data DummyModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.Arr.IsNull() || data.Arr.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "arr is required.")
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 1, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 198: resources_core.FormatInt64(data.DurationMs),
- 199: resources_core.FormatBool(data.FailAtStart),
- 200: resources_core.FormatBool(data.FailInProgress),
- 201: resources_core.FormatInt64(data.WhereFail),
- 242: resources_core.FormatString(data.ResourceRealm),
- 286: resources_core.FormatString(data.Bodymessage),
- 321: resources_core.BuildJSON(map[string]string{"subparam1": fmt.Sprintf("\"%s\"", data.MapExample.Subparam1.ValueString()), "secret": fmt.Sprintf("\"%s\"", data.MapExample.Secret.ValueString()), "subparam2": fmt.Sprintf("\"%s\"", data.MapExample.Subparam2.ValueString())}),
- 322: resources_core.FormatString(data.JsonExample),
- 396: resources_core.FormatString(data.NestedRefExample),
- 647: resources_core.BuildJSON(map[string]string{"bol1": fmt.Sprintf("%v", data.MapFixed.Bol1.ValueBool()), "minStr1": fmt.Sprintf("\"%s\"", data.MapFixed.MinStr1.ValueString()), "param1": fmt.Sprintf("%d", data.MapFixed.Param1.ValueInt64()), "param2": fmt.Sprintf("\"%s\"", data.MapFixed.Param2.ValueString()), "param3": fmt.Sprintf("%d", data.MapFixed.Param3.ValueInt64())}),
- 654: resources_core.FormatString(data.ArrayMapFixedExample),
- 863: resources_core.FormatString(data.Arr),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 1, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 1, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "arr", Field: "Arr", Type: "string"},
- {Code: "arrayMapFixedExample", Field: "ArrayMapFixedExample", Type: "array-map-fixed"},
- {Code: "bodymessage", Field: "Bodymessage", Type: "string"},
- {Code: "durationMs", Field: "DurationMs", Type: "int64"},
- {Code: "failAtStart", Field: "FailAtStart", Type: "bool"},
- {Code: "failInProgress", Field: "FailInProgress", Type: "bool"},
- {Code: "jsonExample", Field: "JsonExample", Type: "string"},
- {Code: "mapExample", Field: "MapExample", Type: "string"},
- {Code: "mapFixed", Field: "MapFixed", Type: "map-fixed"},
- {Code: "nestedRefExample", Field: "NestedRefExample", Type: "string"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "whereFail", Field: "WhereFail", Type: "int64"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *DummyResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state DummyModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 1, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "arr", Field: "Arr", Type: "string"},
- {Code: "arrayMapFixedExample", Field: "ArrayMapFixedExample", Type: "array-map-fixed"},
- {Code: "bodymessage", Field: "Bodymessage", Type: "string"},
- {Code: "durationMs", Field: "DurationMs", Type: "int64"},
- {Code: "failAtStart", Field: "FailAtStart", Type: "bool"},
- {Code: "failInProgress", Field: "FailInProgress", Type: "bool"},
- {Code: "jsonExample", Field: "JsonExample", Type: "string"},
- {Code: "mapExample", Field: "MapExample", Type: "string"},
- {Code: "mapFixed", Field: "MapFixed", Type: "map-fixed"},
- {Code: "nestedRefExample", Field: "NestedRefExample", Type: "string"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "whereFail", Field: "WhereFail", Type: "int64"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *DummyResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan DummyModel
- var state DummyModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.DurationMs.IsNull() != state.DurationMs.IsNull() || plan.DurationMs.IsUnknown() != state.DurationMs.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.DurationMs.IsNull() && !plan.DurationMs.IsUnknown() && !state.DurationMs.IsNull() && !state.DurationMs.IsUnknown() {
- if plan.DurationMs.ValueInt64() != state.DurationMs.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.FailAtStart.IsNull() != state.FailAtStart.IsNull() || plan.FailAtStart.IsUnknown() != state.FailAtStart.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.FailAtStart.IsNull() && !plan.FailAtStart.IsUnknown() && !state.FailAtStart.IsNull() && !state.FailAtStart.IsUnknown() {
- if plan.FailAtStart.ValueBool() != state.FailAtStart.ValueBool() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.FailInProgress.IsNull() != state.FailInProgress.IsNull() || plan.FailInProgress.IsUnknown() != state.FailInProgress.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.FailInProgress.IsNull() && !plan.FailInProgress.IsUnknown() && !state.FailInProgress.IsNull() && !state.FailInProgress.IsUnknown() {
- if plan.FailInProgress.ValueBool() != state.FailInProgress.ValueBool() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.WhereFail.IsNull() != state.WhereFail.IsNull() || plan.WhereFail.IsUnknown() != state.WhereFail.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.WhereFail.IsNull() && !plan.WhereFail.IsUnknown() && !state.WhereFail.IsNull() && !state.WhereFail.IsUnknown() {
- if plan.WhereFail.ValueInt64() != state.WhereFail.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.Bodymessage.IsNull() != state.Bodymessage.IsNull() || plan.Bodymessage.IsUnknown() != state.Bodymessage.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.Bodymessage.IsNull() && !plan.Bodymessage.IsUnknown() && !state.Bodymessage.IsNull() && !state.Bodymessage.IsUnknown() {
- if !strings.EqualFold(plan.Bodymessage.ValueString(), state.Bodymessage.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.JsonExample.IsNull() != state.JsonExample.IsNull() || plan.JsonExample.IsUnknown() != state.JsonExample.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.JsonExample.IsNull() && !plan.JsonExample.IsUnknown() && !state.JsonExample.IsNull() && !state.JsonExample.IsUnknown() {
- if !strings.EqualFold(plan.JsonExample.ValueString(), state.JsonExample.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
- // --- Redeploy support (ARCHITECTURE.md) ---
- // Проверяем изменился ли git_revision.
- // Если да — вызываем redeploy вместо modify.
- // git_revision = "" (не задано) → обычный modify.
- redeployRequested := false
- if !plan.GitRevision.IsNull() && !plan.GitRevision.IsUnknown() {
- if state.GitRevision.IsNull() || state.GitRevision.IsUnknown() || plan.GitRevision.ValueString() != state.GitRevision.ValueString() {
- redeployRequested = true
- }
- }
-
- if !hasServiceParamChanges && !redeployRequested {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- // --- Redeploy support (ARCHITECTURE.md) ---
- if redeployRequested {
- // Вызываем redeploy — пустой params (операция не требует CFS-параметров)
- if err := r.client.RunRedeployOperation(ctx, instanceID.ValueString(), operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- } else {
- params := map[int]string{
- 287: resources_core.FormatInt64(plan.DurationMs),
- 288: resources_core.FormatBool(plan.FailAtStart),
- 289: resources_core.FormatBool(plan.FailInProgress),
- 290: resources_core.FormatInt64(plan.WhereFail),
- 291: resources_core.FormatString(plan.Bodymessage),
- 373: resources_core.BuildJSON(map[string]string{"secret": fmt.Sprintf("\"%s\"", plan.MapExample.Secret.ValueString())}),
- 374: resources_core.FormatString(plan.JsonExample),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 1, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "arr", Field: "Arr", Type: "string"},
- {Code: "arrayMapFixedExample", Field: "ArrayMapFixedExample", Type: "array-map-fixed"},
- {Code: "bodymessage", Field: "Bodymessage", Type: "string"},
- {Code: "durationMs", Field: "DurationMs", Type: "int64"},
- {Code: "failAtStart", Field: "FailAtStart", Type: "bool"},
- {Code: "failInProgress", Field: "FailInProgress", Type: "bool"},
- {Code: "jsonExample", Field: "JsonExample", Type: "string"},
- {Code: "mapExample", Field: "MapExample", Type: "string"},
- {Code: "mapFixed", Field: "MapFixed", Type: "map-fixed"},
- {Code: "nestedRefExample", Field: "NestedRefExample", Type: "string"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "whereFail", Field: "WhereFail", Type: "int64"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *DummyResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state DummyModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *DummyResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *DummyResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/20_vc_org_saas_resource.go b/provider/internal/resources_gen/20_vc_org_saas_resource.go
deleted file mode 100644
index 83cdd6e..0000000
--- a/provider/internal/resources_gen/20_vc_org_saas_resource.go
+++ /dev/null
@@ -1,348 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: vc_org_saas
-// Service ID: 20
-
-var _ resource.Resource = &VcOrgSaasResource{}
-var _ resource.ResourceWithModifyPlan = &VcOrgSaasResource{}
-var _ resource.ResourceWithImportState = &VcOrgSaasResource{}
-
-type VcOrgSaasResource struct {
- client *core.UniversalClient
-}
-
-type VcOrgSaasModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewVcOrgSaasResource() resource.Resource {
- return &VcOrgSaasResource{}
-}
-
-func (r *VcOrgSaasResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_vc_org_saas"
-}
-
-func (r *VcOrgSaasResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "resource_realm": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("sandbox.nubes.ru"), MarkdownDescription: "Платформа для развертывания Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *VcOrgSaasResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *VcOrgSaasModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *VcOrgSaasModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan VcOrgSaasModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 185: resources_core.FormatString(config.ResourceRealm),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 20, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *VcOrgSaasResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data VcOrgSaasModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 20, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 185: resources_core.FormatString(data.ResourceRealm),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 20, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 20, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcOrgSaasResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state VcOrgSaasModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 20, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *VcOrgSaasResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan VcOrgSaasModel
- var state VcOrgSaasModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{}
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 20, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcOrgSaasResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state VcOrgSaasModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *VcOrgSaasResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *VcOrgSaasResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/21_vc_vdc_resource.go b/provider/internal/resources_gen/21_vc_vdc_resource.go
deleted file mode 100644
index 21d0d3d..0000000
--- a/provider/internal/resources_gen/21_vc_vdc_resource.go
+++ /dev/null
@@ -1,573 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: vc_vdc
-// Service ID: 21
-
-var _ resource.Resource = &VcVdcResource{}
-var _ resource.ResourceWithModifyPlan = &VcVdcResource{}
-var _ resource.ResourceWithImportState = &VcVdcResource{}
-
-type VcVdcResource struct {
- client *core.UniversalClient
-}
-
-type VcVdcModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- CpuAllocated types.Int64 `tfsdk:"cpu_allocated"`
- CpuGuaranteed types.Int64 `tfsdk:"cpu_guaranteed"`
- MemAllocated types.Int64 `tfsdk:"mem_allocated"`
- NetworkProvider types.String `tfsdk:"network_provider"`
- OrganizationUid types.String `tfsdk:"organization_uid"`
- ProviderVdc types.String `tfsdk:"provider_vdc"`
- StorageConfig types.String `tfsdk:"storage_config"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewVcVdcResource() resource.Resource {
- return &VcVdcResource{}
-}
-
-func (r *VcVdcResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_vc_vdc"
-}
-
-func (r *VcVdcResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "cpu_allocated": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(80), MarkdownDescription: "шт"},
- "cpu_guaranteed": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(20), MarkdownDescription: "% резервирования Не изменяется после создания."},
- "mem_allocated": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(200), MarkdownDescription: "gb"},
- "network_provider": schema.StringAttribute{Required: true, MarkdownDescription: "Не изменяется после создания."},
- "organization_uid": schema.StringAttribute{Optional: true, Computed: true, MarkdownDescription: "Для создания VDC предварительно необходимо создать организацию через услугу `Организация в Cloud Director` Не изменяется после создания."},
- "provider_vdc": schema.StringAttribute{Required: true, MarkdownDescription: "Приписка `2.8` - Скорость vCPU - 2800MHz
И так далее...
Не изменяется после создания."},
- "storage_config": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[{}]"), MarkdownDescription: "Первая политика в списке указывается как "По умолчанию""},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *VcVdcResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *VcVdcModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *VcVdcModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan VcVdcModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- // FIX(uuid-case): resolve ref_svc params НЕ делаем в ModifyPlan.
- // Terraform правило: plan ОБЯЗАН равняться config для user-provided атрибутов.
- // Resolve (displayName → UUID или uppercase → lowercase) нужен только для
- // API-вызова в Create/Update. Делать его здесь = менять plan = ошибка
- // "Provider produced invalid plan: planned value does not match config value".
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.CpuGuaranteed.IsNull() && !plan.CpuGuaranteed.IsUnknown() && !state.CpuGuaranteed.IsNull() && !state.CpuGuaranteed.IsUnknown() {
- if plan.CpuGuaranteed.ValueInt64() != state.CpuGuaranteed.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить cpu_guaranteed", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.NetworkProvider.IsNull() && !plan.NetworkProvider.IsUnknown() && !state.NetworkProvider.IsNull() && !state.NetworkProvider.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.NetworkProvider.ValueString(), state.NetworkProvider.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить network_provider", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.OrganizationUid.IsNull() && !plan.OrganizationUid.IsUnknown() && !state.OrganizationUid.IsNull() && !state.OrganizationUid.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.OrganizationUid.ValueString(), state.OrganizationUid.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить organization_uid", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ProviderVdc.IsNull() && !plan.ProviderVdc.IsUnknown() && !state.ProviderVdc.IsNull() && !state.ProviderVdc.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ProviderVdc.ValueString(), state.ProviderVdc.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить provider_vdc", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.NetworkProvider.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "network_provider is required.")
- return
- }
- if config.NetworkProvider.IsUnknown() {
- return
- }
- if config.OrganizationUid.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "organization_uid is required.")
- return
- }
- if config.OrganizationUid.IsUnknown() {
- return
- }
- if config.ProviderVdc.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "provider_vdc is required.")
- return
- }
- if config.ProviderVdc.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- if !config.OrganizationUid.IsNull() && !config.OrganizationUid.IsUnknown() {
- resolvedOrganizationUid, err := r.client.ResolveRefSvcParamValue(ctx, 19, config.OrganizationUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve organization_uid", err.Error())
- } else if resolvedOrganizationUid != "" && resolvedOrganizationUid != config.OrganizationUid.ValueString() {
- config.OrganizationUid = types.StringValue(resolvedOrganizationUid)
- }
- }
- params := map[int]string{
- 30: resources_core.FormatString(config.OrganizationUid),
- 335: resources_core.FormatString(config.ProviderVdc),
- 361: resources_core.FormatString(config.StorageConfig),
- 397: resources_core.FormatInt64(config.CpuGuaranteed),
- 557: resources_core.FormatInt64(config.CpuAllocated),
- 558: resources_core.FormatInt64(config.MemAllocated),
- 746: resources_core.FormatString(config.NetworkProvider),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 21, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *VcVdcResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data VcVdcModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.NetworkProvider.IsNull() || data.NetworkProvider.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "network_provider is required.")
- return
- }
- if data.OrganizationUid.IsNull() || data.OrganizationUid.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "organization_uid is required.")
- return
- }
- if data.ProviderVdc.IsNull() || data.ProviderVdc.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "provider_vdc is required.")
- return
- }
- // ══════════════════════════════════════════════════════════════════════════
- // ПРАВИЛО TERRAFORM (официальная документация):
- // «If an attribute value is configured, it is NEVER valid to change that
- // value in the plan.» — то есть plan ОБЯЗАН равняться config (= тому что
- // написал пользователь). Менять plan запрещено на уровне фреймворка.
- //
- // ПРОБЛЕМА: API нашего облака возвращает UUID в нижнем регистре.
- // Пользователь пишет: vapp_uid = "6214BA32-..." (верхний или смешанный).
- // После apply API вернул: "6214ba32-..." → state != plan → Terraform кричит:
- // «Provider produced inconsistent result after apply».
- //
- // РЕШЕНИЕ: корректировать STATE под PLAN, а не наоборот.
- // Шаг 1 (здесь): сохраняем оригинальное значение из plan ДО того как
- // ResolveRefSvcParamValue переведёт UUID в нижний регистр (нужен для API).
- // Шаг 2 (ниже, после RefreshResourceState): восстанавливаем оригинальный
- // регистр в state через strings.EqualFold (сравниваем без учёта регистра).
- // ══════════════════════════════════════════════════════════════════════════
- originalOrganizationUid := data.OrganizationUid
- if !data.OrganizationUid.IsNull() && !data.OrganizationUid.IsUnknown() {
- resolvedOrganizationUid, err := r.client.ResolveRefSvcParamValue(ctx, 19, data.OrganizationUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if resolvedOrganizationUid != "" && resolvedOrganizationUid != data.OrganizationUid.ValueString() {
- data.OrganizationUid = types.StringValue(resolvedOrganizationUid)
- }
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 21, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 30: resources_core.FormatString(data.OrganizationUid),
- 335: resources_core.FormatString(data.ProviderVdc),
- 361: resources_core.FormatString(data.StorageConfig),
- 397: resources_core.FormatInt64(data.CpuGuaranteed),
- 557: resources_core.FormatInt64(data.CpuAllocated),
- 558: resources_core.FormatInt64(data.MemAllocated),
- 746: resources_core.FormatString(data.NetworkProvider),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 21, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 21, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "cpuAllocated", Field: "CpuAllocated", Type: "int64"},
- {Code: "cpuGuaranteed", Field: "CpuGuaranteed", Type: "int64"},
- {Code: "memAllocated", Field: "MemAllocated", Type: "int64"},
- {Code: "networkProvider", Field: "NetworkProvider", Type: "string"},
- {Code: "organizationUid", Field: "OrganizationUid", Type: "string"},
- {Code: "providerVdc", Field: "ProviderVdc", Type: "string"},
- {Code: "storageConfig", Field: "StorageConfig", Type: "array-map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !state.OrganizationUid.IsNull() && !state.OrganizationUid.IsUnknown() {
- resolvedOrganizationUid, err := r.client.ResolveRefSvcParamValue(ctx, 19, state.OrganizationUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve organization_uid", err.Error())
- } else if resolvedOrganizationUid != "" && resolvedOrganizationUid != state.OrganizationUid.ValueString() {
- state.OrganizationUid = types.StringValue(resolvedOrganizationUid)
- }
- }
- // Restore user-provided casing в state (Create).
- // EqualFold = «совпадают ли значения без учёта регистра?»
- // Если да — значит API вернул «туже» строку, только в другом регистре.
- // Заменяем state на original (то что было в plan/config пользователя).
- // Итог: plan=="6214BA32-..." и state=="6214BA32-..." → нет diff → нет taint.
- if !originalOrganizationUid.IsNull() && !originalOrganizationUid.IsUnknown() && !state.OrganizationUid.IsNull() && !state.OrganizationUid.IsUnknown() {
- if strings.EqualFold(state.OrganizationUid.ValueString(), originalOrganizationUid.ValueString()) {
- state.OrganizationUid = originalOrganizationUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcVdcResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state VcVdcModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 21, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "cpuAllocated", Field: "CpuAllocated", Type: "int64"},
- {Code: "cpuGuaranteed", Field: "CpuGuaranteed", Type: "int64"},
- {Code: "memAllocated", Field: "MemAllocated", Type: "int64"},
- {Code: "networkProvider", Field: "NetworkProvider", Type: "string"},
- {Code: "organizationUid", Field: "OrganizationUid", Type: "string"},
- {Code: "providerVdc", Field: "ProviderVdc", Type: "string"},
- {Code: "storageConfig", Field: "StorageConfig", Type: "array-map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !newState.OrganizationUid.IsNull() && !newState.OrganizationUid.IsUnknown() {
- resolvedOrganizationUid, err := r.client.ResolveRefSvcParamValue(ctx, 19, newState.OrganizationUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve organization_uid", err.Error())
- } else if resolvedOrganizationUid != "" && resolvedOrganizationUid != newState.OrganizationUid.ValueString() {
- newState.OrganizationUid = types.StringValue(resolvedOrganizationUid)
- }
- }
- // Restore user-provided casing в state (Read).
- // При чтении у нас нет plan — но предыдущий state уже хранит значение
- // в регистре пользователя (после первого Create оно было восстановлено).
- // Берём prior state (переменная state) как эталон регистра.
- // Если API вернул то же UUID только строчными буквами — восстанавливаем.
- if !state.OrganizationUid.IsNull() && !state.OrganizationUid.IsUnknown() && !newState.OrganizationUid.IsNull() && !newState.OrganizationUid.IsUnknown() {
- if strings.EqualFold(newState.OrganizationUid.ValueString(), state.OrganizationUid.ValueString()) {
- newState.OrganizationUid = state.OrganizationUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *VcVdcResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan VcVdcModel
- var state VcVdcModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.CpuAllocated.IsNull() != state.CpuAllocated.IsNull() || plan.CpuAllocated.IsUnknown() != state.CpuAllocated.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.CpuAllocated.IsNull() && !plan.CpuAllocated.IsUnknown() && !state.CpuAllocated.IsNull() && !state.CpuAllocated.IsUnknown() {
- if plan.CpuAllocated.ValueInt64() != state.CpuAllocated.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.MemAllocated.IsNull() != state.MemAllocated.IsNull() || plan.MemAllocated.IsUnknown() != state.MemAllocated.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.MemAllocated.IsNull() && !plan.MemAllocated.IsUnknown() && !state.MemAllocated.IsNull() && !state.MemAllocated.IsUnknown() {
- if plan.MemAllocated.ValueInt64() != state.MemAllocated.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.StorageConfig.IsNull() != state.StorageConfig.IsNull() || plan.StorageConfig.IsUnknown() != state.StorageConfig.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.StorageConfig.IsNull() && !plan.StorageConfig.IsUnknown() && !state.StorageConfig.IsNull() && !state.StorageConfig.IsUnknown() {
- if !strings.EqualFold(plan.StorageConfig.ValueString(), state.StorageConfig.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 560: resources_core.FormatInt64(plan.CpuAllocated),
- 561: resources_core.FormatInt64(plan.MemAllocated),
- 562: resources_core.FormatString(plan.StorageConfig),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 21, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "cpuAllocated", Field: "CpuAllocated", Type: "int64"},
- {Code: "cpuGuaranteed", Field: "CpuGuaranteed", Type: "int64"},
- {Code: "memAllocated", Field: "MemAllocated", Type: "int64"},
- {Code: "networkProvider", Field: "NetworkProvider", Type: "string"},
- {Code: "organizationUid", Field: "OrganizationUid", Type: "string"},
- {Code: "providerVdc", Field: "ProviderVdc", Type: "string"},
- {Code: "storageConfig", Field: "StorageConfig", Type: "array-map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !state.OrganizationUid.IsNull() && !state.OrganizationUid.IsUnknown() {
- resolvedOrganizationUid, err := r.client.ResolveRefSvcParamValue(ctx, 19, state.OrganizationUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve organization_uid", err.Error())
- } else if resolvedOrganizationUid != "" && resolvedOrganizationUid != state.OrganizationUid.ValueString() {
- state.OrganizationUid = types.StringValue(resolvedOrganizationUid)
- }
- }
- // Restore user-provided casing в state (Update).
- // После API-вызова modify state содержит значения в lower-case от API.
- // Plan == config == то что написал пользователь (регистр неизменён).
- // EqualFold: если UUID совпадает без учёта регистра — берём из plan.
- if !plan.OrganizationUid.IsNull() && !plan.OrganizationUid.IsUnknown() && !state.OrganizationUid.IsNull() && !state.OrganizationUid.IsUnknown() {
- if strings.EqualFold(state.OrganizationUid.ValueString(), plan.OrganizationUid.ValueString()) {
- state.OrganizationUid = plan.OrganizationUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcVdcResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state VcVdcModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *VcVdcResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *VcVdcResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/22_vc_nsxt_resource.go b/provider/internal/resources_gen/22_vc_nsxt_resource.go
deleted file mode 100644
index 58189cc..0000000
--- a/provider/internal/resources_gen/22_vc_nsxt_resource.go
+++ /dev/null
@@ -1,614 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: vc_nsxt
-// Service ID: 22
-
-var _ resource.Resource = &VcNsxtResource{}
-var _ resource.ResourceWithModifyPlan = &VcNsxtResource{}
-var _ resource.ResourceWithImportState = &VcNsxtResource{}
-
-type VcNsxtResource struct {
- client *core.UniversalClient
-}
-
-type VcNsxtModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- IpSpaceName types.String `tfsdk:"ip_space_name"`
- NeedEnableAVI types.Bool `tfsdk:"need_enable_a_v_i"`
- QosProfile types.String `tfsdk:"qos_profile"`
- VdcGroupUid types.String `tfsdk:"vdc_group_uid"`
- VdcType types.String `tfsdk:"vdc_type"`
- VdcUid types.String `tfsdk:"vdc_uid"`
- VirtualServicesCount types.Int64 `tfsdk:"virtual_services_count"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewVcNsxtResource() resource.Resource {
- return &VcNsxtResource{}
-}
-
-func (r *VcNsxtResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_vc_nsxt"
-}
-
-func (r *VcNsxtResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "ip_space_name": schema.StringAttribute{Optional: true, MarkdownDescription: "Имя ip Space для внешнего IP"},
- "need_enable_a_v_i": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Включение Load Balancer"},
- "qos_profile": schema.StringAttribute{Optional: true, MarkdownDescription: "Параметр пока не работает
Должен возвращать поле из ресурсной платформы типа vc из .vcd.hardware.gatewayQoSProfiles
Как по идее должен работать.
Нужно заполнить или CFS vdcUid, или vdcGroupUid
Идеально конечно проверять `if (params.vdcType == "vdc" && params.vdcUid != "")` или `if (params.vdcType == "vdcGroup" && params.vdcGroupUid != "")`
Далее надо пойти по стейту vdc -> org -> resPlatform, взять gatewayQoSProfiles
Или пойти по стейту vdcgroup -> vdc -> org -> resPlatform, взять gatewayQoSProfiles
Регулярку могу написать (Виталя)"},
- "vdc_group_uid": schema.StringAttribute{Optional: true, Computed: true, MarkdownDescription: "UUID Услуги `Группа виртуальных датацентров (groupvDC)` Не изменяется после создания."},
- "vdc_type": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("vdc"), MarkdownDescription: "Тип родительской услуги Не изменяется после создания."},
- "vdc_uid": schema.StringAttribute{Optional: true, Computed: true, MarkdownDescription: "UUID Услуги `Виртуальный датацентр (vDC)` Не изменяется после создания."},
- "virtual_services_count": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Кол-во виртуальных сервисов, которые **резервируются** на AVI"},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *VcNsxtResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *VcNsxtModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *VcNsxtModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan VcNsxtModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- // FIX(uuid-case): resolve ref_svc params НЕ делаем в ModifyPlan.
- // Terraform правило: plan ОБЯЗАН равняться config для user-provided атрибутов.
- // Resolve (displayName → UUID или uppercase → lowercase) нужен только для
- // API-вызова в Create/Update. Делать его здесь = менять plan = ошибка
- // "Provider produced invalid plan: planned value does not match config value".
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.VdcGroupUid.IsNull() && !plan.VdcGroupUid.IsUnknown() && !state.VdcGroupUid.IsNull() && !state.VdcGroupUid.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.VdcGroupUid.ValueString(), state.VdcGroupUid.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить vdc_group_uid", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.VdcType.IsNull() && !plan.VdcType.IsUnknown() && !state.VdcType.IsNull() && !state.VdcType.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.VdcType.ValueString(), state.VdcType.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить vdc_type", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.VdcUid.IsNull() && !plan.VdcUid.IsUnknown() && !state.VdcUid.IsNull() && !state.VdcUid.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.VdcUid.ValueString(), state.VdcUid.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить vdc_uid", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- if !config.VdcGroupUid.IsNull() && !config.VdcGroupUid.IsUnknown() {
- resolvedVdcGroupUid, err := r.client.ResolveRefSvcParamValue(ctx, 29, config.VdcGroupUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vdc_group_uid", err.Error())
- } else if resolvedVdcGroupUid != "" && resolvedVdcGroupUid != config.VdcGroupUid.ValueString() {
- config.VdcGroupUid = types.StringValue(resolvedVdcGroupUid)
- }
- }
- if !config.VdcUid.IsNull() && !config.VdcUid.IsUnknown() {
- resolvedVdcUid, err := r.client.ResolveRefSvcParamValue(ctx, 21, config.VdcUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vdc_uid", err.Error())
- } else if resolvedVdcUid != "" && resolvedVdcUid != config.VdcUid.ValueString() {
- config.VdcUid = types.StringValue(resolvedVdcUid)
- }
- }
- params := map[int]string{
- 8: resources_core.FormatString(config.VdcUid),
- 340: resources_core.FormatBool(config.NeedEnableAVI),
- 341: resources_core.FormatInt64(config.VirtualServicesCount),
- 621: resources_core.FormatString(config.VdcType),
- 622: resources_core.FormatString(config.VdcGroupUid),
- 825: resources_core.FormatString(config.QosProfile),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 22, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *VcNsxtResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data VcNsxtModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- // ══════════════════════════════════════════════════════════════════════════
- // ПРАВИЛО TERRAFORM (официальная документация):
- // «If an attribute value is configured, it is NEVER valid to change that
- // value in the plan.» — то есть plan ОБЯЗАН равняться config (= тому что
- // написал пользователь). Менять plan запрещено на уровне фреймворка.
- //
- // ПРОБЛЕМА: API нашего облака возвращает UUID в нижнем регистре.
- // Пользователь пишет: vapp_uid = "6214BA32-..." (верхний или смешанный).
- // После apply API вернул: "6214ba32-..." → state != plan → Terraform кричит:
- // «Provider produced inconsistent result after apply».
- //
- // РЕШЕНИЕ: корректировать STATE под PLAN, а не наоборот.
- // Шаг 1 (здесь): сохраняем оригинальное значение из plan ДО того как
- // ResolveRefSvcParamValue переведёт UUID в нижний регистр (нужен для API).
- // Шаг 2 (ниже, после RefreshResourceState): восстанавливаем оригинальный
- // регистр в state через strings.EqualFold (сравниваем без учёта регистра).
- // ══════════════════════════════════════════════════════════════════════════
- originalVdcGroupUid := data.VdcGroupUid
- // ══════════════════════════════════════════════════════════════════════════
- // ПРАВИЛО TERRAFORM (официальная документация):
- // «If an attribute value is configured, it is NEVER valid to change that
- // value in the plan.» — то есть plan ОБЯЗАН равняться config (= тому что
- // написал пользователь). Менять plan запрещено на уровне фреймворка.
- //
- // ПРОБЛЕМА: API нашего облака возвращает UUID в нижнем регистре.
- // Пользователь пишет: vapp_uid = "6214BA32-..." (верхний или смешанный).
- // После apply API вернул: "6214ba32-..." → state != plan → Terraform кричит:
- // «Provider produced inconsistent result after apply».
- //
- // РЕШЕНИЕ: корректировать STATE под PLAN, а не наоборот.
- // Шаг 1 (здесь): сохраняем оригинальное значение из plan ДО того как
- // ResolveRefSvcParamValue переведёт UUID в нижний регистр (нужен для API).
- // Шаг 2 (ниже, после RefreshResourceState): восстанавливаем оригинальный
- // регистр в state через strings.EqualFold (сравниваем без учёта регистра).
- // ══════════════════════════════════════════════════════════════════════════
- originalVdcUid := data.VdcUid
- if !data.VdcGroupUid.IsNull() && !data.VdcGroupUid.IsUnknown() {
- resolvedVdcGroupUid, err := r.client.ResolveRefSvcParamValue(ctx, 29, data.VdcGroupUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if resolvedVdcGroupUid != "" && resolvedVdcGroupUid != data.VdcGroupUid.ValueString() {
- data.VdcGroupUid = types.StringValue(resolvedVdcGroupUid)
- }
- }
- if !data.VdcUid.IsNull() && !data.VdcUid.IsUnknown() {
- resolvedVdcUid, err := r.client.ResolveRefSvcParamValue(ctx, 21, data.VdcUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if resolvedVdcUid != "" && resolvedVdcUid != data.VdcUid.ValueString() {
- data.VdcUid = types.StringValue(resolvedVdcUid)
- }
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 22, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 8: resources_core.FormatString(data.VdcUid),
- 340: resources_core.FormatBool(data.NeedEnableAVI),
- 341: resources_core.FormatInt64(data.VirtualServicesCount),
- 621: resources_core.FormatString(data.VdcType),
- 622: resources_core.FormatString(data.VdcGroupUid),
- 825: resources_core.FormatString(data.QosProfile),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 22, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 22, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "ipSpaceName", Field: "IpSpaceName", Type: "string"},
- {Code: "needEnableAVI", Field: "NeedEnableAVI", Type: "bool"},
- {Code: "qosProfile", Field: "QosProfile", Type: "string"},
- {Code: "vdcGroupUid", Field: "VdcGroupUid", Type: "string"},
- {Code: "vdcType", Field: "VdcType", Type: "string"},
- {Code: "vdcUid", Field: "VdcUid", Type: "string"},
- {Code: "virtualServicesCount", Field: "VirtualServicesCount", Type: "int64"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !state.VdcGroupUid.IsNull() && !state.VdcGroupUid.IsUnknown() {
- resolvedVdcGroupUid, err := r.client.ResolveRefSvcParamValue(ctx, 29, state.VdcGroupUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vdc_group_uid", err.Error())
- } else if resolvedVdcGroupUid != "" && resolvedVdcGroupUid != state.VdcGroupUid.ValueString() {
- state.VdcGroupUid = types.StringValue(resolvedVdcGroupUid)
- }
- }
- if !state.VdcUid.IsNull() && !state.VdcUid.IsUnknown() {
- resolvedVdcUid, err := r.client.ResolveRefSvcParamValue(ctx, 21, state.VdcUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vdc_uid", err.Error())
- } else if resolvedVdcUid != "" && resolvedVdcUid != state.VdcUid.ValueString() {
- state.VdcUid = types.StringValue(resolvedVdcUid)
- }
- }
- // Restore user-provided casing в state (Create).
- // EqualFold = «совпадают ли значения без учёта регистра?»
- // Если да — значит API вернул «туже» строку, только в другом регистре.
- // Заменяем state на original (то что было в plan/config пользователя).
- // Итог: plan=="6214BA32-..." и state=="6214BA32-..." → нет diff → нет taint.
- if !originalVdcGroupUid.IsNull() && !originalVdcGroupUid.IsUnknown() && !state.VdcGroupUid.IsNull() && !state.VdcGroupUid.IsUnknown() {
- if strings.EqualFold(state.VdcGroupUid.ValueString(), originalVdcGroupUid.ValueString()) {
- state.VdcGroupUid = originalVdcGroupUid
- }
- }
- if !originalVdcUid.IsNull() && !originalVdcUid.IsUnknown() && !state.VdcUid.IsNull() && !state.VdcUid.IsUnknown() {
- if strings.EqualFold(state.VdcUid.ValueString(), originalVdcUid.ValueString()) {
- state.VdcUid = originalVdcUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcNsxtResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state VcNsxtModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 22, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "ipSpaceName", Field: "IpSpaceName", Type: "string"},
- {Code: "needEnableAVI", Field: "NeedEnableAVI", Type: "bool"},
- {Code: "qosProfile", Field: "QosProfile", Type: "string"},
- {Code: "vdcGroupUid", Field: "VdcGroupUid", Type: "string"},
- {Code: "vdcType", Field: "VdcType", Type: "string"},
- {Code: "vdcUid", Field: "VdcUid", Type: "string"},
- {Code: "virtualServicesCount", Field: "VirtualServicesCount", Type: "int64"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !newState.VdcGroupUid.IsNull() && !newState.VdcGroupUid.IsUnknown() {
- resolvedVdcGroupUid, err := r.client.ResolveRefSvcParamValue(ctx, 29, newState.VdcGroupUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vdc_group_uid", err.Error())
- } else if resolvedVdcGroupUid != "" && resolvedVdcGroupUid != newState.VdcGroupUid.ValueString() {
- newState.VdcGroupUid = types.StringValue(resolvedVdcGroupUid)
- }
- }
- if !newState.VdcUid.IsNull() && !newState.VdcUid.IsUnknown() {
- resolvedVdcUid, err := r.client.ResolveRefSvcParamValue(ctx, 21, newState.VdcUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vdc_uid", err.Error())
- } else if resolvedVdcUid != "" && resolvedVdcUid != newState.VdcUid.ValueString() {
- newState.VdcUid = types.StringValue(resolvedVdcUid)
- }
- }
- // Restore user-provided casing в state (Read).
- // При чтении у нас нет plan — но предыдущий state уже хранит значение
- // в регистре пользователя (после первого Create оно было восстановлено).
- // Берём prior state (переменная state) как эталон регистра.
- // Если API вернул то же UUID только строчными буквами — восстанавливаем.
- if !state.VdcGroupUid.IsNull() && !state.VdcGroupUid.IsUnknown() && !newState.VdcGroupUid.IsNull() && !newState.VdcGroupUid.IsUnknown() {
- if strings.EqualFold(newState.VdcGroupUid.ValueString(), state.VdcGroupUid.ValueString()) {
- newState.VdcGroupUid = state.VdcGroupUid
- }
- }
- if !state.VdcUid.IsNull() && !state.VdcUid.IsUnknown() && !newState.VdcUid.IsNull() && !newState.VdcUid.IsUnknown() {
- if strings.EqualFold(newState.VdcUid.ValueString(), state.VdcUid.ValueString()) {
- newState.VdcUid = state.VdcUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *VcNsxtResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan VcNsxtModel
- var state VcNsxtModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.NeedEnableAVI.IsNull() != state.NeedEnableAVI.IsNull() || plan.NeedEnableAVI.IsUnknown() != state.NeedEnableAVI.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.NeedEnableAVI.IsNull() && !plan.NeedEnableAVI.IsUnknown() && !state.NeedEnableAVI.IsNull() && !state.NeedEnableAVI.IsUnknown() {
- if plan.NeedEnableAVI.ValueBool() != state.NeedEnableAVI.ValueBool() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.VirtualServicesCount.IsNull() != state.VirtualServicesCount.IsNull() || plan.VirtualServicesCount.IsUnknown() != state.VirtualServicesCount.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.VirtualServicesCount.IsNull() && !plan.VirtualServicesCount.IsUnknown() && !state.VirtualServicesCount.IsNull() && !state.VirtualServicesCount.IsUnknown() {
- if plan.VirtualServicesCount.ValueInt64() != state.VirtualServicesCount.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.IpSpaceName.IsNull() != state.IpSpaceName.IsNull() || plan.IpSpaceName.IsUnknown() != state.IpSpaceName.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.IpSpaceName.IsNull() && !plan.IpSpaceName.IsUnknown() && !state.IpSpaceName.IsNull() && !state.IpSpaceName.IsUnknown() {
- if !strings.EqualFold(plan.IpSpaceName.ValueString(), state.IpSpaceName.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.QosProfile.IsNull() != state.QosProfile.IsNull() || plan.QosProfile.IsUnknown() != state.QosProfile.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.QosProfile.IsNull() && !plan.QosProfile.IsUnknown() && !state.QosProfile.IsNull() && !state.QosProfile.IsUnknown() {
- if !strings.EqualFold(plan.QosProfile.ValueString(), state.QosProfile.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 368: resources_core.FormatBool(plan.NeedEnableAVI),
- 369: resources_core.FormatInt64(plan.VirtualServicesCount),
- 372: resources_core.FormatString(plan.IpSpaceName),
- 856: resources_core.FormatString(plan.QosProfile),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 22, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "ipSpaceName", Field: "IpSpaceName", Type: "string"},
- {Code: "needEnableAVI", Field: "NeedEnableAVI", Type: "bool"},
- {Code: "qosProfile", Field: "QosProfile", Type: "string"},
- {Code: "vdcGroupUid", Field: "VdcGroupUid", Type: "string"},
- {Code: "vdcType", Field: "VdcType", Type: "string"},
- {Code: "vdcUid", Field: "VdcUid", Type: "string"},
- {Code: "virtualServicesCount", Field: "VirtualServicesCount", Type: "int64"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !state.VdcGroupUid.IsNull() && !state.VdcGroupUid.IsUnknown() {
- resolvedVdcGroupUid, err := r.client.ResolveRefSvcParamValue(ctx, 29, state.VdcGroupUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vdc_group_uid", err.Error())
- } else if resolvedVdcGroupUid != "" && resolvedVdcGroupUid != state.VdcGroupUid.ValueString() {
- state.VdcGroupUid = types.StringValue(resolvedVdcGroupUid)
- }
- }
- if !state.VdcUid.IsNull() && !state.VdcUid.IsUnknown() {
- resolvedVdcUid, err := r.client.ResolveRefSvcParamValue(ctx, 21, state.VdcUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vdc_uid", err.Error())
- } else if resolvedVdcUid != "" && resolvedVdcUid != state.VdcUid.ValueString() {
- state.VdcUid = types.StringValue(resolvedVdcUid)
- }
- }
- // Restore user-provided casing в state (Update).
- // После API-вызова modify state содержит значения в lower-case от API.
- // Plan == config == то что написал пользователь (регистр неизменён).
- // EqualFold: если UUID совпадает без учёта регистра — берём из plan.
- if !plan.VdcGroupUid.IsNull() && !plan.VdcGroupUid.IsUnknown() && !state.VdcGroupUid.IsNull() && !state.VdcGroupUid.IsUnknown() {
- if strings.EqualFold(state.VdcGroupUid.ValueString(), plan.VdcGroupUid.ValueString()) {
- state.VdcGroupUid = plan.VdcGroupUid
- }
- }
- if !plan.VdcUid.IsNull() && !plan.VdcUid.IsUnknown() && !state.VdcUid.IsNull() && !state.VdcUid.IsUnknown() {
- if strings.EqualFold(state.VdcUid.ValueString(), plan.VdcUid.ValueString()) {
- state.VdcUid = plan.VdcUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcNsxtResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state VcNsxtModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "delete"
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *VcNsxtResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *VcNsxtResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/23_vc_vm_resource.go b/provider/internal/resources_gen/23_vc_vm_resource.go
deleted file mode 100644
index d39e2e1..0000000
--- a/provider/internal/resources_gen/23_vc_vm_resource.go
+++ /dev/null
@@ -1,581 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: vc_vm
-// Service ID: 23
-
-var _ resource.Resource = &VcVmResource{}
-var _ resource.ResourceWithModifyPlan = &VcVmResource{}
-var _ resource.ResourceWithImportState = &VcVmResource{}
-
-type VcVmResource struct {
- client *core.UniversalClient
-}
-
-type VcVmModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- AccessIpList types.String `tfsdk:"access_ip_list"`
- IpSpaceName types.String `tfsdk:"ip_space_name"`
- TemplateName types.String `tfsdk:"template_name"`
- VappUid types.String `tfsdk:"vapp_uid"`
- VmCpu types.String `tfsdk:"vm_cpu"`
- VmDisksize types.String `tfsdk:"vm_disksize"`
- VmName types.String `tfsdk:"vm_name"`
- VmRam types.String `tfsdk:"vm_ram"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewVcVmResource() resource.Resource {
- return &VcVmResource{}
-}
-
-func (r *VcVmResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_vc_vm"
-}
-
-func (r *VcVmResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "access_ip_list": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("79.111.119.78/32 185.247.187.1/32"), MarkdownDescription: "Вставить содержимое из 'curl ifconfig.io'
IP адреса в CIDR формате через пробел для настройки аксес листов"},
- "ip_space_name": schema.StringAttribute{Required: true, MarkdownDescription: "Брать из свойств ресурсной платформы
.vcd.ipSpace
Имя IP-space для выделения внешнего IP (IP выделяется обязательно) Не изменяется после создания."},
- "template_name": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("RockyLinux_9-16G"), MarkdownDescription: "ОС Не изменяется после создания."},
- "vapp_uid": schema.StringAttribute{Optional: true, Computed: true, MarkdownDescription: "InstanceUid vApp. vApp должен быть создан Не изменяется после создания."},
- "vm_cpu": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("2"), MarkdownDescription: "CPU"},
- "vm_disksize": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("10"), MarkdownDescription: "Размер диска под сервис (GB)"},
- "vm_name": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("vm0001"), MarkdownDescription: "Имя ВМ. Не поддерживает спец-символы Не изменяется после создания."},
- "vm_ram": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("2"), MarkdownDescription: "RAM (GB)"},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *VcVmResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *VcVmModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *VcVmModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan VcVmModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- // FIX(uuid-case): resolve ref_svc params НЕ делаем в ModifyPlan.
- // Terraform правило: plan ОБЯЗАН равняться config для user-provided атрибутов.
- // Resolve (displayName → UUID или uppercase → lowercase) нужен только для
- // API-вызова в Create/Update. Делать его здесь = менять plan = ошибка
- // "Provider produced invalid plan: planned value does not match config value".
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.IpSpaceName.IsNull() && !plan.IpSpaceName.IsUnknown() && !state.IpSpaceName.IsNull() && !state.IpSpaceName.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.IpSpaceName.ValueString(), state.IpSpaceName.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить ip_space_name", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.TemplateName.IsNull() && !plan.TemplateName.IsUnknown() && !state.TemplateName.IsNull() && !state.TemplateName.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.TemplateName.ValueString(), state.TemplateName.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить template_name", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.VappUid.IsNull() && !plan.VappUid.IsUnknown() && !state.VappUid.IsNull() && !state.VappUid.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.VappUid.ValueString(), state.VappUid.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить vapp_uid", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.VmName.IsNull() && !plan.VmName.IsUnknown() && !state.VmName.IsNull() && !state.VmName.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.VmName.ValueString(), state.VmName.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить vm_name", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.IpSpaceName.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "ip_space_name is required.")
- return
- }
- if config.IpSpaceName.IsUnknown() {
- return
- }
- if config.VappUid.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "vapp_uid is required.")
- return
- }
- if config.VappUid.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- if !config.VappUid.IsNull() && !config.VappUid.IsUnknown() {
- resolvedVappUid, err := r.client.ResolveRefSvcParamValue(ctx, 26, config.VappUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vapp_uid", err.Error())
- } else if resolvedVappUid != "" && resolvedVappUid != config.VappUid.ValueString() {
- config.VappUid = types.StringValue(resolvedVappUid)
- }
- }
- params := map[int]string{
- 33: resources_core.FormatString(config.VappUid),
- 35: resources_core.FormatString(config.VmName),
- 36: resources_core.FormatString(config.VmCpu),
- 37: resources_core.FormatString(config.VmRam),
- 38: resources_core.FormatString(config.VmDisksize),
- 176: resources_core.FormatString(config.TemplateName),
- 177: resources_core.FormatString(config.AccessIpList),
- 406: resources_core.FormatString(config.IpSpaceName),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 23, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *VcVmResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data VcVmModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.IpSpaceName.IsNull() || data.IpSpaceName.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "ip_space_name is required.")
- return
- }
- if data.VappUid.IsNull() || data.VappUid.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "vapp_uid is required.")
- return
- }
- // ══════════════════════════════════════════════════════════════════════════
- // ПРАВИЛО TERRAFORM (официальная документация):
- // «If an attribute value is configured, it is NEVER valid to change that
- // value in the plan.» — то есть plan ОБЯЗАН равняться config (= тому что
- // написал пользователь). Менять plan запрещено на уровне фреймворка.
- //
- // ПРОБЛЕМА: API нашего облака возвращает UUID в нижнем регистре.
- // Пользователь пишет: vapp_uid = "6214BA32-..." (верхний или смешанный).
- // После apply API вернул: "6214ba32-..." → state != plan → Terraform кричит:
- // «Provider produced inconsistent result after apply».
- //
- // РЕШЕНИЕ: корректировать STATE под PLAN, а не наоборот.
- // Шаг 1 (здесь): сохраняем оригинальное значение из plan ДО того как
- // ResolveRefSvcParamValue переведёт UUID в нижний регистр (нужен для API).
- // Шаг 2 (ниже, после RefreshResourceState): восстанавливаем оригинальный
- // регистр в state через strings.EqualFold (сравниваем без учёта регистра).
- // ══════════════════════════════════════════════════════════════════════════
- originalVappUid := data.VappUid
- if !data.VappUid.IsNull() && !data.VappUid.IsUnknown() {
- resolvedVappUid, err := r.client.ResolveRefSvcParamValue(ctx, 26, data.VappUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if resolvedVappUid != "" && resolvedVappUid != data.VappUid.ValueString() {
- data.VappUid = types.StringValue(resolvedVappUid)
- }
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 23, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 33: resources_core.FormatString(data.VappUid),
- 35: resources_core.FormatString(data.VmName),
- 36: resources_core.FormatString(data.VmCpu),
- 37: resources_core.FormatString(data.VmRam),
- 38: resources_core.FormatString(data.VmDisksize),
- 176: resources_core.FormatString(data.TemplateName),
- 177: resources_core.FormatString(data.AccessIpList),
- 406: resources_core.FormatString(data.IpSpaceName),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 23, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 23, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessIpList", Field: "AccessIpList", Type: "string"},
- {Code: "ipSpaceName", Field: "IpSpaceName", Type: "string"},
- {Code: "templateName", Field: "TemplateName", Type: "string"},
- {Code: "vappUid", Field: "VappUid", Type: "string"},
- {Code: "vmCpu", Field: "VmCpu", Type: "string"},
- {Code: "vmDisksize", Field: "VmDisksize", Type: "string"},
- {Code: "vmName", Field: "VmName", Type: "string"},
- {Code: "vmRam", Field: "VmRam", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !state.VappUid.IsNull() && !state.VappUid.IsUnknown() {
- resolvedVappUid, err := r.client.ResolveRefSvcParamValue(ctx, 26, state.VappUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vapp_uid", err.Error())
- } else if resolvedVappUid != "" && resolvedVappUid != state.VappUid.ValueString() {
- state.VappUid = types.StringValue(resolvedVappUid)
- }
- }
- // Restore user-provided casing в state (Create).
- // EqualFold = «совпадают ли значения без учёта регистра?»
- // Если да — значит API вернул «туже» строку, только в другом регистре.
- // Заменяем state на original (то что было в plan/config пользователя).
- // Итог: plan=="6214BA32-..." и state=="6214BA32-..." → нет diff → нет taint.
- if !originalVappUid.IsNull() && !originalVappUid.IsUnknown() && !state.VappUid.IsNull() && !state.VappUid.IsUnknown() {
- if strings.EqualFold(state.VappUid.ValueString(), originalVappUid.ValueString()) {
- state.VappUid = originalVappUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcVmResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state VcVmModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 23, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessIpList", Field: "AccessIpList", Type: "string"},
- {Code: "ipSpaceName", Field: "IpSpaceName", Type: "string"},
- {Code: "templateName", Field: "TemplateName", Type: "string"},
- {Code: "vappUid", Field: "VappUid", Type: "string"},
- {Code: "vmCpu", Field: "VmCpu", Type: "string"},
- {Code: "vmDisksize", Field: "VmDisksize", Type: "string"},
- {Code: "vmName", Field: "VmName", Type: "string"},
- {Code: "vmRam", Field: "VmRam", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !newState.VappUid.IsNull() && !newState.VappUid.IsUnknown() {
- resolvedVappUid, err := r.client.ResolveRefSvcParamValue(ctx, 26, newState.VappUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vapp_uid", err.Error())
- } else if resolvedVappUid != "" && resolvedVappUid != newState.VappUid.ValueString() {
- newState.VappUid = types.StringValue(resolvedVappUid)
- }
- }
- // Restore user-provided casing в state (Read).
- // При чтении у нас нет plan — но предыдущий state уже хранит значение
- // в регистре пользователя (после первого Create оно было восстановлено).
- // Берём prior state (переменная state) как эталон регистра.
- // Если API вернул то же UUID только строчными буквами — восстанавливаем.
- if !state.VappUid.IsNull() && !state.VappUid.IsUnknown() && !newState.VappUid.IsNull() && !newState.VappUid.IsUnknown() {
- if strings.EqualFold(newState.VappUid.ValueString(), state.VappUid.ValueString()) {
- newState.VappUid = state.VappUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *VcVmResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan VcVmModel
- var state VcVmModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.VmCpu.IsNull() != state.VmCpu.IsNull() || plan.VmCpu.IsUnknown() != state.VmCpu.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.VmCpu.IsNull() && !plan.VmCpu.IsUnknown() && !state.VmCpu.IsNull() && !state.VmCpu.IsUnknown() {
- if !strings.EqualFold(plan.VmCpu.ValueString(), state.VmCpu.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.VmRam.IsNull() != state.VmRam.IsNull() || plan.VmRam.IsUnknown() != state.VmRam.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.VmRam.IsNull() && !plan.VmRam.IsUnknown() && !state.VmRam.IsNull() && !state.VmRam.IsUnknown() {
- if !strings.EqualFold(plan.VmRam.ValueString(), state.VmRam.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.VmDisksize.IsNull() != state.VmDisksize.IsNull() || plan.VmDisksize.IsUnknown() != state.VmDisksize.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.VmDisksize.IsNull() && !plan.VmDisksize.IsUnknown() && !state.VmDisksize.IsNull() && !state.VmDisksize.IsUnknown() {
- if !strings.EqualFold(plan.VmDisksize.ValueString(), state.VmDisksize.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.AccessIpList.IsNull() != state.AccessIpList.IsNull() || plan.AccessIpList.IsUnknown() != state.AccessIpList.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.AccessIpList.IsNull() && !plan.AccessIpList.IsUnknown() && !state.AccessIpList.IsNull() && !state.AccessIpList.IsUnknown() {
- if !strings.EqualFold(plan.AccessIpList.ValueString(), state.AccessIpList.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 186: resources_core.FormatString(plan.VmCpu),
- 187: resources_core.FormatString(plan.VmRam),
- 188: resources_core.FormatString(plan.VmDisksize),
- 189: resources_core.FormatString(plan.AccessIpList),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 23, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessIpList", Field: "AccessIpList", Type: "string"},
- {Code: "ipSpaceName", Field: "IpSpaceName", Type: "string"},
- {Code: "templateName", Field: "TemplateName", Type: "string"},
- {Code: "vappUid", Field: "VappUid", Type: "string"},
- {Code: "vmCpu", Field: "VmCpu", Type: "string"},
- {Code: "vmDisksize", Field: "VmDisksize", Type: "string"},
- {Code: "vmName", Field: "VmName", Type: "string"},
- {Code: "vmRam", Field: "VmRam", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !state.VappUid.IsNull() && !state.VappUid.IsUnknown() {
- resolvedVappUid, err := r.client.ResolveRefSvcParamValue(ctx, 26, state.VappUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vapp_uid", err.Error())
- } else if resolvedVappUid != "" && resolvedVappUid != state.VappUid.ValueString() {
- state.VappUid = types.StringValue(resolvedVappUid)
- }
- }
- // Restore user-provided casing в state (Update).
- // После API-вызова modify state содержит значения в lower-case от API.
- // Plan == config == то что написал пользователь (регистр неизменён).
- // EqualFold: если UUID совпадает без учёта регистра — берём из plan.
- if !plan.VappUid.IsNull() && !plan.VappUid.IsUnknown() && !state.VappUid.IsNull() && !state.VappUid.IsUnknown() {
- if strings.EqualFold(state.VappUid.ValueString(), plan.VappUid.ValueString()) {
- state.VappUid = plan.VappUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcVmResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state VcVmModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *VcVmResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *VcVmResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/24_vc_nat_resource.go b/provider/internal/resources_gen/24_vc_nat_resource.go
deleted file mode 100644
index 20fe4bd..0000000
--- a/provider/internal/resources_gen/24_vc_nat_resource.go
+++ /dev/null
@@ -1,322 +0,0 @@
-package resources_gen
-
-import (
- "context"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: vc_nat
-// Service ID: 24
-
-var _ resource.Resource = &VcNatResource{}
-var _ resource.ResourceWithModifyPlan = &VcNatResource{}
-var _ resource.ResourceWithImportState = &VcNatResource{}
-
-type VcNatResource struct {
- client *core.UniversalClient
-}
-
-type VcNatModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewVcNatResource() resource.Resource {
- return &VcNatResource{}
-}
-
-func (r *VcNatResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_vc_nat"
-}
-
-func (r *VcNatResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *VcNatResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *VcNatModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *VcNatModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan VcNatModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{}
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 24, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *VcNatResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data VcNatModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 24, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{}
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 24, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 24, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{})
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcNatResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state VcNatModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 24, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{})
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *VcNatResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan VcNatModel
- var state VcNatModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{}
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 24, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{})
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcNatResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state VcNatModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "delete"
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *VcNatResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *VcNatResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/25_vcexternalip_resource.go b/provider/internal/resources_gen/25_vcexternalip_resource.go
deleted file mode 100644
index c375621..0000000
--- a/provider/internal/resources_gen/25_vcexternalip_resource.go
+++ /dev/null
@@ -1,604 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: vcexternalip
-// Service ID: 25
-
-var _ resource.Resource = &VcexternalipResource{}
-var _ resource.ResourceWithModifyPlan = &VcexternalipResource{}
-var _ resource.ResourceWithImportState = &VcexternalipResource{}
-
-type VcexternalipResource struct {
- client *core.UniversalClient
-}
-
-type VcexternalipModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- DnatCreate types.Bool `tfsdk:"dnat_create"`
- FromServiceCloudEdgeName types.String `tfsdk:"from_service_cloud_edge_name"`
- FromServiceCloudEdgeScope types.String `tfsdk:"from_service_cloud_edge_scope"`
- FromServiceCloudOrgName types.String `tfsdk:"from_service_cloud_org_name"`
- FromServiceCloudVdcName types.String `tfsdk:"from_service_cloud_vdc_name"`
- FromServiceCloudVmwareUrl types.String `tfsdk:"from_service_cloud_vmware_url"`
- FromServiceNamespace types.String `tfsdk:"from_service_namespace"`
- FromServiceVdcGroupName types.String `tfsdk:"from_service_vdc_group_name"`
- InternalAddrAccess types.String `tfsdk:"internal_addr_access"`
- InternalPortAccess types.String `tfsdk:"internal_port_access"`
- IpSpaceName types.String `tfsdk:"ip_space_name"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- ServiceUid types.String `tfsdk:"service_uid"`
- SnatCreate types.Bool `tfsdk:"snat_create"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewVcexternalipResource() resource.Resource {
- return &VcexternalipResource{}
-}
-
-func (r *VcexternalipResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_vcexternalip"
-}
-
-func (r *VcexternalipResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "dnat_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true), MarkdownDescription: "Необходимо создать DNAT-правило."},
- "from_service_cloud_edge_name": schema.StringAttribute{Optional: true, MarkdownDescription: "Edge составной услуги (указывать, если resourceRealm связан с CloudDirector) Не изменяется после создания."},
- "from_service_cloud_edge_scope": schema.StringAttribute{Optional: true, MarkdownDescription: "Не изменяется после создания."},
- "from_service_cloud_org_name": schema.StringAttribute{Optional: true, MarkdownDescription: "Org составной услуги (указывать, если resourceRealm связан с CloudDirector) Не изменяется после создания."},
- "from_service_cloud_vdc_name": schema.StringAttribute{Optional: true, MarkdownDescription: "Vdc составной услуги (указывать, если resourceRealm связан с CloudDirector) Не изменяется после создания."},
- "from_service_cloud_vmware_url": schema.StringAttribute{Optional: true, MarkdownDescription: "Api-Url составной услуги (указывать, если resourceRealm связан с CloudDirector) Не изменяется после создания."},
- "from_service_namespace": schema.StringAttribute{Required: true, MarkdownDescription: "Namespace составной услуги (для отображения правил FW) Не изменяется после создания."},
- "from_service_vdc_group_name": schema.StringAttribute{Optional: true, MarkdownDescription: "Не изменяется после создания."},
- "internal_addr_access": schema.StringAttribute{Required: true, MarkdownDescription: "Внутренний адрес для связки ната. Требует dnatCreate=true или snatCreate=true"},
- "internal_port_access": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("5432"), MarkdownDescription: "Порт для связки ната с адресом. Несколько значений можно передавать через пробел. Если передать all, то dnat будет на все порты. Требует dnatCreate=true
"},
- "ip_space_name": schema.StringAttribute{Required: true, MarkdownDescription: "Тип ip Space (internet-ipv4-v1 / internet-antiddos-v1 / internet-no-antiddos-v1)"},
- "resource_realm": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("sandbox.nubes.ru"), MarkdownDescription: "Платформа для развертывания Не изменяется после создания."},
- "service_uid": schema.StringAttribute{Required: true},
- "snat_create": schema.BoolAttribute{Optional: true, MarkdownDescription: "Необходимо создать SNAT-правило.
"},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *VcexternalipResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *VcexternalipModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *VcexternalipModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan VcexternalipModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.FromServiceCloudEdgeName.IsNull() && !plan.FromServiceCloudEdgeName.IsUnknown() && !state.FromServiceCloudEdgeName.IsNull() && !state.FromServiceCloudEdgeName.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.FromServiceCloudEdgeName.ValueString(), state.FromServiceCloudEdgeName.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить from_service_cloud_edge_name", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.FromServiceCloudEdgeScope.IsNull() && !plan.FromServiceCloudEdgeScope.IsUnknown() && !state.FromServiceCloudEdgeScope.IsNull() && !state.FromServiceCloudEdgeScope.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.FromServiceCloudEdgeScope.ValueString(), state.FromServiceCloudEdgeScope.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить from_service_cloud_edge_scope", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.FromServiceCloudOrgName.IsNull() && !plan.FromServiceCloudOrgName.IsUnknown() && !state.FromServiceCloudOrgName.IsNull() && !state.FromServiceCloudOrgName.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.FromServiceCloudOrgName.ValueString(), state.FromServiceCloudOrgName.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить from_service_cloud_org_name", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.FromServiceCloudVdcName.IsNull() && !plan.FromServiceCloudVdcName.IsUnknown() && !state.FromServiceCloudVdcName.IsNull() && !state.FromServiceCloudVdcName.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.FromServiceCloudVdcName.ValueString(), state.FromServiceCloudVdcName.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить from_service_cloud_vdc_name", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.FromServiceCloudVmwareUrl.IsNull() && !plan.FromServiceCloudVmwareUrl.IsUnknown() && !state.FromServiceCloudVmwareUrl.IsNull() && !state.FromServiceCloudVmwareUrl.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.FromServiceCloudVmwareUrl.ValueString(), state.FromServiceCloudVmwareUrl.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить from_service_cloud_vmware_url", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.FromServiceNamespace.IsNull() && !plan.FromServiceNamespace.IsUnknown() && !state.FromServiceNamespace.IsNull() && !state.FromServiceNamespace.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.FromServiceNamespace.ValueString(), state.FromServiceNamespace.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить from_service_namespace", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.FromServiceVdcGroupName.IsNull() && !plan.FromServiceVdcGroupName.IsUnknown() && !state.FromServiceVdcGroupName.IsNull() && !state.FromServiceVdcGroupName.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.FromServiceVdcGroupName.ValueString(), state.FromServiceVdcGroupName.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить from_service_vdc_group_name", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.FromServiceNamespace.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "from_service_namespace is required.")
- return
- }
- if config.FromServiceNamespace.IsUnknown() {
- return
- }
- if config.InternalAddrAccess.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "internal_addr_access is required.")
- return
- }
- if config.InternalAddrAccess.IsUnknown() {
- return
- }
- if config.IpSpaceName.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "ip_space_name is required.")
- return
- }
- if config.IpSpaceName.IsUnknown() {
- return
- }
- if config.ServiceUid.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "service_uid is required.")
- return
- }
- if config.ServiceUid.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 140: resources_core.FormatString(config.ServiceUid),
- 141: resources_core.FormatBool(config.DnatCreate),
- 142: resources_core.FormatString(config.InternalPortAccess),
- 143: resources_core.FormatBool(config.SnatCreate),
- 144: resources_core.FormatString(config.InternalAddrAccess),
- 324: resources_core.FormatString(config.FromServiceNamespace),
- 325: resources_core.FormatString(config.FromServiceCloudEdgeName),
- 326: resources_core.FormatString(config.FromServiceCloudVdcName),
- 327: resources_core.FormatString(config.FromServiceCloudOrgName),
- 328: resources_core.FormatString(config.FromServiceCloudVmwareUrl),
- 336: resources_core.FormatString(config.IpSpaceName),
- 488: resources_core.FormatString(config.ResourceRealm),
- 624: resources_core.FormatString(config.FromServiceCloudEdgeScope),
- 626: resources_core.FormatString(config.FromServiceVdcGroupName),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 25, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *VcexternalipResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data VcexternalipModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.FromServiceNamespace.IsNull() || data.FromServiceNamespace.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "from_service_namespace is required.")
- return
- }
- if data.InternalAddrAccess.IsNull() || data.InternalAddrAccess.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "internal_addr_access is required.")
- return
- }
- if data.IpSpaceName.IsNull() || data.IpSpaceName.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "ip_space_name is required.")
- return
- }
- if data.ServiceUid.IsNull() || data.ServiceUid.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "service_uid is required.")
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 25, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 140: resources_core.FormatString(data.ServiceUid),
- 141: resources_core.FormatBool(data.DnatCreate),
- 142: resources_core.FormatString(data.InternalPortAccess),
- 143: resources_core.FormatBool(data.SnatCreate),
- 144: resources_core.FormatString(data.InternalAddrAccess),
- 324: resources_core.FormatString(data.FromServiceNamespace),
- 325: resources_core.FormatString(data.FromServiceCloudEdgeName),
- 326: resources_core.FormatString(data.FromServiceCloudVdcName),
- 327: resources_core.FormatString(data.FromServiceCloudOrgName),
- 328: resources_core.FormatString(data.FromServiceCloudVmwareUrl),
- 336: resources_core.FormatString(data.IpSpaceName),
- 488: resources_core.FormatString(data.ResourceRealm),
- 624: resources_core.FormatString(data.FromServiceCloudEdgeScope),
- 626: resources_core.FormatString(data.FromServiceVdcGroupName),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 25, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 25, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "dnatCreate", Field: "DnatCreate", Type: "bool"},
- {Code: "fromServiceCloudEdgeName", Field: "FromServiceCloudEdgeName", Type: "string"},
- {Code: "fromServiceCloudEdgeScope", Field: "FromServiceCloudEdgeScope", Type: "string"},
- {Code: "fromServiceCloudOrgName", Field: "FromServiceCloudOrgName", Type: "string"},
- {Code: "fromServiceCloudVdcName", Field: "FromServiceCloudVdcName", Type: "string"},
- {Code: "fromServiceCloudVmwareUrl", Field: "FromServiceCloudVmwareUrl", Type: "string"},
- {Code: "fromServiceNamespace", Field: "FromServiceNamespace", Type: "string"},
- {Code: "fromServiceVdcGroupName", Field: "FromServiceVdcGroupName", Type: "string"},
- {Code: "internalAddrAccess", Field: "InternalAddrAccess", Type: "string"},
- {Code: "internalPortAccess", Field: "InternalPortAccess", Type: "string"},
- {Code: "ipSpaceName", Field: "IpSpaceName", Type: "string"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "serviceUid", Field: "ServiceUid", Type: "string"},
- {Code: "snatCreate", Field: "SnatCreate", Type: "bool"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcexternalipResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state VcexternalipModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 25, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "dnatCreate", Field: "DnatCreate", Type: "bool"},
- {Code: "fromServiceCloudEdgeName", Field: "FromServiceCloudEdgeName", Type: "string"},
- {Code: "fromServiceCloudEdgeScope", Field: "FromServiceCloudEdgeScope", Type: "string"},
- {Code: "fromServiceCloudOrgName", Field: "FromServiceCloudOrgName", Type: "string"},
- {Code: "fromServiceCloudVdcName", Field: "FromServiceCloudVdcName", Type: "string"},
- {Code: "fromServiceCloudVmwareUrl", Field: "FromServiceCloudVmwareUrl", Type: "string"},
- {Code: "fromServiceNamespace", Field: "FromServiceNamespace", Type: "string"},
- {Code: "fromServiceVdcGroupName", Field: "FromServiceVdcGroupName", Type: "string"},
- {Code: "internalAddrAccess", Field: "InternalAddrAccess", Type: "string"},
- {Code: "internalPortAccess", Field: "InternalPortAccess", Type: "string"},
- {Code: "ipSpaceName", Field: "IpSpaceName", Type: "string"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "serviceUid", Field: "ServiceUid", Type: "string"},
- {Code: "snatCreate", Field: "SnatCreate", Type: "bool"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *VcexternalipResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan VcexternalipModel
- var state VcexternalipModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.ServiceUid.IsNull() != state.ServiceUid.IsNull() || plan.ServiceUid.IsUnknown() != state.ServiceUid.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ServiceUid.IsNull() && !plan.ServiceUid.IsUnknown() && !state.ServiceUid.IsNull() && !state.ServiceUid.IsUnknown() {
- if !strings.EqualFold(plan.ServiceUid.ValueString(), state.ServiceUid.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.IpSpaceName.IsNull() != state.IpSpaceName.IsNull() || plan.IpSpaceName.IsUnknown() != state.IpSpaceName.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.IpSpaceName.IsNull() && !plan.IpSpaceName.IsUnknown() && !state.IpSpaceName.IsNull() && !state.IpSpaceName.IsUnknown() {
- if !strings.EqualFold(plan.IpSpaceName.ValueString(), state.IpSpaceName.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.DnatCreate.IsNull() != state.DnatCreate.IsNull() || plan.DnatCreate.IsUnknown() != state.DnatCreate.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.DnatCreate.IsNull() && !plan.DnatCreate.IsUnknown() && !state.DnatCreate.IsNull() && !state.DnatCreate.IsUnknown() {
- if plan.DnatCreate.ValueBool() != state.DnatCreate.ValueBool() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.SnatCreate.IsNull() != state.SnatCreate.IsNull() || plan.SnatCreate.IsUnknown() != state.SnatCreate.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.SnatCreate.IsNull() && !plan.SnatCreate.IsUnknown() && !state.SnatCreate.IsNull() && !state.SnatCreate.IsUnknown() {
- if plan.SnatCreate.ValueBool() != state.SnatCreate.ValueBool() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.InternalPortAccess.IsNull() != state.InternalPortAccess.IsNull() || plan.InternalPortAccess.IsUnknown() != state.InternalPortAccess.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.InternalPortAccess.IsNull() && !plan.InternalPortAccess.IsUnknown() && !state.InternalPortAccess.IsNull() && !state.InternalPortAccess.IsUnknown() {
- if !strings.EqualFold(plan.InternalPortAccess.ValueString(), state.InternalPortAccess.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.InternalAddrAccess.IsNull() != state.InternalAddrAccess.IsNull() || plan.InternalAddrAccess.IsUnknown() != state.InternalAddrAccess.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.InternalAddrAccess.IsNull() && !plan.InternalAddrAccess.IsUnknown() && !state.InternalAddrAccess.IsNull() && !state.InternalAddrAccess.IsUnknown() {
- if !strings.EqualFold(plan.InternalAddrAccess.ValueString(), state.InternalAddrAccess.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 627: resources_core.FormatString(plan.ServiceUid),
- 628: resources_core.FormatString(plan.IpSpaceName),
- 629: resources_core.FormatBool(plan.DnatCreate),
- 630: resources_core.FormatBool(plan.SnatCreate),
- 631: resources_core.FormatString(plan.InternalPortAccess),
- 632: resources_core.FormatString(plan.InternalAddrAccess),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 25, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "dnatCreate", Field: "DnatCreate", Type: "bool"},
- {Code: "fromServiceCloudEdgeName", Field: "FromServiceCloudEdgeName", Type: "string"},
- {Code: "fromServiceCloudEdgeScope", Field: "FromServiceCloudEdgeScope", Type: "string"},
- {Code: "fromServiceCloudOrgName", Field: "FromServiceCloudOrgName", Type: "string"},
- {Code: "fromServiceCloudVdcName", Field: "FromServiceCloudVdcName", Type: "string"},
- {Code: "fromServiceCloudVmwareUrl", Field: "FromServiceCloudVmwareUrl", Type: "string"},
- {Code: "fromServiceNamespace", Field: "FromServiceNamespace", Type: "string"},
- {Code: "fromServiceVdcGroupName", Field: "FromServiceVdcGroupName", Type: "string"},
- {Code: "internalAddrAccess", Field: "InternalAddrAccess", Type: "string"},
- {Code: "internalPortAccess", Field: "InternalPortAccess", Type: "string"},
- {Code: "ipSpaceName", Field: "IpSpaceName", Type: "string"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "serviceUid", Field: "ServiceUid", Type: "string"},
- {Code: "snatCreate", Field: "SnatCreate", Type: "bool"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcexternalipResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state VcexternalipModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "delete"
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *VcexternalipResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *VcexternalipResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/26_vapp_resource.go b/provider/internal/resources_gen/26_vapp_resource.go
deleted file mode 100644
index e210b7f..0000000
--- a/provider/internal/resources_gen/26_vapp_resource.go
+++ /dev/null
@@ -1,571 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: vapp
-// Service ID: 26
-
-var _ resource.Resource = &VappResource{}
-var _ resource.ResourceWithModifyPlan = &VappResource{}
-var _ resource.ResourceWithImportState = &VappResource{}
-
-type VappResource struct {
- client *core.UniversalClient
-}
-
-type VappModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- NsxtUid types.String `tfsdk:"nsxt_uid"`
- VappName types.String `tfsdk:"vapp_name"`
- VdcUid types.String `tfsdk:"vdc_uid"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewVappResource() resource.Resource {
- return &VappResource{}
-}
-
-func (r *VappResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_vapp"
-}
-
-func (r *VappResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "nsxt_uid": schema.StringAttribute{Optional: true, Computed: true, MarkdownDescription: "UUID Услуги `Сетевой шлюз периметра (Edge)` Не изменяется после создания."},
- "vapp_name": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("9pv2jybu"), MarkdownDescription: "Уникальное в рамках организации Не изменяется после создания."},
- "vdc_uid": schema.StringAttribute{Optional: true, Computed: true, MarkdownDescription: "UUID Услуги `Виртуальный датацентр (vDC)` Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *VappResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *VappModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *VappModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan VappModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- // FIX(uuid-case): resolve ref_svc params НЕ делаем в ModifyPlan.
- // Terraform правило: plan ОБЯЗАН равняться config для user-provided атрибутов.
- // Resolve (displayName → UUID или uppercase → lowercase) нужен только для
- // API-вызова в Create/Update. Делать его здесь = менять plan = ошибка
- // "Provider produced invalid plan: planned value does not match config value".
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.NsxtUid.IsNull() && !plan.NsxtUid.IsUnknown() && !state.NsxtUid.IsNull() && !state.NsxtUid.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.NsxtUid.ValueString(), state.NsxtUid.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить nsxt_uid", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.VappName.IsNull() && !plan.VappName.IsUnknown() && !state.VappName.IsNull() && !state.VappName.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.VappName.ValueString(), state.VappName.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить vapp_name", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.VdcUid.IsNull() && !plan.VdcUid.IsUnknown() && !state.VdcUid.IsNull() && !state.VdcUid.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.VdcUid.ValueString(), state.VdcUid.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить vdc_uid", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.NsxtUid.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "nsxt_uid is required.")
- return
- }
- if config.NsxtUid.IsUnknown() {
- return
- }
- if config.VdcUid.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "vdc_uid is required.")
- return
- }
- if config.VdcUid.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- if !config.NsxtUid.IsNull() && !config.NsxtUid.IsUnknown() {
- resolvedNsxtUid, err := r.client.ResolveRefSvcParamValue(ctx, 22, config.NsxtUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve nsxt_uid", err.Error())
- } else if resolvedNsxtUid != "" && resolvedNsxtUid != config.NsxtUid.ValueString() {
- config.NsxtUid = types.StringValue(resolvedNsxtUid)
- }
- }
- if !config.VdcUid.IsNull() && !config.VdcUid.IsUnknown() {
- resolvedVdcUid, err := r.client.ResolveRefSvcParamValue(ctx, 21, config.VdcUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vdc_uid", err.Error())
- } else if resolvedVdcUid != "" && resolvedVdcUid != config.VdcUid.ValueString() {
- config.VdcUid = types.StringValue(resolvedVdcUid)
- }
- }
- params := map[int]string{
- 190: resources_core.FormatString(config.NsxtUid),
- 191: resources_core.FormatString(config.VappName),
- 623: resources_core.FormatString(config.VdcUid),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 26, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *VappResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data VappModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.NsxtUid.IsNull() || data.NsxtUid.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "nsxt_uid is required.")
- return
- }
- if data.VdcUid.IsNull() || data.VdcUid.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "vdc_uid is required.")
- return
- }
- // ══════════════════════════════════════════════════════════════════════════
- // ПРАВИЛО TERRAFORM (официальная документация):
- // «If an attribute value is configured, it is NEVER valid to change that
- // value in the plan.» — то есть plan ОБЯЗАН равняться config (= тому что
- // написал пользователь). Менять plan запрещено на уровне фреймворка.
- //
- // ПРОБЛЕМА: API нашего облака возвращает UUID в нижнем регистре.
- // Пользователь пишет: vapp_uid = "6214BA32-..." (верхний или смешанный).
- // После apply API вернул: "6214ba32-..." → state != plan → Terraform кричит:
- // «Provider produced inconsistent result after apply».
- //
- // РЕШЕНИЕ: корректировать STATE под PLAN, а не наоборот.
- // Шаг 1 (здесь): сохраняем оригинальное значение из plan ДО того как
- // ResolveRefSvcParamValue переведёт UUID в нижний регистр (нужен для API).
- // Шаг 2 (ниже, после RefreshResourceState): восстанавливаем оригинальный
- // регистр в state через strings.EqualFold (сравниваем без учёта регистра).
- // ══════════════════════════════════════════════════════════════════════════
- originalNsxtUid := data.NsxtUid
- // ══════════════════════════════════════════════════════════════════════════
- // ПРАВИЛО TERRAFORM (официальная документация):
- // «If an attribute value is configured, it is NEVER valid to change that
- // value in the plan.» — то есть plan ОБЯЗАН равняться config (= тому что
- // написал пользователь). Менять plan запрещено на уровне фреймворка.
- //
- // ПРОБЛЕМА: API нашего облака возвращает UUID в нижнем регистре.
- // Пользователь пишет: vapp_uid = "6214BA32-..." (верхний или смешанный).
- // После apply API вернул: "6214ba32-..." → state != plan → Terraform кричит:
- // «Provider produced inconsistent result after apply».
- //
- // РЕШЕНИЕ: корректировать STATE под PLAN, а не наоборот.
- // Шаг 1 (здесь): сохраняем оригинальное значение из plan ДО того как
- // ResolveRefSvcParamValue переведёт UUID в нижний регистр (нужен для API).
- // Шаг 2 (ниже, после RefreshResourceState): восстанавливаем оригинальный
- // регистр в state через strings.EqualFold (сравниваем без учёта регистра).
- // ══════════════════════════════════════════════════════════════════════════
- originalVdcUid := data.VdcUid
- if !data.NsxtUid.IsNull() && !data.NsxtUid.IsUnknown() {
- resolvedNsxtUid, err := r.client.ResolveRefSvcParamValue(ctx, 22, data.NsxtUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if resolvedNsxtUid != "" && resolvedNsxtUid != data.NsxtUid.ValueString() {
- data.NsxtUid = types.StringValue(resolvedNsxtUid)
- }
- }
- if !data.VdcUid.IsNull() && !data.VdcUid.IsUnknown() {
- resolvedVdcUid, err := r.client.ResolveRefSvcParamValue(ctx, 21, data.VdcUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if resolvedVdcUid != "" && resolvedVdcUid != data.VdcUid.ValueString() {
- data.VdcUid = types.StringValue(resolvedVdcUid)
- }
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 26, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 190: resources_core.FormatString(data.NsxtUid),
- 191: resources_core.FormatString(data.VappName),
- 623: resources_core.FormatString(data.VdcUid),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 26, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 26, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "nsxtUid", Field: "NsxtUid", Type: "string"},
- {Code: "vappName", Field: "VappName", Type: "string"},
- {Code: "vdcUid", Field: "VdcUid", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !state.NsxtUid.IsNull() && !state.NsxtUid.IsUnknown() {
- resolvedNsxtUid, err := r.client.ResolveRefSvcParamValue(ctx, 22, state.NsxtUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve nsxt_uid", err.Error())
- } else if resolvedNsxtUid != "" && resolvedNsxtUid != state.NsxtUid.ValueString() {
- state.NsxtUid = types.StringValue(resolvedNsxtUid)
- }
- }
- if !state.VdcUid.IsNull() && !state.VdcUid.IsUnknown() {
- resolvedVdcUid, err := r.client.ResolveRefSvcParamValue(ctx, 21, state.VdcUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vdc_uid", err.Error())
- } else if resolvedVdcUid != "" && resolvedVdcUid != state.VdcUid.ValueString() {
- state.VdcUid = types.StringValue(resolvedVdcUid)
- }
- }
- // Restore user-provided casing в state (Create).
- // EqualFold = «совпадают ли значения без учёта регистра?»
- // Если да — значит API вернул «туже» строку, только в другом регистре.
- // Заменяем state на original (то что было в plan/config пользователя).
- // Итог: plan=="6214BA32-..." и state=="6214BA32-..." → нет diff → нет taint.
- if !originalNsxtUid.IsNull() && !originalNsxtUid.IsUnknown() && !state.NsxtUid.IsNull() && !state.NsxtUid.IsUnknown() {
- if strings.EqualFold(state.NsxtUid.ValueString(), originalNsxtUid.ValueString()) {
- state.NsxtUid = originalNsxtUid
- }
- }
- if !originalVdcUid.IsNull() && !originalVdcUid.IsUnknown() && !state.VdcUid.IsNull() && !state.VdcUid.IsUnknown() {
- if strings.EqualFold(state.VdcUid.ValueString(), originalVdcUid.ValueString()) {
- state.VdcUid = originalVdcUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VappResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state VappModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 26, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "nsxtUid", Field: "NsxtUid", Type: "string"},
- {Code: "vappName", Field: "VappName", Type: "string"},
- {Code: "vdcUid", Field: "VdcUid", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !newState.NsxtUid.IsNull() && !newState.NsxtUid.IsUnknown() {
- resolvedNsxtUid, err := r.client.ResolveRefSvcParamValue(ctx, 22, newState.NsxtUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve nsxt_uid", err.Error())
- } else if resolvedNsxtUid != "" && resolvedNsxtUid != newState.NsxtUid.ValueString() {
- newState.NsxtUid = types.StringValue(resolvedNsxtUid)
- }
- }
- if !newState.VdcUid.IsNull() && !newState.VdcUid.IsUnknown() {
- resolvedVdcUid, err := r.client.ResolveRefSvcParamValue(ctx, 21, newState.VdcUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vdc_uid", err.Error())
- } else if resolvedVdcUid != "" && resolvedVdcUid != newState.VdcUid.ValueString() {
- newState.VdcUid = types.StringValue(resolvedVdcUid)
- }
- }
- // Restore user-provided casing в state (Read).
- // При чтении у нас нет plan — но предыдущий state уже хранит значение
- // в регистре пользователя (после первого Create оно было восстановлено).
- // Берём prior state (переменная state) как эталон регистра.
- // Если API вернул то же UUID только строчными буквами — восстанавливаем.
- if !state.NsxtUid.IsNull() && !state.NsxtUid.IsUnknown() && !newState.NsxtUid.IsNull() && !newState.NsxtUid.IsUnknown() {
- if strings.EqualFold(newState.NsxtUid.ValueString(), state.NsxtUid.ValueString()) {
- newState.NsxtUid = state.NsxtUid
- }
- }
- if !state.VdcUid.IsNull() && !state.VdcUid.IsUnknown() && !newState.VdcUid.IsNull() && !newState.VdcUid.IsUnknown() {
- if strings.EqualFold(newState.VdcUid.ValueString(), state.VdcUid.ValueString()) {
- newState.VdcUid = state.VdcUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *VappResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan VappModel
- var state VappModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{}
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 26, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "nsxtUid", Field: "NsxtUid", Type: "string"},
- {Code: "vappName", Field: "VappName", Type: "string"},
- {Code: "vdcUid", Field: "VdcUid", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !state.NsxtUid.IsNull() && !state.NsxtUid.IsUnknown() {
- resolvedNsxtUid, err := r.client.ResolveRefSvcParamValue(ctx, 22, state.NsxtUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve nsxt_uid", err.Error())
- } else if resolvedNsxtUid != "" && resolvedNsxtUid != state.NsxtUid.ValueString() {
- state.NsxtUid = types.StringValue(resolvedNsxtUid)
- }
- }
- if !state.VdcUid.IsNull() && !state.VdcUid.IsUnknown() {
- resolvedVdcUid, err := r.client.ResolveRefSvcParamValue(ctx, 21, state.VdcUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vdc_uid", err.Error())
- } else if resolvedVdcUid != "" && resolvedVdcUid != state.VdcUid.ValueString() {
- state.VdcUid = types.StringValue(resolvedVdcUid)
- }
- }
- // Restore user-provided casing в state (Update).
- // После API-вызова modify state содержит значения в lower-case от API.
- // Plan == config == то что написал пользователь (регистр неизменён).
- // EqualFold: если UUID совпадает без учёта регистра — берём из plan.
- if !plan.NsxtUid.IsNull() && !plan.NsxtUid.IsUnknown() && !state.NsxtUid.IsNull() && !state.NsxtUid.IsUnknown() {
- if strings.EqualFold(state.NsxtUid.ValueString(), plan.NsxtUid.ValueString()) {
- state.NsxtUid = plan.NsxtUid
- }
- }
- if !plan.VdcUid.IsNull() && !plan.VdcUid.IsUnknown() && !state.VdcUid.IsNull() && !state.VdcUid.IsUnknown() {
- if strings.EqualFold(state.VdcUid.ValueString(), plan.VdcUid.ValueString()) {
- state.VdcUid = plan.VdcUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VappResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state VappModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *VappResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *VappResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/27_vc_vm_v2_resource.go b/provider/internal/resources_gen/27_vc_vm_v2_resource.go
deleted file mode 100644
index 6a05554..0000000
--- a/provider/internal/resources_gen/27_vc_vm_v2_resource.go
+++ /dev/null
@@ -1,350 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: vc_vm_v2
-// Service ID: 27
-
-var _ resource.Resource = &VcVmV2Resource{}
-var _ resource.ResourceWithModifyPlan = &VcVmV2Resource{}
-var _ resource.ResourceWithImportState = &VcVmV2Resource{}
-
-type VcVmV2Resource struct {
- client *core.UniversalClient
-}
-
-type VcVmV2Model struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- ServerListJson types.String `tfsdk:"server_list_json"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewVcVmV2Resource() resource.Resource {
- return &VcVmV2Resource{}
-}
-
-func (r *VcVmV2Resource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_vc_vm_v2"
-}
-
-func (r *VcVmV2Resource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "server_list_json": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[{}]"), MarkdownDescription: "Необходимо изменить vappUid и ipSpaceName
Пример конфигурации взять по ссылке ниже
Объект серверов вида [{}] (Map(Object))
Более подробнее смотреть в README.md (https://gitea.mgmt.nubes.ru/cloudServices/vcVmV2)", PlanModifiers: []planmodifier.String{resources_core.JsonNormalize()}},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *VcVmV2Resource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *VcVmV2Model
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *VcVmV2Model
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan VcVmV2Model
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 301: resources_core.FormatString(config.ServerListJson),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 27, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *VcVmV2Resource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data VcVmV2Model
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 27, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 301: resources_core.FormatString(data.ServerListJson),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 27, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 27, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "serverListJson", Field: "ServerListJson", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcVmV2Resource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state VcVmV2Model
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 27, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "serverListJson", Field: "ServerListJson", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *VcVmV2Resource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan VcVmV2Model
- var state VcVmV2Model
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.ServerListJson.IsNull() != state.ServerListJson.IsNull() || plan.ServerListJson.IsUnknown() != state.ServerListJson.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ServerListJson.IsNull() && !plan.ServerListJson.IsUnknown() && !state.ServerListJson.IsNull() && !state.ServerListJson.IsUnknown() {
- if !strings.EqualFold(plan.ServerListJson.ValueString(), state.ServerListJson.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 302: resources_core.FormatString(plan.ServerListJson),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 27, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "serverListJson", Field: "ServerListJson", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcVmV2Resource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state VcVmV2Model
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *VcVmV2Resource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *VcVmV2Resource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/28_vc_vm_v3_resource.go b/provider/internal/resources_gen/28_vc_vm_v3_resource.go
deleted file mode 100644
index 61fe97c..0000000
--- a/provider/internal/resources_gen/28_vc_vm_v3_resource.go
+++ /dev/null
@@ -1,697 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: vc_vm_v3
-// Service ID: 28
-
-var _ resource.Resource = &VcVmV3Resource{}
-var _ resource.ResourceWithModifyPlan = &VcVmV3Resource{}
-var _ resource.ResourceWithImportState = &VcVmV3Resource{}
-
-type VcVmV3Resource struct {
- client *core.UniversalClient
-}
-
-type VcVmV3Model struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- // --- Redeploy support (ARCHITECTURE.md) ---
- // git_revision: при изменении вызывает redeploy вместо modify.
- // Опциональное поле — если не задано, modify работает как обычно.
- GitRevision types.String `tfsdk:"git_revision"`
- AccessIpList types.String `tfsdk:"access_ip_list"`
- AccessPortList types.String `tfsdk:"access_port_list"`
- CloudInit types.String `tfsdk:"cloud_init"`
- ImageVm types.String `tfsdk:"image_vm"`
- IpSpaceName types.String `tfsdk:"ip_space_name"`
- UserLogin types.String `tfsdk:"user_login"`
- UserPublicKey types.String `tfsdk:"user_public_key"`
- VappUid types.String `tfsdk:"vapp_uid"`
- VmCpu types.Int64 `tfsdk:"vm_cpu"`
- VmDisk types.Int64 `tfsdk:"vm_disk"`
- VmName types.String `tfsdk:"vm_name"`
- VmRam types.Int64 `tfsdk:"vm_ram"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewVcVmV3Resource() resource.Resource {
- return &VcVmV3Resource{}
-}
-
-func (r *VcVmV3Resource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_vc_vm_v3"
-}
-
-func (r *VcVmV3Resource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "access_ip_list": schema.StringAttribute{Optional: true, Computed: true, MarkdownDescription: "Формат массива
Каким адресам будет предоставлен доступ до вм
Требует выделенного внешнего IP
Если ничего не передано, то выставлено ["0.0.0.0/0"]", PlanModifiers: []planmodifier.String{resources_core.JsonNormalize()}},
- "access_port_list": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[\"22\"]"), MarkdownDescription: "По каким портам открыть доступ к ВМ.
Порты 22, 10050 проставляются автоматически
Пока доступно:
22 - SSH,
80 - HTTP,
443 - HTTPS,
10050 - ZABBIX"},
- "cloud_init": schema.StringAttribute{Optional: true, MarkdownDescription: "Можно передать создание дополнительных пользователей.
На текущий момент не реализовано выполнения в cloud-init, установки пакетов, выполнения команд и записи файлов. Не изменяется после создания."},
- "image_vm": schema.StringAttribute{Required: true, MarkdownDescription: "Не изменяется после создания."},
- "ip_space_name": schema.StringAttribute{Required: true},
- "user_login": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("myuser"), MarkdownDescription: "Учётка SSH Не изменяется после создания."},
- "user_public_key": schema.StringAttribute{Required: true, MarkdownDescription: "Публичная часть SSH-Ключа для пользователя Не изменяется после создания."},
- "vapp_uid": schema.StringAttribute{Optional: true, Computed: true, MarkdownDescription: "UI display_name for service_id=26 (mapped to UUID in core) Не изменяется после создания."},
- "vm_cpu": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "шт"},
- "vm_disk": schema.Int64Attribute{Optional: true, MarkdownDescription: "Основной диск у vm зависит от образа (см. документацию)
Если необходимо дополнительное место для vm, введите колличество Gb в эту форму"},
- "vm_name": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("web01"), MarkdownDescription: "Не изменяется после создания."},
- "vm_ram": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Gb"},
- // --- Redeploy support (ARCHITECTURE.md) ---
- // При изменении git_revision вызывается redeploy вместо modify.
- // Если не задано — modify работает без изменений.
- "git_revision": schema.StringAttribute{Optional: true, MarkdownDescription: "Git revision (commit hash/tag). Changing this triggers redeploy instead of modify."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *VcVmV3Resource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *VcVmV3Model
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *VcVmV3Model
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan VcVmV3Model
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- // FIX(uuid-case): resolve ref_svc params НЕ делаем в ModifyPlan.
- // Terraform правило: plan ОБЯЗАН равняться config для user-provided атрибутов.
- // Resolve (displayName → UUID или uppercase → lowercase) нужен только для
- // API-вызова в Create/Update. Делать его здесь = менять plan = ошибка
- // "Provider produced invalid plan: planned value does not match config value".
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.CloudInit.IsNull() && !plan.CloudInit.IsUnknown() && !state.CloudInit.IsNull() && !state.CloudInit.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.CloudInit.ValueString(), state.CloudInit.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить cloud_init", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ImageVm.IsNull() && !plan.ImageVm.IsUnknown() && !state.ImageVm.IsNull() && !state.ImageVm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ImageVm.ValueString(), state.ImageVm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить image_vm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.UserLogin.IsNull() && !plan.UserLogin.IsUnknown() && !state.UserLogin.IsNull() && !state.UserLogin.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.UserLogin.ValueString(), state.UserLogin.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить user_login", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.UserPublicKey.IsNull() && !plan.UserPublicKey.IsUnknown() && !state.UserPublicKey.IsNull() && !state.UserPublicKey.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.UserPublicKey.ValueString(), state.UserPublicKey.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить user_public_key", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.VappUid.IsNull() && !plan.VappUid.IsUnknown() && !state.VappUid.IsNull() && !state.VappUid.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.VappUid.ValueString(), state.VappUid.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить vapp_uid", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.VmName.IsNull() && !plan.VmName.IsUnknown() && !state.VmName.IsNull() && !state.VmName.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.VmName.ValueString(), state.VmName.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить vm_name", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.ImageVm.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "image_vm is required.")
- return
- }
- if config.ImageVm.IsUnknown() {
- return
- }
- if config.IpSpaceName.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "ip_space_name is required.")
- return
- }
- if config.IpSpaceName.IsUnknown() {
- return
- }
- if config.UserPublicKey.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "user_public_key is required.")
- return
- }
- if config.UserPublicKey.IsUnknown() {
- return
- }
- if config.VappUid.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "vapp_uid is required.")
- return
- }
- if config.VappUid.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- if !config.VappUid.IsNull() && !config.VappUid.IsUnknown() {
- resolvedVappUid, err := r.client.ResolveRefSvcParamValue(ctx, 26, config.VappUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vapp_uid", err.Error())
- } else if resolvedVappUid != "" && resolvedVappUid != config.VappUid.ValueString() {
- config.VappUid = types.StringValue(resolvedVappUid)
- }
- }
- params := map[int]string{
- 407: resources_core.FormatString(config.VappUid),
- 408: resources_core.FormatString(config.VmName),
- 409: resources_core.FormatInt64(config.VmCpu),
- 410: resources_core.FormatInt64(config.VmRam),
- 411: resources_core.FormatInt64(config.VmDisk),
- 412: resources_core.FormatString(config.IpSpaceName),
- 413: resources_core.FormatString(config.AccessIpList),
- 414: resources_core.FormatString(config.ImageVm),
- 415: resources_core.FormatString(config.CloudInit),
- 416: resources_core.FormatString(config.UserLogin),
- 417: resources_core.FormatString(config.UserPublicKey),
- 448: resources_core.FormatString(config.AccessPortList),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 28, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *VcVmV3Resource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data VcVmV3Model
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.ImageVm.IsNull() || data.ImageVm.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "image_vm is required.")
- return
- }
- if data.IpSpaceName.IsNull() || data.IpSpaceName.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "ip_space_name is required.")
- return
- }
- if data.UserPublicKey.IsNull() || data.UserPublicKey.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "user_public_key is required.")
- return
- }
- if data.VappUid.IsNull() || data.VappUid.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "vapp_uid is required.")
- return
- }
- // ══════════════════════════════════════════════════════════════════════════
- // ПРАВИЛО TERRAFORM (официальная документация):
- // «If an attribute value is configured, it is NEVER valid to change that
- // value in the plan.» — то есть plan ОБЯЗАН равняться config (= тому что
- // написал пользователь). Менять plan запрещено на уровне фреймворка.
- //
- // ПРОБЛЕМА: API нашего облака возвращает UUID в нижнем регистре.
- // Пользователь пишет: vapp_uid = "6214BA32-..." (верхний или смешанный).
- // После apply API вернул: "6214ba32-..." → state != plan → Terraform кричит:
- // «Provider produced inconsistent result after apply».
- //
- // РЕШЕНИЕ: корректировать STATE под PLAN, а не наоборот.
- // Шаг 1 (здесь): сохраняем оригинальное значение из plan ДО того как
- // ResolveRefSvcParamValue переведёт UUID в нижний регистр (нужен для API).
- // Шаг 2 (ниже, после RefreshResourceState): восстанавливаем оригинальный
- // регистр в state через strings.EqualFold (сравниваем без учёта регистра).
- // ══════════════════════════════════════════════════════════════════════════
- originalVappUid := data.VappUid
- if !data.VappUid.IsNull() && !data.VappUid.IsUnknown() {
- resolvedVappUid, err := r.client.ResolveRefSvcParamValue(ctx, 26, data.VappUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if resolvedVappUid != "" && resolvedVappUid != data.VappUid.ValueString() {
- data.VappUid = types.StringValue(resolvedVappUid)
- }
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 28, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 407: resources_core.FormatString(data.VappUid),
- 408: resources_core.FormatString(data.VmName),
- 409: resources_core.FormatInt64(data.VmCpu),
- 410: resources_core.FormatInt64(data.VmRam),
- 411: resources_core.FormatInt64(data.VmDisk),
- 412: resources_core.FormatString(data.IpSpaceName),
- 413: resources_core.FormatString(data.AccessIpList),
- 414: resources_core.FormatString(data.ImageVm),
- 415: resources_core.FormatString(data.CloudInit),
- 416: resources_core.FormatString(data.UserLogin),
- 417: resources_core.FormatString(data.UserPublicKey),
- 448: resources_core.FormatString(data.AccessPortList),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 28, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 28, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessIpList", Field: "AccessIpList", Type: "string"},
- {Code: "accessPortList", Field: "AccessPortList", Type: "string"},
- {Code: "cloudInit", Field: "CloudInit", Type: "string"},
- {Code: "imageVm", Field: "ImageVm", Type: "string"},
- {Code: "ipSpaceName", Field: "IpSpaceName", Type: "string"},
- {Code: "userLogin", Field: "UserLogin", Type: "string"},
- {Code: "userPublicKey", Field: "UserPublicKey", Type: "string"},
- {Code: "vappUid", Field: "VappUid", Type: "string"},
- {Code: "vmCpu", Field: "VmCpu", Type: "int64"},
- {Code: "vmDisk", Field: "VmDisk", Type: "int64"},
- {Code: "vmName", Field: "VmName", Type: "string"},
- {Code: "vmRam", Field: "VmRam", Type: "int64"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !state.VappUid.IsNull() && !state.VappUid.IsUnknown() {
- resolvedVappUid, err := r.client.ResolveRefSvcParamValue(ctx, 26, state.VappUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vapp_uid", err.Error())
- } else if resolvedVappUid != "" && resolvedVappUid != state.VappUid.ValueString() {
- state.VappUid = types.StringValue(resolvedVappUid)
- }
- }
- // Restore user-provided casing в state (Create).
- // EqualFold = «совпадают ли значения без учёта регистра?»
- // Если да — значит API вернул «туже» строку, только в другом регистре.
- // Заменяем state на original (то что было в plan/config пользователя).
- // Итог: plan=="6214BA32-..." и state=="6214BA32-..." → нет diff → нет taint.
- if !originalVappUid.IsNull() && !originalVappUid.IsUnknown() && !state.VappUid.IsNull() && !state.VappUid.IsUnknown() {
- if strings.EqualFold(state.VappUid.ValueString(), originalVappUid.ValueString()) {
- state.VappUid = originalVappUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcVmV3Resource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state VcVmV3Model
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 28, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessIpList", Field: "AccessIpList", Type: "string"},
- {Code: "accessPortList", Field: "AccessPortList", Type: "string"},
- {Code: "cloudInit", Field: "CloudInit", Type: "string"},
- {Code: "imageVm", Field: "ImageVm", Type: "string"},
- {Code: "ipSpaceName", Field: "IpSpaceName", Type: "string"},
- {Code: "userLogin", Field: "UserLogin", Type: "string"},
- {Code: "userPublicKey", Field: "UserPublicKey", Type: "string"},
- {Code: "vappUid", Field: "VappUid", Type: "string"},
- {Code: "vmCpu", Field: "VmCpu", Type: "int64"},
- {Code: "vmDisk", Field: "VmDisk", Type: "int64"},
- {Code: "vmName", Field: "VmName", Type: "string"},
- {Code: "vmRam", Field: "VmRam", Type: "int64"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !newState.VappUid.IsNull() && !newState.VappUid.IsUnknown() {
- resolvedVappUid, err := r.client.ResolveRefSvcParamValue(ctx, 26, newState.VappUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vapp_uid", err.Error())
- } else if resolvedVappUid != "" && resolvedVappUid != newState.VappUid.ValueString() {
- newState.VappUid = types.StringValue(resolvedVappUid)
- }
- }
- // Restore user-provided casing в state (Read).
- // При чтении у нас нет plan — но предыдущий state уже хранит значение
- // в регистре пользователя (после первого Create оно было восстановлено).
- // Берём prior state (переменная state) как эталон регистра.
- // Если API вернул то же UUID только строчными буквами — восстанавливаем.
- if !state.VappUid.IsNull() && !state.VappUid.IsUnknown() && !newState.VappUid.IsNull() && !newState.VappUid.IsUnknown() {
- if strings.EqualFold(newState.VappUid.ValueString(), state.VappUid.ValueString()) {
- newState.VappUid = state.VappUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *VcVmV3Resource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan VcVmV3Model
- var state VcVmV3Model
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.VmCpu.IsNull() != state.VmCpu.IsNull() || plan.VmCpu.IsUnknown() != state.VmCpu.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.VmCpu.IsNull() && !plan.VmCpu.IsUnknown() && !state.VmCpu.IsNull() && !state.VmCpu.IsUnknown() {
- if plan.VmCpu.ValueInt64() != state.VmCpu.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.VmRam.IsNull() != state.VmRam.IsNull() || plan.VmRam.IsUnknown() != state.VmRam.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.VmRam.IsNull() && !plan.VmRam.IsUnknown() && !state.VmRam.IsNull() && !state.VmRam.IsUnknown() {
- if plan.VmRam.ValueInt64() != state.VmRam.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.VmDisk.IsNull() != state.VmDisk.IsNull() || plan.VmDisk.IsUnknown() != state.VmDisk.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.VmDisk.IsNull() && !plan.VmDisk.IsUnknown() && !state.VmDisk.IsNull() && !state.VmDisk.IsUnknown() {
- if plan.VmDisk.ValueInt64() != state.VmDisk.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.IpSpaceName.IsNull() != state.IpSpaceName.IsNull() || plan.IpSpaceName.IsUnknown() != state.IpSpaceName.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.IpSpaceName.IsNull() && !plan.IpSpaceName.IsUnknown() && !state.IpSpaceName.IsNull() && !state.IpSpaceName.IsUnknown() {
- if !strings.EqualFold(plan.IpSpaceName.ValueString(), state.IpSpaceName.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.AccessIpList.IsNull() != state.AccessIpList.IsNull() || plan.AccessIpList.IsUnknown() != state.AccessIpList.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.AccessIpList.IsNull() && !plan.AccessIpList.IsUnknown() && !state.AccessIpList.IsNull() && !state.AccessIpList.IsUnknown() {
- if !strings.EqualFold(plan.AccessIpList.ValueString(), state.AccessIpList.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.AccessPortList.IsNull() != state.AccessPortList.IsNull() || plan.AccessPortList.IsUnknown() != state.AccessPortList.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.AccessPortList.IsNull() && !plan.AccessPortList.IsUnknown() && !state.AccessPortList.IsNull() && !state.AccessPortList.IsUnknown() {
- if !strings.EqualFold(plan.AccessPortList.ValueString(), state.AccessPortList.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
- // --- Redeploy support (ARCHITECTURE.md) ---
- // Проверяем изменился ли git_revision.
- // Если да — вызываем redeploy вместо modify.
- // git_revision = "" (не задано) → обычный modify.
- redeployRequested := false
- if !plan.GitRevision.IsNull() && !plan.GitRevision.IsUnknown() {
- if state.GitRevision.IsNull() || state.GitRevision.IsUnknown() || plan.GitRevision.ValueString() != state.GitRevision.ValueString() {
- redeployRequested = true
- }
- }
-
- if !hasServiceParamChanges && !redeployRequested {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- // --- Redeploy support (ARCHITECTURE.md) ---
- if redeployRequested {
- // Вызываем redeploy — пустой params (операция не требует CFS-параметров)
- if err := r.client.RunRedeployOperation(ctx, instanceID.ValueString(), operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- } else {
- params := map[int]string{
- 493: resources_core.FormatInt64(plan.VmCpu),
- 494: resources_core.FormatInt64(plan.VmRam),
- 495: resources_core.FormatInt64(plan.VmDisk),
- 496: resources_core.FormatString(plan.IpSpaceName),
- 497: resources_core.FormatString(plan.AccessIpList),
- 498: resources_core.FormatString(plan.AccessPortList),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 28, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessIpList", Field: "AccessIpList", Type: "string"},
- {Code: "accessPortList", Field: "AccessPortList", Type: "string"},
- {Code: "cloudInit", Field: "CloudInit", Type: "string"},
- {Code: "imageVm", Field: "ImageVm", Type: "string"},
- {Code: "ipSpaceName", Field: "IpSpaceName", Type: "string"},
- {Code: "userLogin", Field: "UserLogin", Type: "string"},
- {Code: "userPublicKey", Field: "UserPublicKey", Type: "string"},
- {Code: "vappUid", Field: "VappUid", Type: "string"},
- {Code: "vmCpu", Field: "VmCpu", Type: "int64"},
- {Code: "vmDisk", Field: "VmDisk", Type: "int64"},
- {Code: "vmName", Field: "VmName", Type: "string"},
- {Code: "vmRam", Field: "VmRam", Type: "int64"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !state.VappUid.IsNull() && !state.VappUid.IsUnknown() {
- resolvedVappUid, err := r.client.ResolveRefSvcParamValue(ctx, 26, state.VappUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vapp_uid", err.Error())
- } else if resolvedVappUid != "" && resolvedVappUid != state.VappUid.ValueString() {
- state.VappUid = types.StringValue(resolvedVappUid)
- }
- }
- // Restore user-provided casing в state (Update).
- // После API-вызова modify state содержит значения в lower-case от API.
- // Plan == config == то что написал пользователь (регистр неизменён).
- // EqualFold: если UUID совпадает без учёта регистра — берём из plan.
- if !plan.VappUid.IsNull() && !plan.VappUid.IsUnknown() && !state.VappUid.IsNull() && !state.VappUid.IsUnknown() {
- if strings.EqualFold(state.VappUid.ValueString(), plan.VappUid.ValueString()) {
- state.VappUid = plan.VappUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcVmV3Resource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state VcVmV3Model
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *VcVmV3Resource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *VcVmV3Resource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/29_vc_vdc_group_resource.go b/provider/internal/resources_gen/29_vc_vdc_group_resource.go
deleted file mode 100644
index 41864ef..0000000
--- a/provider/internal/resources_gen/29_vc_vdc_group_resource.go
+++ /dev/null
@@ -1,449 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: vc_vdc_group
-// Service ID: 29
-
-var _ resource.Resource = &VcVdcGroupResource{}
-var _ resource.ResourceWithModifyPlan = &VcVdcGroupResource{}
-var _ resource.ResourceWithImportState = &VcVdcGroupResource{}
-
-type VcVdcGroupResource struct {
- client *core.UniversalClient
-}
-
-type VcVdcGroupModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- VdcUid types.String `tfsdk:"vdc_uid"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewVcVdcGroupResource() resource.Resource {
- return &VcVdcGroupResource{}
-}
-
-func (r *VcVdcGroupResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_vc_vdc_group"
-}
-
-func (r *VcVdcGroupResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "vdc_uid": schema.StringAttribute{Optional: true, Computed: true, MarkdownDescription: "UI display_name for service_id=21 (mapped to UUID in core) Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *VcVdcGroupResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *VcVdcGroupModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *VcVdcGroupModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan VcVdcGroupModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- // FIX(uuid-case): resolve ref_svc params НЕ делаем в ModifyPlan.
- // Terraform правило: plan ОБЯЗАН равняться config для user-provided атрибутов.
- // Resolve (displayName → UUID или uppercase → lowercase) нужен только для
- // API-вызова в Create/Update. Делать его здесь = менять plan = ошибка
- // "Provider produced invalid plan: planned value does not match config value".
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.VdcUid.IsNull() && !plan.VdcUid.IsUnknown() && !state.VdcUid.IsNull() && !state.VdcUid.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.VdcUid.ValueString(), state.VdcUid.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить vdc_uid", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.VdcUid.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "vdc_uid is required.")
- return
- }
- if config.VdcUid.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- if !config.VdcUid.IsNull() && !config.VdcUid.IsUnknown() {
- resolvedVdcUid, err := r.client.ResolveRefSvcParamValue(ctx, 21, config.VdcUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vdc_uid", err.Error())
- } else if resolvedVdcUid != "" && resolvedVdcUid != config.VdcUid.ValueString() {
- config.VdcUid = types.StringValue(resolvedVdcUid)
- }
- }
- params := map[int]string{
- 618: resources_core.FormatString(config.VdcUid),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 29, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *VcVdcGroupResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data VcVdcGroupModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.VdcUid.IsNull() || data.VdcUid.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "vdc_uid is required.")
- return
- }
- // ══════════════════════════════════════════════════════════════════════════
- // ПРАВИЛО TERRAFORM (официальная документация):
- // «If an attribute value is configured, it is NEVER valid to change that
- // value in the plan.» — то есть plan ОБЯЗАН равняться config (= тому что
- // написал пользователь). Менять plan запрещено на уровне фреймворка.
- //
- // ПРОБЛЕМА: API нашего облака возвращает UUID в нижнем регистре.
- // Пользователь пишет: vapp_uid = "6214BA32-..." (верхний или смешанный).
- // После apply API вернул: "6214ba32-..." → state != plan → Terraform кричит:
- // «Provider produced inconsistent result after apply».
- //
- // РЕШЕНИЕ: корректировать STATE под PLAN, а не наоборот.
- // Шаг 1 (здесь): сохраняем оригинальное значение из plan ДО того как
- // ResolveRefSvcParamValue переведёт UUID в нижний регистр (нужен для API).
- // Шаг 2 (ниже, после RefreshResourceState): восстанавливаем оригинальный
- // регистр в state через strings.EqualFold (сравниваем без учёта регистра).
- // ══════════════════════════════════════════════════════════════════════════
- originalVdcUid := data.VdcUid
- if !data.VdcUid.IsNull() && !data.VdcUid.IsUnknown() {
- resolvedVdcUid, err := r.client.ResolveRefSvcParamValue(ctx, 21, data.VdcUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if resolvedVdcUid != "" && resolvedVdcUid != data.VdcUid.ValueString() {
- data.VdcUid = types.StringValue(resolvedVdcUid)
- }
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 29, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 618: resources_core.FormatString(data.VdcUid),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 29, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 29, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "vdcUid", Field: "VdcUid", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !state.VdcUid.IsNull() && !state.VdcUid.IsUnknown() {
- resolvedVdcUid, err := r.client.ResolveRefSvcParamValue(ctx, 21, state.VdcUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vdc_uid", err.Error())
- } else if resolvedVdcUid != "" && resolvedVdcUid != state.VdcUid.ValueString() {
- state.VdcUid = types.StringValue(resolvedVdcUid)
- }
- }
- // Restore user-provided casing в state (Create).
- // EqualFold = «совпадают ли значения без учёта регистра?»
- // Если да — значит API вернул «туже» строку, только в другом регистре.
- // Заменяем state на original (то что было в plan/config пользователя).
- // Итог: plan=="6214BA32-..." и state=="6214BA32-..." → нет diff → нет taint.
- if !originalVdcUid.IsNull() && !originalVdcUid.IsUnknown() && !state.VdcUid.IsNull() && !state.VdcUid.IsUnknown() {
- if strings.EqualFold(state.VdcUid.ValueString(), originalVdcUid.ValueString()) {
- state.VdcUid = originalVdcUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcVdcGroupResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state VcVdcGroupModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 29, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "vdcUid", Field: "VdcUid", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !newState.VdcUid.IsNull() && !newState.VdcUid.IsUnknown() {
- resolvedVdcUid, err := r.client.ResolveRefSvcParamValue(ctx, 21, newState.VdcUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vdc_uid", err.Error())
- } else if resolvedVdcUid != "" && resolvedVdcUid != newState.VdcUid.ValueString() {
- newState.VdcUid = types.StringValue(resolvedVdcUid)
- }
- }
- // Restore user-provided casing в state (Read).
- // При чтении у нас нет plan — но предыдущий state уже хранит значение
- // в регистре пользователя (после первого Create оно было восстановлено).
- // Берём prior state (переменная state) как эталон регистра.
- // Если API вернул то же UUID только строчными буквами — восстанавливаем.
- if !state.VdcUid.IsNull() && !state.VdcUid.IsUnknown() && !newState.VdcUid.IsNull() && !newState.VdcUid.IsUnknown() {
- if strings.EqualFold(newState.VdcUid.ValueString(), state.VdcUid.ValueString()) {
- newState.VdcUid = state.VdcUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *VcVdcGroupResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan VcVdcGroupModel
- var state VcVdcGroupModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{}
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 29, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "vdcUid", Field: "VdcUid", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !state.VdcUid.IsNull() && !state.VdcUid.IsUnknown() {
- resolvedVdcUid, err := r.client.ResolveRefSvcParamValue(ctx, 21, state.VdcUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vdc_uid", err.Error())
- } else if resolvedVdcUid != "" && resolvedVdcUid != state.VdcUid.ValueString() {
- state.VdcUid = types.StringValue(resolvedVdcUid)
- }
- }
- // Restore user-provided casing в state (Update).
- // После API-вызова modify state содержит значения в lower-case от API.
- // Plan == config == то что написал пользователь (регистр неизменён).
- // EqualFold: если UUID совпадает без учёта регистра — берём из plan.
- if !plan.VdcUid.IsNull() && !plan.VdcUid.IsUnknown() && !state.VdcUid.IsNull() && !state.VdcUid.IsUnknown() {
- if strings.EqualFold(state.VdcUid.ValueString(), plan.VdcUid.ValueString()) {
- state.VdcUid = plan.VdcUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcVdcGroupResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state VcVdcGroupModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "delete"
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *VcVdcGroupResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *VcVdcGroupResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/29_vc_vdc_group_vdc_resource.go b/provider/internal/resources_gen/29_vc_vdc_group_vdc_resource.go
deleted file mode 100644
index 3e3e8ef..0000000
--- a/provider/internal/resources_gen/29_vc_vdc_group_vdc_resource.go
+++ /dev/null
@@ -1,326 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: vc_vdc_group
-// Subresource: vdc
-
-var _ resource.Resource = &VcVdcGroupVdcResource{}
-
-// VcVdcGroupVdcResource manages a subresource via operations.
-type VcVdcGroupVdcResource struct {
- client *core.UniversalClient
-}
-
-type VcVdcGroupVdcModel struct {
- ID types.String `tfsdk:"id"`
- VcVdcGroupID types.String `tfsdk:"vc_vdc_group_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
-}
-
-func NewVcVdcGroupVdcResource() resource.Resource {
- return &VcVdcGroupVdcResource{}
-}
-
-func (r *VcVdcGroupVdcResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_vc_vdc_group_vdc"
-}
-
-func (r *VcVdcGroupVdcResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "vc_vdc_group_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *VcVdcGroupVdcResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan VcVdcGroupVdcModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceUID := strings.TrimSpace(plan.VcVdcGroupID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{}
- identityCodes := []string{}
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("vdc", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "vdc", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "vdc", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "vdc", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "vdc", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *VcVdcGroupVdcResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state VcVdcGroupVdcModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VcVdcGroupVdcResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan VcVdcGroupVdcModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "" == "" {
- var state VcVdcGroupVdcModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.VcVdcGroupID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- idParams := map[string]string{}
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "vdc", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *VcVdcGroupVdcResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state VcVdcGroupVdcModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.VcVdcGroupID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{}
- identityCodes := []string{}
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("vdc", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *VcVdcGroupVdcResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/2_template_resource.go b/provider/internal/resources_gen/2_template_resource.go
deleted file mode 100644
index 9c63c5f..0000000
--- a/provider/internal/resources_gen/2_template_resource.go
+++ /dev/null
@@ -1,397 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "fmt"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: template
-// Service ID: 2
-
-var _ resource.Resource = &TemplateResource{}
-var _ resource.ResourceWithModifyPlan = &TemplateResource{}
-var _ resource.ResourceWithImportState = &TemplateResource{}
-
-type TemplateResource struct {
- client *core.UniversalClient
-}
-
-// TemplateAccessConfigurationModel — вложенная модель для map-fixed параметра accessConfiguration.
-type TemplateAccessConfigurationModel struct {
- SlaveAccessList types.String `tfsdk:"slave_access_list" json:"slaveAccessList"`
- Type types.String `tfsdk:"type" json:"type"`
- Domain types.String `tfsdk:"domain" json:"domain"`
- MasterIpSpace types.String `tfsdk:"master_ip_space" json:"masterIpSpace"`
- MasterAccessList types.String `tfsdk:"master_access_list" json:"masterAccessList"`
- SlaveIpSpace types.String `tfsdk:"slave_ip_space" json:"slaveIpSpace"`
-}
-
-// TemplateClusterConfigurationModel — вложенная модель для map-fixed параметра clusterConfiguration.
-type TemplateClusterConfigurationModel struct {
- Disk types.Int64 `tfsdk:"disk" json:"disk"`
- Memory types.Int64 `tfsdk:"memory" json:"memory"`
- Replicas types.Int64 `tfsdk:"replicas" json:"replicas"`
- Cpu types.Int64 `tfsdk:"cpu" json:"cpu"`
-}
-
-// TemplateStartupConfigurationModel — вложенная модель для map-fixed параметра startupConfiguration.
-type TemplateStartupConfigurationModel struct {
- ResourceRealm types.String `tfsdk:"resource_realm" json:"resourceRealm"`
-}
-
-type TemplateModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- AccessConfiguration *TemplateAccessConfigurationModel `tfsdk:"access_configuration"`
- ClusterConfiguration *TemplateClusterConfigurationModel `tfsdk:"cluster_configuration"`
- StartupConfiguration *TemplateStartupConfigurationModel `tfsdk:"startup_configuration"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewTemplateResource() resource.Resource {
- return &TemplateResource{}
-}
-
-func (r *TemplateResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_template"
-}
-
-func (r *TemplateResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "access_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "slave_access_list": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[]")},
- "type": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("ingress")},
- "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("abracadabra-mgonny3n")},
- "master_ip_space": schema.StringAttribute{Required: true},
- "master_access_list": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[]")},
- "slave_ip_space": schema.StringAttribute{Required: true},
- }},
- "cluster_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(5)},
- "memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(128)},
- "replicas": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1)},
- "cpu": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(100)},
- }},
- "startup_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "resource_realm": schema.StringAttribute{Required: true},
- }},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *TemplateResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *TemplateModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *TemplateModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan TemplateModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 813: resources_core.BuildJSON(map[string]string{"disk": fmt.Sprintf("%d", config.ClusterConfiguration.Disk.ValueInt64()), "memory": fmt.Sprintf("%d", config.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", config.ClusterConfiguration.Replicas.ValueInt64()), "cpu": fmt.Sprintf("%d", config.ClusterConfiguration.Cpu.ValueInt64())}),
- 814: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", config.StartupConfiguration.ResourceRealm.ValueString())}),
- 815: resources_core.BuildJSON(map[string]string{"slaveAccessList": config.AccessConfiguration.SlaveAccessList.ValueString(), "type": fmt.Sprintf("\"%s\"", config.AccessConfiguration.Type.ValueString()), "domain": fmt.Sprintf("\"%s\"", config.AccessConfiguration.Domain.ValueString()), "masterIpSpace": fmt.Sprintf("\"%s\"", config.AccessConfiguration.MasterIpSpace.ValueString()), "masterAccessList": config.AccessConfiguration.MasterAccessList.ValueString(), "slaveIpSpace": fmt.Sprintf("\"%s\"", config.AccessConfiguration.SlaveIpSpace.ValueString())}),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 2, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *TemplateResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data TemplateModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 2, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 813: resources_core.BuildJSON(map[string]string{"disk": fmt.Sprintf("%d", data.ClusterConfiguration.Disk.ValueInt64()), "memory": fmt.Sprintf("%d", data.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", data.ClusterConfiguration.Replicas.ValueInt64()), "cpu": fmt.Sprintf("%d", data.ClusterConfiguration.Cpu.ValueInt64())}),
- 814: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", data.StartupConfiguration.ResourceRealm.ValueString())}),
- 815: resources_core.BuildJSON(map[string]string{"slaveAccessList": data.AccessConfiguration.SlaveAccessList.ValueString(), "type": fmt.Sprintf("\"%s\"", data.AccessConfiguration.Type.ValueString()), "domain": fmt.Sprintf("\"%s\"", data.AccessConfiguration.Domain.ValueString()), "masterIpSpace": fmt.Sprintf("\"%s\"", data.AccessConfiguration.MasterIpSpace.ValueString()), "masterAccessList": data.AccessConfiguration.MasterAccessList.ValueString(), "slaveIpSpace": fmt.Sprintf("\"%s\"", data.AccessConfiguration.SlaveIpSpace.ValueString())}),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 2, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 2, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *TemplateResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state TemplateModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 2, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *TemplateResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan TemplateModel
- var state TemplateModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 816: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", plan.ClusterConfiguration.Cpu.ValueInt64()), "disk": fmt.Sprintf("%d", plan.ClusterConfiguration.Disk.ValueInt64()), "memory": fmt.Sprintf("%d", plan.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", plan.ClusterConfiguration.Replicas.ValueInt64())}),
- 817: resources_core.BuildJSON(map[string]string{"masterAccessList": plan.AccessConfiguration.MasterAccessList.ValueString(), "slaveIpSpace": fmt.Sprintf("\"%s\"", plan.AccessConfiguration.SlaveIpSpace.ValueString()), "slaveAccessList": plan.AccessConfiguration.SlaveAccessList.ValueString(), "type": fmt.Sprintf("\"%s\"", plan.AccessConfiguration.Type.ValueString()), "domain": fmt.Sprintf("\"%s\"", plan.AccessConfiguration.Domain.ValueString()), "masterIpSpace": fmt.Sprintf("\"%s\"", plan.AccessConfiguration.MasterIpSpace.ValueString())}),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 2, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *TemplateResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state TemplateModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *TemplateResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *TemplateResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/32_vmpostgre_resource.go b/provider/internal/resources_gen/32_vmpostgre_resource.go
deleted file mode 100644
index 5d39c90..0000000
--- a/provider/internal/resources_gen/32_vmpostgre_resource.go
+++ /dev/null
@@ -1,514 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: vmpostgre
-// Service ID: 32
-
-var _ resource.Resource = &VmpostgreResource{}
-var _ resource.ResourceWithModifyPlan = &VmpostgreResource{}
-var _ resource.ResourceWithImportState = &VmpostgreResource{}
-
-type VmpostgreResource struct {
- client *core.UniversalClient
-}
-
-type VmpostgreModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- UserDb types.String `tfsdk:"user_db"`
- UserLogin types.String `tfsdk:"user_login"`
- UserPassword types.String `tfsdk:"user_password"`
- VmUid types.String `tfsdk:"vm_uid"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewVmpostgreResource() resource.Resource {
- return &VmpostgreResource{}
-}
-
-func (r *VmpostgreResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_vmpostgre"
-}
-
-func (r *VmpostgreResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "resource_realm": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("sandbox.nubes.ru"), MarkdownDescription: "Платформа для развертывания Не изменяется после создания."},
- "user_db": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("servicedb"), MarkdownDescription: "Наименование Базы данных
Не изменяется после создания."},
- "user_login": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("serviceuser"), MarkdownDescription: "Пользователь базы данных
Не изменяется после создания."},
- "user_password": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("fj29gm48fm!d374mc9"), MarkdownDescription: "Пароль от доступа к Базе данных
Не изменяется после создания."},
- "vm_uid": schema.StringAttribute{Optional: true, Computed: true, MarkdownDescription: "InstanceUid ВМ. ВМ должна быть создана
Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *VmpostgreResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *VmpostgreModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *VmpostgreModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan VmpostgreModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- // FIX(uuid-case): resolve ref_svc params НЕ делаем в ModifyPlan.
- // Terraform правило: plan ОБЯЗАН равняться config для user-provided атрибутов.
- // Resolve (displayName → UUID или uppercase → lowercase) нужен только для
- // API-вызова в Create/Update. Делать его здесь = менять plan = ошибка
- // "Provider produced invalid plan: planned value does not match config value".
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.UserDb.IsNull() && !plan.UserDb.IsUnknown() && !state.UserDb.IsNull() && !state.UserDb.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.UserDb.ValueString(), state.UserDb.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить user_db", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.UserLogin.IsNull() && !plan.UserLogin.IsUnknown() && !state.UserLogin.IsNull() && !state.UserLogin.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.UserLogin.ValueString(), state.UserLogin.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить user_login", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.UserPassword.IsNull() && !plan.UserPassword.IsUnknown() && !state.UserPassword.IsNull() && !state.UserPassword.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.UserPassword.ValueString(), state.UserPassword.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить user_password", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.VmUid.IsNull() && !plan.VmUid.IsUnknown() && !state.VmUid.IsNull() && !state.VmUid.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.VmUid.ValueString(), state.VmUid.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить vm_uid", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.VmUid.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "vm_uid is required.")
- return
- }
- if config.VmUid.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- if !config.VmUid.IsNull() && !config.VmUid.IsUnknown() {
- resolvedVmUid, err := r.client.ResolveRefSvcParamValue(ctx, 23, config.VmUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vm_uid", err.Error())
- } else if resolvedVmUid != "" && resolvedVmUid != config.VmUid.ValueString() {
- config.VmUid = types.StringValue(resolvedVmUid)
- }
- }
- params := map[int]string{
- 45: resources_core.FormatString(config.VmUid),
- 46: resources_core.FormatString(config.UserDb),
- 47: resources_core.FormatString(config.UserLogin),
- 48: resources_core.FormatString(config.UserPassword),
- 278: resources_core.FormatString(config.ResourceRealm),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 32, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *VmpostgreResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data VmpostgreModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.VmUid.IsNull() || data.VmUid.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "vm_uid is required.")
- return
- }
- // ══════════════════════════════════════════════════════════════════════════
- // ПРАВИЛО TERRAFORM (официальная документация):
- // «If an attribute value is configured, it is NEVER valid to change that
- // value in the plan.» — то есть plan ОБЯЗАН равняться config (= тому что
- // написал пользователь). Менять plan запрещено на уровне фреймворка.
- //
- // ПРОБЛЕМА: API нашего облака возвращает UUID в нижнем регистре.
- // Пользователь пишет: vapp_uid = "6214BA32-..." (верхний или смешанный).
- // После apply API вернул: "6214ba32-..." → state != plan → Terraform кричит:
- // «Provider produced inconsistent result after apply».
- //
- // РЕШЕНИЕ: корректировать STATE под PLAN, а не наоборот.
- // Шаг 1 (здесь): сохраняем оригинальное значение из plan ДО того как
- // ResolveRefSvcParamValue переведёт UUID в нижний регистр (нужен для API).
- // Шаг 2 (ниже, после RefreshResourceState): восстанавливаем оригинальный
- // регистр в state через strings.EqualFold (сравниваем без учёта регистра).
- // ══════════════════════════════════════════════════════════════════════════
- originalVmUid := data.VmUid
- if !data.VmUid.IsNull() && !data.VmUid.IsUnknown() {
- resolvedVmUid, err := r.client.ResolveRefSvcParamValue(ctx, 23, data.VmUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if resolvedVmUid != "" && resolvedVmUid != data.VmUid.ValueString() {
- data.VmUid = types.StringValue(resolvedVmUid)
- }
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 32, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 45: resources_core.FormatString(data.VmUid),
- 46: resources_core.FormatString(data.UserDb),
- 47: resources_core.FormatString(data.UserLogin),
- 48: resources_core.FormatString(data.UserPassword),
- 278: resources_core.FormatString(data.ResourceRealm),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 32, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 32, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "userDb", Field: "UserDb", Type: "string"},
- {Code: "userLogin", Field: "UserLogin", Type: "string"},
- {Code: "userPassword", Field: "UserPassword", Type: "string"},
- {Code: "vmUid", Field: "VmUid", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !state.VmUid.IsNull() && !state.VmUid.IsUnknown() {
- resolvedVmUid, err := r.client.ResolveRefSvcParamValue(ctx, 23, state.VmUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vm_uid", err.Error())
- } else if resolvedVmUid != "" && resolvedVmUid != state.VmUid.ValueString() {
- state.VmUid = types.StringValue(resolvedVmUid)
- }
- }
- // Restore user-provided casing в state (Create).
- // EqualFold = «совпадают ли значения без учёта регистра?»
- // Если да — значит API вернул «туже» строку, только в другом регистре.
- // Заменяем state на original (то что было в plan/config пользователя).
- // Итог: plan=="6214BA32-..." и state=="6214BA32-..." → нет diff → нет taint.
- if !originalVmUid.IsNull() && !originalVmUid.IsUnknown() && !state.VmUid.IsNull() && !state.VmUid.IsUnknown() {
- if strings.EqualFold(state.VmUid.ValueString(), originalVmUid.ValueString()) {
- state.VmUid = originalVmUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VmpostgreResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state VmpostgreModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 32, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "userDb", Field: "UserDb", Type: "string"},
- {Code: "userLogin", Field: "UserLogin", Type: "string"},
- {Code: "userPassword", Field: "UserPassword", Type: "string"},
- {Code: "vmUid", Field: "VmUid", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !newState.VmUid.IsNull() && !newState.VmUid.IsUnknown() {
- resolvedVmUid, err := r.client.ResolveRefSvcParamValue(ctx, 23, newState.VmUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vm_uid", err.Error())
- } else if resolvedVmUid != "" && resolvedVmUid != newState.VmUid.ValueString() {
- newState.VmUid = types.StringValue(resolvedVmUid)
- }
- }
- // Restore user-provided casing в state (Read).
- // При чтении у нас нет plan — но предыдущий state уже хранит значение
- // в регистре пользователя (после первого Create оно было восстановлено).
- // Берём prior state (переменная state) как эталон регистра.
- // Если API вернул то же UUID только строчными буквами — восстанавливаем.
- if !state.VmUid.IsNull() && !state.VmUid.IsUnknown() && !newState.VmUid.IsNull() && !newState.VmUid.IsUnknown() {
- if strings.EqualFold(newState.VmUid.ValueString(), state.VmUid.ValueString()) {
- newState.VmUid = state.VmUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *VmpostgreResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan VmpostgreModel
- var state VmpostgreModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{}
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 32, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- {Code: "userDb", Field: "UserDb", Type: "string"},
- {Code: "userLogin", Field: "UserLogin", Type: "string"},
- {Code: "userPassword", Field: "UserPassword", Type: "string"},
- {Code: "vmUid", Field: "VmUid", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !state.VmUid.IsNull() && !state.VmUid.IsUnknown() {
- resolvedVmUid, err := r.client.ResolveRefSvcParamValue(ctx, 23, state.VmUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve vm_uid", err.Error())
- } else if resolvedVmUid != "" && resolvedVmUid != state.VmUid.ValueString() {
- state.VmUid = types.StringValue(resolvedVmUid)
- }
- }
- // Restore user-provided casing в state (Update).
- // После API-вызова modify state содержит значения в lower-case от API.
- // Plan == config == то что написал пользователь (регистр неизменён).
- // EqualFold: если UUID совпадает без учёта регистра — берём из plan.
- if !plan.VmUid.IsNull() && !plan.VmUid.IsUnknown() && !state.VmUid.IsNull() && !state.VmUid.IsUnknown() {
- if strings.EqualFold(state.VmUid.ValueString(), plan.VmUid.ValueString()) {
- state.VmUid = plan.VmUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *VmpostgreResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state VmpostgreModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "delete"
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *VmpostgreResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *VmpostgreResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/50_nextcloud_backup_resource.go b/provider/internal/resources_gen/50_nextcloud_backup_resource.go
deleted file mode 100644
index feb1f0e..0000000
--- a/provider/internal/resources_gen/50_nextcloud_backup_resource.go
+++ /dev/null
@@ -1,344 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: nextcloud
-// Subresource: backup
-
-var _ resource.Resource = &NextcloudBackupResource{}
-
-// NextcloudBackupResource manages a subresource via operations.
-type NextcloudBackupResource struct {
- client *core.UniversalClient
-}
-
-type NextcloudBackupModel struct {
- ID types.String `tfsdk:"id"`
- NextcloudID types.String `tfsdk:"nextcloud_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- StartupConfiguration types.String `tfsdk:"startup_configuration"`
-}
-
-func NewNextcloudBackupResource() resource.Resource {
- return &NextcloudBackupResource{}
-}
-
-func (r *NextcloudBackupResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_nextcloud_backup"
-}
-
-func (r *NextcloudBackupResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "nextcloud_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "startup_configuration": schema.StringAttribute{Required: true, MarkdownDescription: "Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *NextcloudBackupResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan NextcloudBackupModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.StartupConfiguration.IsNull() || plan.StartupConfiguration.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "startup_configuration is required.")
- return
- }
-
- instanceUID := strings.TrimSpace(plan.NextcloudID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{
- "startupConfiguration": resources_core.FormatString(plan.StartupConfiguration),
- }
- identityCodes := []string{
- "startupConfiguration",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("backup", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "backup", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "startupConfiguration": resources_core.FormatString(plan.StartupConfiguration),
- })
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_backup", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_backup", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "backup", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "backup", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "backup", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *NextcloudBackupResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state NextcloudBackupModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *NextcloudBackupResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan NextcloudBackupModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "" == "" {
- var state NextcloudBackupModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.NextcloudID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- idParams := map[string]string{
- "startupConfiguration": resources_core.FormatString(plan.StartupConfiguration),
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "backup", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *NextcloudBackupResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state NextcloudBackupModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.NextcloudID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{
- "startupConfiguration": resources_core.FormatString(state.StartupConfiguration),
- }
- identityCodes := []string{
- "startupConfiguration",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("backup", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *NextcloudBackupResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/50_nextcloud_resource.go b/provider/internal/resources_gen/50_nextcloud_resource.go
deleted file mode 100644
index 3e5c608..0000000
--- a/provider/internal/resources_gen/50_nextcloud_resource.go
+++ /dev/null
@@ -1,414 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "fmt"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: nextcloud
-// Service ID: 50
-
-var _ resource.Resource = &NextcloudResource{}
-var _ resource.ResourceWithModifyPlan = &NextcloudResource{}
-var _ resource.ResourceWithImportState = &NextcloudResource{}
-
-type NextcloudResource struct {
- client *core.UniversalClient
-}
-
-// NextcloudAccessConfigurationModel — вложенная модель для map-fixed параметра accessConfiguration.
-type NextcloudAccessConfigurationModel struct {
- Domain types.String `tfsdk:"domain" json:"domain"`
-}
-
-// NextcloudAppConfigurationModel — вложенная модель для map-fixed параметра appConfiguration.
-type NextcloudAppConfigurationModel struct {
- Version types.String `tfsdk:"version" json:"version"`
- DocumentServer types.String `tfsdk:"document_server" json:"documentServer"`
- LogLevel types.String `tfsdk:"log_level" json:"logLevel"`
-}
-
-// NextcloudClusterConfigurationModel — вложенная модель для map-fixed параметра clusterConfiguration.
-type NextcloudClusterConfigurationModel struct {
- Cpu types.Int64 `tfsdk:"cpu" json:"cpu"`
- Memory types.Int64 `tfsdk:"memory" json:"memory"`
- Replicas types.Int64 `tfsdk:"replicas" json:"replicas"`
- Disk types.Int64 `tfsdk:"disk" json:"disk"`
-}
-
-// NextcloudStartupConfigurationModel — вложенная модель для map-fixed параметра startupConfiguration.
-type NextcloudStartupConfigurationModel struct {
- ResourceRealm types.String `tfsdk:"resource_realm" json:"resourceRealm"`
- PsqlEnabled types.Bool `tfsdk:"psql_enabled" json:"psqlEnabled"`
- RedisEnabled types.Bool `tfsdk:"redis_enabled" json:"redisEnabled"`
- PsqlUid types.String `tfsdk:"psql_uid" json:"psqlUid"`
- RedisUid types.String `tfsdk:"redis_uid" json:"redisUid"`
-}
-
-type NextcloudModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- AccessConfiguration *NextcloudAccessConfigurationModel `tfsdk:"access_configuration"`
- AppConfiguration *NextcloudAppConfigurationModel `tfsdk:"app_configuration"`
- ClusterConfiguration *NextcloudClusterConfigurationModel `tfsdk:"cluster_configuration"`
- StartupConfiguration *NextcloudStartupConfigurationModel `tfsdk:"startup_configuration"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewNextcloudResource() resource.Resource {
- return &NextcloudResource{}
-}
-
-func (r *NextcloudResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_nextcloud"
-}
-
-func (r *NextcloudResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "access_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("nextcloud-xcq3u70l"), MarkdownDescription: "Если указан FQDN в формате: `myapp.example.com`, предварительно будет проверяться DNS-запись (А-запись **должна смотреть на IP Ingress кластера ресурсной платформы**)
Если указан в формате `myapp`, DNS-запись будет автоматически создана в служебной DNS-зоне"},
- }},
- "app_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "version": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("33.0.4")},
- "document_server": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("collabora"), MarkdownDescription: "Выбор сервера документов (onlyoffice)/(collabora). onlyoffice пока не доступен
Размер пода collabora:
1.8 ядра. 2Gi ОЗУ"},
- "log_level": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("INFO"), MarkdownDescription: "Включает отображение логов самого nextcloud
Логи уходят в /dev/stdout контейнера
`NONE` отключает логирование"},
- }},
- "cluster_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "cpu": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1000), MarkdownDescription: "Указывается в Milicores
`1000` Mili == `1` Ядро"},
- "memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1024), MarkdownDescription: "Указывается в Megabytes"},
- "replicas": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1)},
- "disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(10), MarkdownDescription: "Указывается в GIGAbytes
На данном диске хранятся данные Nextcloud"},
- }},
- "startup_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Кластер Kubernetes, на котором будет развернут экземпляр"},
- "psql_enabled": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true), MarkdownDescription: "Инстанс обязан быть развёрнут на той же ресурсной платформе, где и будет располагаться Nextcloud"},
- "redis_enabled": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true), MarkdownDescription: "Инстанс обязан быть развёрнут на той же ресурсной платформе, где и будет располагаться Nextcloud"},
- "psql_uid": schema.StringAttribute{Required: true, MarkdownDescription: "Необходимо выбирать, когда выбран параметр `Подключить PostgreSQL из Личного кабинета`"},
- "redis_uid": schema.StringAttribute{Required: true, MarkdownDescription: "Необходимо выбирать, когда выбран параметр `Подключить Redis из Личного кабинета`"},
- }},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *NextcloudResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *NextcloudModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *NextcloudModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan NextcloudModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 1055: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", config.StartupConfiguration.ResourceRealm.ValueString()), "psqlEnabled": fmt.Sprintf("%v", config.StartupConfiguration.PsqlEnabled.ValueBool()), "redisEnabled": fmt.Sprintf("%v", config.StartupConfiguration.RedisEnabled.ValueBool()), "psqlUid": fmt.Sprintf("\"%s\"", config.StartupConfiguration.PsqlUid.ValueString()), "redisUid": fmt.Sprintf("\"%s\"", config.StartupConfiguration.RedisUid.ValueString())}),
- 1056: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", config.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", config.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", config.ClusterConfiguration.Replicas.ValueInt64()), "disk": fmt.Sprintf("%d", config.ClusterConfiguration.Disk.ValueInt64())}),
- 1057: resources_core.BuildJSON(map[string]string{"domain": fmt.Sprintf("\"%s\"", config.AccessConfiguration.Domain.ValueString())}),
- 1058: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", config.AppConfiguration.Version.ValueString()), "documentServer": fmt.Sprintf("\"%s\"", config.AppConfiguration.DocumentServer.ValueString()), "logLevel": fmt.Sprintf("\"%s\"", config.AppConfiguration.LogLevel.ValueString())}),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 50, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *NextcloudResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data NextcloudModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 50, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 1055: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", data.StartupConfiguration.ResourceRealm.ValueString()), "psqlEnabled": fmt.Sprintf("%v", data.StartupConfiguration.PsqlEnabled.ValueBool()), "redisEnabled": fmt.Sprintf("%v", data.StartupConfiguration.RedisEnabled.ValueBool()), "psqlUid": fmt.Sprintf("\"%s\"", data.StartupConfiguration.PsqlUid.ValueString()), "redisUid": fmt.Sprintf("\"%s\"", data.StartupConfiguration.RedisUid.ValueString())}),
- 1056: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", data.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", data.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", data.ClusterConfiguration.Replicas.ValueInt64()), "disk": fmt.Sprintf("%d", data.ClusterConfiguration.Disk.ValueInt64())}),
- 1057: resources_core.BuildJSON(map[string]string{"domain": fmt.Sprintf("\"%s\"", data.AccessConfiguration.Domain.ValueString())}),
- 1058: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", data.AppConfiguration.Version.ValueString()), "documentServer": fmt.Sprintf("\"%s\"", data.AppConfiguration.DocumentServer.ValueString()), "logLevel": fmt.Sprintf("\"%s\"", data.AppConfiguration.LogLevel.ValueString())}),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 50, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 50, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "appConfiguration", Field: "AppConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *NextcloudResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state NextcloudModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 50, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "appConfiguration", Field: "AppConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *NextcloudResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan NextcloudModel
- var state NextcloudModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 1059: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", plan.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", plan.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", plan.ClusterConfiguration.Replicas.ValueInt64()), "disk": fmt.Sprintf("%d", plan.ClusterConfiguration.Disk.ValueInt64())}),
- 1060: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", plan.AppConfiguration.Version.ValueString()), "documentServer": fmt.Sprintf("\"%s\"", plan.AppConfiguration.DocumentServer.ValueString()), "logLevel": fmt.Sprintf("\"%s\"", plan.AppConfiguration.LogLevel.ValueString())}),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 50, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "appConfiguration", Field: "AppConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *NextcloudResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state NextcloudModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *NextcloudResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *NextcloudResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/81_superset_resource.go b/provider/internal/resources_gen/81_superset_resource.go
deleted file mode 100644
index 94602e6..0000000
--- a/provider/internal/resources_gen/81_superset_resource.go
+++ /dev/null
@@ -1,447 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: superset
-// Service ID: 81
-
-var _ resource.Resource = &SupersetResource{}
-var _ resource.ResourceWithModifyPlan = &SupersetResource{}
-var _ resource.ResourceWithImportState = &SupersetResource{}
-
-type SupersetResource struct {
- client *core.UniversalClient
-}
-
-type SupersetModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- Domain types.String `tfsdk:"domain"`
- Emails types.String `tfsdk:"emails"`
- ResourceCPU types.Int64 `tfsdk:"resource_c_p_u"`
- ResourceDisk types.Int64 `tfsdk:"resource_disk"`
- ResourceInstances types.Int64 `tfsdk:"resource_instances"`
- ResourceMemory types.Int64 `tfsdk:"resource_memory"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewSupersetResource() resource.Resource {
- return &SupersetResource{}
-}
-
-func (r *SupersetResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_superset"
-}
-
-func (r *SupersetResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("superset-1"), MarkdownDescription: "Если будет указан FQDN, то происходят проверки DNS на валидность А-записи, или будет добавлено в зону resourceRealm Не изменяется после создания."},
- "emails": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("testuser1"), MarkdownDescription: "Учётная запись, которой будут выданы админские права. В формате email [ну не совсем. Для доменных учетных записей - без доменного суффикса]. Обязана находиться в Keycloak. Можно передавать несколько через пробел Не изменяется после создания."},
- "resource_c_p_u": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(500), MarkdownDescription: "Квота ядра пода (Указывается в mili). 1000 Mili = 1 ядро Не изменяется после создания."},
- "resource_disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Квота диска (Указывается в GIGAbytes) Не изменяется после создания."},
- "resource_instances": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Количество узлов Не изменяется после создания."},
- "resource_memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(512), MarkdownDescription: "Квота памяти пода (Указывается в Megabytes) Не изменяется после создания."},
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Платформа для развертывания Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *SupersetResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *SupersetModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *SupersetModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan SupersetModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.Domain.IsNull() && !plan.Domain.IsUnknown() && !state.Domain.IsNull() && !state.Domain.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.Domain.ValueString(), state.Domain.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить domain", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.Emails.IsNull() && !plan.Emails.IsUnknown() && !state.Emails.IsNull() && !state.Emails.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.Emails.ValueString(), state.Emails.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить emails", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceCPU.IsNull() && !plan.ResourceCPU.IsUnknown() && !state.ResourceCPU.IsNull() && !state.ResourceCPU.IsUnknown() {
- if plan.ResourceCPU.ValueInt64() != state.ResourceCPU.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить resource_c_p_u", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceDisk.IsNull() && !plan.ResourceDisk.IsUnknown() && !state.ResourceDisk.IsNull() && !state.ResourceDisk.IsUnknown() {
- if plan.ResourceDisk.ValueInt64() != state.ResourceDisk.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить resource_disk", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceInstances.IsNull() && !plan.ResourceInstances.IsUnknown() && !state.ResourceInstances.IsNull() && !state.ResourceInstances.IsUnknown() {
- if plan.ResourceInstances.ValueInt64() != state.ResourceInstances.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить resource_instances", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceMemory.IsNull() && !plan.ResourceMemory.IsUnknown() && !state.ResourceMemory.IsNull() && !state.ResourceMemory.IsUnknown() {
- if plan.ResourceMemory.ValueInt64() != state.ResourceMemory.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить resource_memory", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.ResourceRealm.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
- if config.ResourceRealm.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 14: resources_core.FormatString(config.Domain),
- 20: resources_core.FormatString(config.Emails),
- 96: resources_core.FormatInt64(config.ResourceCPU),
- 97: resources_core.FormatInt64(config.ResourceMemory),
- 98: resources_core.FormatInt64(config.ResourceDisk),
- 109: resources_core.FormatString(config.ResourceRealm),
- 227: resources_core.FormatInt64(config.ResourceInstances),
- }
- desiredDomain := ""
- if !config.Domain.IsNull() && !config.Domain.IsUnknown() {
- desiredDomain = config.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 81, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *SupersetResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data SupersetModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.ResourceRealm.IsNull() || data.ResourceRealm.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- if !data.Domain.IsNull() && !data.Domain.IsUnknown() {
- desiredDomain = data.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 81, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 14: resources_core.FormatString(data.Domain),
- 20: resources_core.FormatString(data.Emails),
- 96: resources_core.FormatInt64(data.ResourceCPU),
- 97: resources_core.FormatInt64(data.ResourceMemory),
- 98: resources_core.FormatInt64(data.ResourceDisk),
- 109: resources_core.FormatString(data.ResourceRealm),
- 227: resources_core.FormatInt64(data.ResourceInstances),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 81, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 81, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "emails", Field: "Emails", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *SupersetResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state SupersetModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 81, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "emails", Field: "Emails", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *SupersetResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan SupersetModel
- var state SupersetModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{}
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 81, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "emails", Field: "Emails", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *SupersetResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state SupersetModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "delete"
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *SupersetResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *SupersetResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/82_harbor_resource.go b/provider/internal/resources_gen/82_harbor_resource.go
deleted file mode 100644
index b53b4c3..0000000
--- a/provider/internal/resources_gen/82_harbor_resource.go
+++ /dev/null
@@ -1,482 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: harbor
-// Service ID: 82
-
-var _ resource.Resource = &HarborResource{}
-var _ resource.ResourceWithModifyPlan = &HarborResource{}
-var _ resource.ResourceWithImportState = &HarborResource{}
-
-type HarborResource struct {
- client *core.UniversalClient
-}
-
-type HarborModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- Domain types.String `tfsdk:"domain"`
- ResourceCPU types.Int64 `tfsdk:"resource_c_p_u"`
- ResourceInstances types.Int64 `tfsdk:"resource_instances"`
- ResourceMemory types.Int64 `tfsdk:"resource_memory"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- S3Uid types.String `tfsdk:"s3_uid"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewHarborResource() resource.Resource {
- return &HarborResource{}
-}
-
-func (r *HarborResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_harbor"
-}
-
-func (r *HarborResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("harbor-1"), MarkdownDescription: "Если будет указан FQDN, то происходят проверки DNS на валидность А-записи, или будет добавлено в зону resourceRealm Не изменяется после создания."},
- "resource_c_p_u": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1000), MarkdownDescription: "Квота ядра пода (Указывается в mili). 1000Mili = 1 Ядро"},
- "resource_instances": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Количество узлов"},
- "resource_memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1024), MarkdownDescription: "Квота памяти пода (Указывается в Megabytes)"},
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Платформа для развертывания Не изменяется после создания."},
- "s3_uid": schema.StringAttribute{Optional: true, Computed: true, MarkdownDescription: "UUID экземпляра услуги S3 Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *HarborResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *HarborModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *HarborModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan HarborModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- // FIX(uuid-case): resolve ref_svc params НЕ делаем в ModifyPlan.
- // Terraform правило: plan ОБЯЗАН равняться config для user-provided атрибутов.
- // Resolve (displayName → UUID или uppercase → lowercase) нужен только для
- // API-вызова в Create/Update. Делать его здесь = менять plan = ошибка
- // "Provider produced invalid plan: planned value does not match config value".
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.Domain.IsNull() && !plan.Domain.IsUnknown() && !state.Domain.IsNull() && !state.Domain.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.Domain.ValueString(), state.Domain.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить domain", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.S3Uid.IsNull() && !plan.S3Uid.IsUnknown() && !state.S3Uid.IsNull() && !state.S3Uid.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.S3Uid.ValueString(), state.S3Uid.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить s3_uid", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.ResourceRealm.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
- if config.ResourceRealm.IsUnknown() {
- return
- }
- if config.S3Uid.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "s3_uid is required.")
- return
- }
- if config.S3Uid.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- if !config.S3Uid.IsNull() && !config.S3Uid.IsUnknown() {
- resolvedS3Uid, err := r.client.ResolveRefSvcParamValue(ctx, 12, config.S3Uid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve s3_uid", err.Error())
- } else if resolvedS3Uid != "" && resolvedS3Uid != config.S3Uid.ValueString() {
- config.S3Uid = types.StringValue(resolvedS3Uid)
- }
- }
- params := map[int]string{
- 16: resources_core.FormatString(config.Domain),
- 110: resources_core.FormatString(config.ResourceRealm),
- 228: resources_core.FormatInt64(config.ResourceCPU),
- 229: resources_core.FormatInt64(config.ResourceMemory),
- 230: resources_core.FormatInt64(config.ResourceInstances),
- 231: resources_core.FormatString(config.S3Uid),
- }
- desiredDomain := ""
- if !config.Domain.IsNull() && !config.Domain.IsUnknown() {
- desiredDomain = config.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 82, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *HarborResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data HarborModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.ResourceRealm.IsNull() || data.ResourceRealm.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
- if data.S3Uid.IsNull() || data.S3Uid.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "s3_uid is required.")
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- if !data.Domain.IsNull() && !data.Domain.IsUnknown() {
- desiredDomain = data.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 82, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 16: resources_core.FormatString(data.Domain),
- 110: resources_core.FormatString(data.ResourceRealm),
- 228: resources_core.FormatInt64(data.ResourceCPU),
- 229: resources_core.FormatInt64(data.ResourceMemory),
- 230: resources_core.FormatInt64(data.ResourceInstances),
- 231: resources_core.FormatString(data.S3Uid),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 82, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 82, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- // Restore user-provided casing в state (Create).
- // EqualFold = «совпадают ли значения без учёта регистра?»
- // Если да — значит API вернул «туже» строку, только в другом регистре.
- // Заменяем state на original (то что было в plan/config пользователя).
- // Итог: plan=="6214BA32-..." и state=="6214BA32-..." → нет diff → нет taint.
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *HarborResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state HarborModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 82, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- // Restore user-provided casing в state (Read).
- // При чтении у нас нет plan — но предыдущий state уже хранит значение
- // в регистре пользователя (после первого Create оно было восстановлено).
- // Берём prior state (переменная state) как эталон регистра.
- // Если API вернул то же UUID только строчными буквами — восстанавливаем.
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *HarborResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan HarborModel
- var state HarborModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.ResourceInstances.IsNull() != state.ResourceInstances.IsNull() || plan.ResourceInstances.IsUnknown() != state.ResourceInstances.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceInstances.IsNull() && !plan.ResourceInstances.IsUnknown() && !state.ResourceInstances.IsNull() && !state.ResourceInstances.IsUnknown() {
- if plan.ResourceInstances.ValueInt64() != state.ResourceInstances.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.ResourceCPU.IsNull() != state.ResourceCPU.IsNull() || plan.ResourceCPU.IsUnknown() != state.ResourceCPU.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceCPU.IsNull() && !plan.ResourceCPU.IsUnknown() && !state.ResourceCPU.IsNull() && !state.ResourceCPU.IsUnknown() {
- if plan.ResourceCPU.ValueInt64() != state.ResourceCPU.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.ResourceMemory.IsNull() != state.ResourceMemory.IsNull() || plan.ResourceMemory.IsUnknown() != state.ResourceMemory.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceMemory.IsNull() && !plan.ResourceMemory.IsUnknown() && !state.ResourceMemory.IsNull() && !state.ResourceMemory.IsUnknown() {
- if plan.ResourceMemory.ValueInt64() != state.ResourceMemory.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 822: resources_core.FormatInt64(plan.ResourceInstances),
- 823: resources_core.FormatInt64(plan.ResourceCPU),
- 824: resources_core.FormatInt64(plan.ResourceMemory),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 82, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- // Restore user-provided casing в state (Update).
- // После API-вызова modify state содержит значения в lower-case от API.
- // Plan == config == то что написал пользователь (регистр неизменён).
- // EqualFold: если UUID совпадает без учёта регистра — берём из plan.
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *HarborResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state HarborModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "delete"
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *HarborResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *HarborResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/86_k8s_velero_resource.go b/provider/internal/resources_gen/86_k8s_velero_resource.go
deleted file mode 100644
index 1a180ac..0000000
--- a/provider/internal/resources_gen/86_k8s_velero_resource.go
+++ /dev/null
@@ -1,401 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "fmt"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: k8s_velero
-// Service ID: 86
-
-var _ resource.Resource = &K8sVeleroResource{}
-var _ resource.ResourceWithModifyPlan = &K8sVeleroResource{}
-var _ resource.ResourceWithImportState = &K8sVeleroResource{}
-
-type K8sVeleroResource struct {
- client *core.UniversalClient
-}
-
-// K8sVeleroBackupConfigurationModel — вложенная модель для map-fixed параметра backupConfiguration.
-type K8sVeleroBackupConfigurationModel struct {
- S3BucketUid types.String `tfsdk:"s3_bucket_uid" json:"s3BucketUid"`
-}
-
-// K8sVeleroClusterConfigurationModel — вложенная модель для map-fixed параметра clusterConfiguration.
-type K8sVeleroClusterConfigurationModel struct {
- Memory types.Int64 `tfsdk:"memory" json:"memory"`
- Replicas types.Int64 `tfsdk:"replicas" json:"replicas"`
- Cpu types.Int64 `tfsdk:"cpu" json:"cpu"`
-}
-
-// K8sVeleroNodeAgentConfigurationModel — вложенная модель для map-fixed параметра nodeAgentConfiguration.
-type K8sVeleroNodeAgentConfigurationModel struct {
- Cpu types.Int64 `tfsdk:"cpu" json:"cpu"`
- Memory types.Int64 `tfsdk:"memory" json:"memory"`
-}
-
-// K8sVeleroStartupConfigurationModel — вложенная модель для map-fixed параметра startupConfiguration.
-type K8sVeleroStartupConfigurationModel struct {
- ResourceRealm types.String `tfsdk:"resource_realm" json:"resourceRealm"`
-}
-
-type K8sVeleroModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- BackupConfiguration *K8sVeleroBackupConfigurationModel `tfsdk:"backup_configuration"`
- ClusterConfiguration *K8sVeleroClusterConfigurationModel `tfsdk:"cluster_configuration"`
- NodeAgentConfiguration *K8sVeleroNodeAgentConfigurationModel `tfsdk:"node_agent_configuration"`
- StartupConfiguration *K8sVeleroStartupConfigurationModel `tfsdk:"startup_configuration"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewK8sVeleroResource() resource.Resource {
- return &K8sVeleroResource{}
-}
-
-func (r *K8sVeleroResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_k8s_velero"
-}
-
-func (r *K8sVeleroResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "backup_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "s3_bucket_uid": schema.StringAttribute{Required: true, MarkdownDescription: "Экземпляр S3-Бакета обязателен
Учётная запись будет создана автоматически, если её нету"},
- }},
- "cluster_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(2048), MarkdownDescription: "Указывается в Megabytes"},
- "replicas": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1)},
- "cpu": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1000), MarkdownDescription: "Указывается в Milicores
`1000` Mili == `1` Ядро"},
- }},
- "node_agent_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "cpu": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(2000), MarkdownDescription: "Указывается в Milicores
`1000` Mili == `1` Ядро"},
- "memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(2048), MarkdownDescription: "Указывается в Megabytes"},
- }},
- "startup_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "resource_realm": schema.StringAttribute{Required: true},
- }},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *K8sVeleroResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *K8sVeleroModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *K8sVeleroModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan K8sVeleroModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 962: resources_core.BuildJSON(map[string]string{"memory": fmt.Sprintf("%d", config.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", config.ClusterConfiguration.Replicas.ValueInt64()), "cpu": fmt.Sprintf("%d", config.ClusterConfiguration.Cpu.ValueInt64())}),
- 963: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", config.StartupConfiguration.ResourceRealm.ValueString())}),
- 964: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", config.NodeAgentConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", config.NodeAgentConfiguration.Memory.ValueInt64())}),
- 1076: resources_core.BuildJSON(map[string]string{"s3BucketUid": fmt.Sprintf("\"%s\"", config.BackupConfiguration.S3BucketUid.ValueString())}),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 86, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *K8sVeleroResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data K8sVeleroModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 86, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 962: resources_core.BuildJSON(map[string]string{"memory": fmt.Sprintf("%d", data.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", data.ClusterConfiguration.Replicas.ValueInt64()), "cpu": fmt.Sprintf("%d", data.ClusterConfiguration.Cpu.ValueInt64())}),
- 963: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", data.StartupConfiguration.ResourceRealm.ValueString())}),
- 964: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", data.NodeAgentConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", data.NodeAgentConfiguration.Memory.ValueInt64())}),
- 1076: resources_core.BuildJSON(map[string]string{"s3BucketUid": fmt.Sprintf("\"%s\"", data.BackupConfiguration.S3BucketUid.ValueString())}),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 86, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 86, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "backupConfiguration", Field: "BackupConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "nodeAgentConfiguration", Field: "NodeAgentConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *K8sVeleroResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state K8sVeleroModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 86, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "backupConfiguration", Field: "BackupConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "nodeAgentConfiguration", Field: "NodeAgentConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *K8sVeleroResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan K8sVeleroModel
- var state K8sVeleroModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 965: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", plan.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", plan.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", plan.ClusterConfiguration.Replicas.ValueInt64())}),
- 966: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", plan.NodeAgentConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", plan.NodeAgentConfiguration.Memory.ValueInt64())}),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 86, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "backupConfiguration", Field: "BackupConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "nodeAgentConfiguration", Field: "NodeAgentConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *K8sVeleroResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state K8sVeleroModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *K8sVeleroResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *K8sVeleroResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/87_k8svalkey_resource.go b/provider/internal/resources_gen/87_k8svalkey_resource.go
deleted file mode 100644
index 28dabfe..0000000
--- a/provider/internal/resources_gen/87_k8svalkey_resource.go
+++ /dev/null
@@ -1,423 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "fmt"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: k8svalkey
-// Service ID: 87
-
-var _ resource.Resource = &K8svalkeyResource{}
-var _ resource.ResourceWithModifyPlan = &K8svalkeyResource{}
-var _ resource.ResourceWithImportState = &K8svalkeyResource{}
-
-type K8svalkeyResource struct {
- client *core.UniversalClient
-}
-
-// K8svalkeyAccessConfigurationModel — вложенная модель для map-fixed параметра accessConfiguration.
-type K8svalkeyAccessConfigurationModel struct {
- MasterIpSpace types.String `tfsdk:"master_ip_space" json:"masterIpSpace"`
- MasterAccessList types.String `tfsdk:"master_access_list" json:"masterAccessList"`
-}
-
-// K8svalkeyClusterConfigurationModel — вложенная модель для map-fixed параметра clusterConfiguration.
-type K8svalkeyClusterConfigurationModel struct {
- Cpu types.Int64 `tfsdk:"cpu" json:"cpu"`
- Memory types.Int64 `tfsdk:"memory" json:"memory"`
- Replicas types.Int64 `tfsdk:"replicas" json:"replicas"`
- Shards types.Int64 `tfsdk:"shards" json:"shards"`
- Disk types.Int64 `tfsdk:"disk" json:"disk"`
-}
-
-// K8svalkeyStartupConfigurationModel — вложенная модель для map-fixed параметра startupConfiguration.
-type K8svalkeyStartupConfigurationModel struct {
- ResourceRealm types.String `tfsdk:"resource_realm" json:"resourceRealm"`
-}
-
-// K8svalkeyValkeyConfigurationModel — вложенная модель для map-fixed параметра valkeyConfiguration.
-type K8svalkeyValkeyConfigurationModel struct {
- Version types.String `tfsdk:"version" json:"version"`
-}
-
-type K8svalkeyModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- AccessConfiguration *K8svalkeyAccessConfigurationModel `tfsdk:"access_configuration"`
- ClusterConfiguration *K8svalkeyClusterConfigurationModel `tfsdk:"cluster_configuration"`
- StartupConfiguration *K8svalkeyStartupConfigurationModel `tfsdk:"startup_configuration"`
- ValkeyConf types.String `tfsdk:"valkey_conf"`
- ValkeyConfiguration *K8svalkeyValkeyConfigurationModel `tfsdk:"valkey_configuration"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewK8svalkeyResource() resource.Resource {
- return &K8svalkeyResource{}
-}
-
-func (r *K8svalkeyResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_k8svalkey"
-}
-
-func (r *K8svalkeyResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "access_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "master_ip_space": schema.StringAttribute{Required: true, MarkdownDescription: "Из какого Ip-Space резервировать внешний IP
Список предоставляется из Организации, в котором развёрнута ресурсная платформа"},
- "master_access_list": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[]"), MarkdownDescription: "Необходимо настраивать, когда зарезервирован внешний адрес
Если передан пустой массив, доступ выделяется всем"},
- }},
- "cluster_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "cpu": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(500), MarkdownDescription: "Указывается в Milicores
`1000` Mili == `1` Ядро"},
- "memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(512), MarkdownDescription: "Указывается в Megabytes"},
- "replicas": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1)},
- "shards": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1)},
- "disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(10), MarkdownDescription: "Указывается в GIGAbytes"},
- }},
- "startup_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Кластер Kubernetes, на котором будет развернут экземпляр"},
- }},
- "valkey_conf": schema.StringAttribute{Optional: true, MarkdownDescription: "Не изменяется после создания."},
- "valkey_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "version": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("0.1.0")},
- }},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *K8svalkeyResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *K8svalkeyModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *K8svalkeyModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan K8svalkeyModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.ValkeyConf.IsNull() && !plan.ValkeyConf.IsUnknown() && !state.ValkeyConf.IsNull() && !state.ValkeyConf.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ValkeyConf.ValueString(), state.ValkeyConf.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить valkey_conf", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 1066: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", config.StartupConfiguration.ResourceRealm.ValueString())}),
- 1067: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", config.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", config.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", config.ClusterConfiguration.Replicas.ValueInt64()), "shards": fmt.Sprintf("%d", config.ClusterConfiguration.Shards.ValueInt64()), "disk": fmt.Sprintf("%d", config.ClusterConfiguration.Disk.ValueInt64())}),
- 1068: resources_core.BuildJSON(map[string]string{"masterIpSpace": fmt.Sprintf("\"%s\"", config.AccessConfiguration.MasterIpSpace.ValueString()), "masterAccessList": config.AccessConfiguration.MasterAccessList.ValueString()}),
- 1071: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", config.ValkeyConfiguration.Version.ValueString())}),
- 1072: resources_core.FormatString(config.ValkeyConf),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 87, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *K8svalkeyResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data K8svalkeyModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 87, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 1066: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", data.StartupConfiguration.ResourceRealm.ValueString())}),
- 1067: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", data.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", data.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", data.ClusterConfiguration.Replicas.ValueInt64()), "shards": fmt.Sprintf("%d", data.ClusterConfiguration.Shards.ValueInt64()), "disk": fmt.Sprintf("%d", data.ClusterConfiguration.Disk.ValueInt64())}),
- 1068: resources_core.BuildJSON(map[string]string{"masterIpSpace": fmt.Sprintf("\"%s\"", data.AccessConfiguration.MasterIpSpace.ValueString()), "masterAccessList": data.AccessConfiguration.MasterAccessList.ValueString()}),
- 1071: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", data.ValkeyConfiguration.Version.ValueString())}),
- 1072: resources_core.FormatString(data.ValkeyConf),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 87, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 87, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- {Code: "valkeyConf", Field: "ValkeyConf", Type: "array-map-fixed"},
- {Code: "valkeyConfiguration", Field: "ValkeyConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *K8svalkeyResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state K8svalkeyModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 87, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- {Code: "valkeyConf", Field: "ValkeyConf", Type: "array-map-fixed"},
- {Code: "valkeyConfiguration", Field: "ValkeyConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *K8svalkeyResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan K8svalkeyModel
- var state K8svalkeyModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 1069: resources_core.BuildJSON(map[string]string{"shards": fmt.Sprintf("%d", plan.ClusterConfiguration.Shards.ValueInt64()), "disk": fmt.Sprintf("%d", plan.ClusterConfiguration.Disk.ValueInt64()), "cpu": fmt.Sprintf("%d", plan.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", plan.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", plan.ClusterConfiguration.Replicas.ValueInt64())}),
- 1070: resources_core.BuildJSON(map[string]string{"masterIpSpace": fmt.Sprintf("\"%s\"", plan.AccessConfiguration.MasterIpSpace.ValueString()), "masterAccessList": plan.AccessConfiguration.MasterAccessList.ValueString()}),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 87, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- {Code: "valkeyConf", Field: "ValkeyConf", Type: "array-map-fixed"},
- {Code: "valkeyConfiguration", Field: "ValkeyConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *K8svalkeyResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state K8svalkeyModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *K8svalkeyResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *K8svalkeyResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/87_k8svalkey_user_resource.go b/provider/internal/resources_gen/87_k8svalkey_user_resource.go
deleted file mode 100644
index 3dbe8e0..0000000
--- a/provider/internal/resources_gen/87_k8svalkey_user_resource.go
+++ /dev/null
@@ -1,358 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: k8svalkey
-// Subresource: user
-
-var _ resource.Resource = &K8svalkeyUserResource{}
-
-// K8svalkeyUserResource manages a subresource via operations.
-type K8svalkeyUserResource struct {
- client *core.UniversalClient
-}
-
-type K8svalkeyUserModel struct {
- ID types.String `tfsdk:"id"`
- K8svalkeyID types.String `tfsdk:"k8svalkey_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- Permissions types.String `tfsdk:"permissions"`
- Username types.String `tfsdk:"username"`
-}
-
-func NewK8svalkeyUserResource() resource.Resource {
- return &K8svalkeyUserResource{}
-}
-
-func (r *K8svalkeyUserResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_k8svalkey_user"
-}
-
-func (r *K8svalkeyUserResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "k8svalkey_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "permissions": schema.StringAttribute{Required: true, MarkdownDescription: "Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- "username": schema.StringAttribute{Required: true, MarkdownDescription: "Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *K8svalkeyUserResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan K8svalkeyUserModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.Permissions.IsNull() || plan.Permissions.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "permissions is required.")
- return
- }
- if plan.Username.IsNull() || plan.Username.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "username is required.")
- return
- }
-
- instanceUID := strings.TrimSpace(plan.K8svalkeyID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{
- "permissions": resources_core.FormatString(plan.Permissions),
- "username": resources_core.FormatString(plan.Username),
- }
- identityCodes := []string{
- "permissions",
- "username",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("user", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "username": resources_core.FormatString(plan.Username),
- "permissions": resources_core.FormatString(plan.Permissions),
- })
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_user", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_user", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *K8svalkeyUserResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state K8svalkeyUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *K8svalkeyUserResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan K8svalkeyUserModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "" == "" {
- var state K8svalkeyUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.K8svalkeyID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- idParams := map[string]string{
- "permissions": resources_core.FormatString(plan.Permissions),
- "username": resources_core.FormatString(plan.Username),
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *K8svalkeyUserResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state K8svalkeyUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "delete_user" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.K8svalkeyID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{
- "permissions": resources_core.FormatString(state.Permissions),
- "username": resources_core.FormatString(state.Username),
- }
- identityCodes := []string{
- "permissions",
- "username",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("user", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "username": resources_core.FormatString(state.Username),
- })
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "delete_user", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *K8svalkeyUserResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/88_k8s_ziti_controller_resource.go b/provider/internal/resources_gen/88_k8s_ziti_controller_resource.go
deleted file mode 100644
index 234875e..0000000
--- a/provider/internal/resources_gen/88_k8s_ziti_controller_resource.go
+++ /dev/null
@@ -1,431 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: k8s_ziti_controller
-// Service ID: 88
-
-var _ resource.Resource = &K8sZitiControllerResource{}
-var _ resource.ResourceWithModifyPlan = &K8sZitiControllerResource{}
-var _ resource.ResourceWithImportState = &K8sZitiControllerResource{}
-
-type K8sZitiControllerResource struct {
- client *core.UniversalClient
-}
-
-type K8sZitiControllerModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- Domain types.String `tfsdk:"domain"`
- ResourceCPU types.Int64 `tfsdk:"resource_c_p_u"`
- ResourceDisk types.Int64 `tfsdk:"resource_disk"`
- ResourceInstances types.Int64 `tfsdk:"resource_instances"`
- ResourceMemory types.Int64 `tfsdk:"resource_memory"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewK8sZitiControllerResource() resource.Resource {
- return &K8sZitiControllerResource{}
-}
-
-func (r *K8sZitiControllerResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_k8s_ziti_controller"
-}
-
-func (r *K8sZitiControllerResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("k8sZitiController-1"), MarkdownDescription: "Если будет указан FQDN, то происходят проверки DNS на валидность А-записи, или будет добавлено в зону resourceRealm Не изменяется после создания."},
- "resource_c_p_u": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(300), MarkdownDescription: "Квота ядра пода (milicores) Не изменяется после создания."},
- "resource_disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Квота диска (Указывается в GIGAbytes) Не изменяется после создания."},
- "resource_instances": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Количество узлов Не изменяется после создания."},
- "resource_memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(512), MarkdownDescription: "Квота памяти пода (MBytes) Не изменяется после создания."},
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Платформа для развертывания Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *K8sZitiControllerResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *K8sZitiControllerModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *K8sZitiControllerModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan K8sZitiControllerModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.Domain.IsNull() && !plan.Domain.IsUnknown() && !state.Domain.IsNull() && !state.Domain.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.Domain.ValueString(), state.Domain.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить domain", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceCPU.IsNull() && !plan.ResourceCPU.IsUnknown() && !state.ResourceCPU.IsNull() && !state.ResourceCPU.IsUnknown() {
- if plan.ResourceCPU.ValueInt64() != state.ResourceCPU.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить resource_c_p_u", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceDisk.IsNull() && !plan.ResourceDisk.IsUnknown() && !state.ResourceDisk.IsNull() && !state.ResourceDisk.IsUnknown() {
- if plan.ResourceDisk.ValueInt64() != state.ResourceDisk.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить resource_disk", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceInstances.IsNull() && !plan.ResourceInstances.IsUnknown() && !state.ResourceInstances.IsNull() && !state.ResourceInstances.IsUnknown() {
- if plan.ResourceInstances.ValueInt64() != state.ResourceInstances.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить resource_instances", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceMemory.IsNull() && !plan.ResourceMemory.IsUnknown() && !state.ResourceMemory.IsNull() && !state.ResourceMemory.IsUnknown() {
- if plan.ResourceMemory.ValueInt64() != state.ResourceMemory.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить resource_memory", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.ResourceRealm.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
- if config.ResourceRealm.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 294: resources_core.FormatInt64(config.ResourceCPU),
- 295: resources_core.FormatInt64(config.ResourceMemory),
- 296: resources_core.FormatInt64(config.ResourceDisk),
- 297: resources_core.FormatInt64(config.ResourceInstances),
- 298: resources_core.FormatString(config.ResourceRealm),
- 299: resources_core.FormatString(config.Domain),
- }
- desiredDomain := ""
- if !config.Domain.IsNull() && !config.Domain.IsUnknown() {
- desiredDomain = config.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 88, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *K8sZitiControllerResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data K8sZitiControllerModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.ResourceRealm.IsNull() || data.ResourceRealm.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- if !data.Domain.IsNull() && !data.Domain.IsUnknown() {
- desiredDomain = data.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 88, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 294: resources_core.FormatInt64(data.ResourceCPU),
- 295: resources_core.FormatInt64(data.ResourceMemory),
- 296: resources_core.FormatInt64(data.ResourceDisk),
- 297: resources_core.FormatInt64(data.ResourceInstances),
- 298: resources_core.FormatString(data.ResourceRealm),
- 299: resources_core.FormatString(data.Domain),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 88, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 88, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *K8sZitiControllerResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state K8sZitiControllerModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 88, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *K8sZitiControllerResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan K8sZitiControllerModel
- var state K8sZitiControllerModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{}
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 88, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *K8sZitiControllerResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state K8sZitiControllerModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "delete"
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *K8sZitiControllerResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *K8sZitiControllerResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/89_flask_resource.go b/provider/internal/resources_gen/89_flask_resource.go
deleted file mode 100644
index f6624df..0000000
--- a/provider/internal/resources_gen/89_flask_resource.go
+++ /dev/null
@@ -1,449 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "fmt"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: flask
-// Service ID: 89
-
-var _ resource.Resource = &FlaskResource{}
-var _ resource.ResourceWithModifyPlan = &FlaskResource{}
-var _ resource.ResourceWithImportState = &FlaskResource{}
-
-type FlaskResource struct {
- client *core.UniversalClient
-}
-
-// FlaskAccessConfigurationModel — вложенная модель для map-fixed параметра accessConfiguration.
-type FlaskAccessConfigurationModel struct {
- Domain types.String `tfsdk:"domain" json:"domain"`
-}
-
-// FlaskAppConfigurationModel — вложенная модель для map-fixed параметра appConfiguration.
-type FlaskAppConfigurationModel struct {
- Version types.String `tfsdk:"version" json:"version"`
- GitPath types.String `tfsdk:"git_path" json:"gitPath"`
- HealthPath types.String `tfsdk:"health_path" json:"healthPath"`
-}
-
-// FlaskClusterConfigurationModel — вложенная модель для map-fixed параметра clusterConfiguration.
-type FlaskClusterConfigurationModel struct {
- Replicas types.Int64 `tfsdk:"replicas" json:"replicas"`
- Cpu types.Int64 `tfsdk:"cpu" json:"cpu"`
- Memory types.Int64 `tfsdk:"memory" json:"memory"`
-}
-
-// FlaskStartupConfigurationModel — вложенная модель для map-fixed параметра startupConfiguration.
-type FlaskStartupConfigurationModel struct {
- ResourceRealm types.String `tfsdk:"resource_realm" json:"resourceRealm"`
-}
-
-type FlaskModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- // --- Redeploy support (ARCHITECTURE.md) ---
- // git_revision: при изменении вызывает redeploy вместо modify.
- // Опциональное поле — если не задано, modify работает как обычно.
- GitRevision types.String `tfsdk:"git_revision"`
- AccessConfiguration *FlaskAccessConfigurationModel `tfsdk:"access_configuration"`
- AppConfiguration *FlaskAppConfigurationModel `tfsdk:"app_configuration"`
- ClusterConfiguration *FlaskClusterConfigurationModel `tfsdk:"cluster_configuration"`
- JsonEnv types.String `tfsdk:"json_env"`
- StartupConfiguration *FlaskStartupConfigurationModel `tfsdk:"startup_configuration"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewFlaskResource() resource.Resource {
- return &FlaskResource{}
-}
-
-func (r *FlaskResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_flask"
-}
-
-func (r *FlaskResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "access_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("flask-y0lfavjf"), MarkdownDescription: "Если указан FQDN в формате: `myapp.example.com`, предварительно будет проверяться DNS-запись (А-запись **должна смотреть на IP Ingress кластера ресурсной платформы**)
Если указан в формате `myapp`, DNS-запись будет автоматически создана в служебной DNS-зоне"},
- }},
- "app_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "version": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("3.12")},
- "git_path": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("https://github.com/Foxyhhd/Baldurs-Gate-test.git"), MarkdownDescription: "Путь до репозитория приложения
Обязательно должен быть передан как URL: `https://....`
Должен быть сетевой доступ до URL для скачивания исходников"},
- "health_path": schema.StringAttribute{Optional: true, MarkdownDescription: "Путь до healtcheck для запуска пода в Kubernetes, который отдаст 200 код
Пустое значение означает, что будет проверяться исключительно доступность приложения по порту"},
- }},
- "cluster_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "replicas": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1)},
- "cpu": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(200), MarkdownDescription: "Указывается в Milicores
`1000` Mili == `1` Ядро"},
- "memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(256), MarkdownDescription: "Указывается в Megabytes"},
- }},
- "json_env": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("{}")},
- "startup_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Кластер Kubernetes, на котором будет развернут экземпляр"},
- }},
- // --- Redeploy support (ARCHITECTURE.md) ---
- // При изменении git_revision вызывается redeploy вместо modify.
- // Если не задано — modify работает без изменений.
- "git_revision": schema.StringAttribute{Optional: true, MarkdownDescription: "Git revision (commit hash/tag). Changing this triggers redeploy instead of modify."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *FlaskResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *FlaskModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *FlaskModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan FlaskModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 1037: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", config.StartupConfiguration.ResourceRealm.ValueString())}),
- 1038: resources_core.BuildJSON(map[string]string{"replicas": fmt.Sprintf("%d", config.ClusterConfiguration.Replicas.ValueInt64()), "cpu": fmt.Sprintf("%d", config.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", config.ClusterConfiguration.Memory.ValueInt64())}),
- 1039: resources_core.BuildJSON(map[string]string{"domain": fmt.Sprintf("\"%s\"", config.AccessConfiguration.Domain.ValueString())}),
- 1040: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", config.AppConfiguration.Version.ValueString()), "gitPath": fmt.Sprintf("\"%s\"", config.AppConfiguration.GitPath.ValueString()), "healthPath": fmt.Sprintf("\"%s\"", config.AppConfiguration.HealthPath.ValueString())}),
- 1041: resources_core.FormatString(config.JsonEnv),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 89, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *FlaskResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data FlaskModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 89, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 1037: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", data.StartupConfiguration.ResourceRealm.ValueString())}),
- 1038: resources_core.BuildJSON(map[string]string{"replicas": fmt.Sprintf("%d", data.ClusterConfiguration.Replicas.ValueInt64()), "cpu": fmt.Sprintf("%d", data.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", data.ClusterConfiguration.Memory.ValueInt64())}),
- 1039: resources_core.BuildJSON(map[string]string{"domain": fmt.Sprintf("\"%s\"", data.AccessConfiguration.Domain.ValueString())}),
- 1040: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", data.AppConfiguration.Version.ValueString()), "gitPath": fmt.Sprintf("\"%s\"", data.AppConfiguration.GitPath.ValueString()), "healthPath": fmt.Sprintf("\"%s\"", data.AppConfiguration.HealthPath.ValueString())}),
- 1041: resources_core.FormatString(data.JsonEnv),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 89, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 89, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "appConfiguration", Field: "AppConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "jsonEnv", Field: "JsonEnv", Type: "string"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *FlaskResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state FlaskModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 89, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "appConfiguration", Field: "AppConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "jsonEnv", Field: "JsonEnv", Type: "string"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *FlaskResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan FlaskModel
- var state FlaskModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.JsonEnv.IsNull() != state.JsonEnv.IsNull() || plan.JsonEnv.IsUnknown() != state.JsonEnv.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.JsonEnv.IsNull() && !plan.JsonEnv.IsUnknown() && !state.JsonEnv.IsNull() && !state.JsonEnv.IsUnknown() {
- if !strings.EqualFold(plan.JsonEnv.ValueString(), state.JsonEnv.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
- // --- Redeploy support (ARCHITECTURE.md) ---
- // Проверяем изменился ли git_revision.
- // Если да — вызываем redeploy вместо modify.
- // git_revision = "" (не задано) → обычный modify.
- redeployRequested := false
- if !plan.GitRevision.IsNull() && !plan.GitRevision.IsUnknown() {
- if state.GitRevision.IsNull() || state.GitRevision.IsUnknown() || plan.GitRevision.ValueString() != state.GitRevision.ValueString() {
- redeployRequested = true
- }
- }
-
- if !hasServiceParamChanges && !redeployRequested {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- // --- Redeploy support (ARCHITECTURE.md) ---
- if redeployRequested {
- // Вызываем redeploy — пустой params (операция не требует CFS-параметров)
- if err := r.client.RunRedeployOperation(ctx, instanceID.ValueString(), operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- } else {
- params := map[int]string{
- 1042: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", plan.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", plan.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", plan.ClusterConfiguration.Replicas.ValueInt64())}),
- 1043: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", plan.AppConfiguration.Version.ValueString()), "gitPath": fmt.Sprintf("\"%s\"", plan.AppConfiguration.GitPath.ValueString()), "healthPath": fmt.Sprintf("\"%s\"", plan.AppConfiguration.HealthPath.ValueString())}),
- 1044: resources_core.FormatString(plan.JsonEnv),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 89, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "appConfiguration", Field: "AppConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "jsonEnv", Field: "JsonEnv", Type: "string"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *FlaskResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state FlaskModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *FlaskResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *FlaskResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/90_postgres_backup_resource.go b/provider/internal/resources_gen/90_postgres_backup_resource.go
deleted file mode 100644
index 957eb3e..0000000
--- a/provider/internal/resources_gen/90_postgres_backup_resource.go
+++ /dev/null
@@ -1,326 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: postgres
-// Subresource: backup
-
-var _ resource.Resource = &PostgresBackupResource{}
-
-// PostgresBackupResource manages a subresource via operations.
-type PostgresBackupResource struct {
- client *core.UniversalClient
-}
-
-type PostgresBackupModel struct {
- ID types.String `tfsdk:"id"`
- PostgresID types.String `tfsdk:"postgres_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
-}
-
-func NewPostgresBackupResource() resource.Resource {
- return &PostgresBackupResource{}
-}
-
-func (r *PostgresBackupResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_postgres_backup"
-}
-
-func (r *PostgresBackupResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "postgres_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *PostgresBackupResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan PostgresBackupModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceUID := strings.TrimSpace(plan.PostgresID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{}
- identityCodes := []string{}
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("backup", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "backup", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_backup", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_backup", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "backup", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "backup", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "backup", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *PostgresBackupResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state PostgresBackupModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *PostgresBackupResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan PostgresBackupModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "" == "" {
- var state PostgresBackupModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.PostgresID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- idParams := map[string]string{}
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "backup", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *PostgresBackupResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state PostgresBackupModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.PostgresID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{}
- identityCodes := []string{}
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("backup", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *PostgresBackupResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/90_postgres_database_resource.go b/provider/internal/resources_gen/90_postgres_database_resource.go
deleted file mode 100644
index 7310720..0000000
--- a/provider/internal/resources_gen/90_postgres_database_resource.go
+++ /dev/null
@@ -1,358 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: postgres
-// Subresource: database
-
-var _ resource.Resource = &PostgresDatabaseResource{}
-
-// PostgresDatabaseResource manages a subresource via operations.
-type PostgresDatabaseResource struct {
- client *core.UniversalClient
-}
-
-type PostgresDatabaseModel struct {
- ID types.String `tfsdk:"id"`
- PostgresID types.String `tfsdk:"postgres_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- DbName types.String `tfsdk:"db_name"`
- DbOwner types.String `tfsdk:"db_owner"`
-}
-
-func NewPostgresDatabaseResource() resource.Resource {
- return &PostgresDatabaseResource{}
-}
-
-func (r *PostgresDatabaseResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_postgres_database"
-}
-
-func (r *PostgresDatabaseResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "postgres_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "db_name": schema.StringAttribute{Required: true, MarkdownDescription: "Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- "db_owner": schema.StringAttribute{Required: true, MarkdownDescription: "Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *PostgresDatabaseResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan PostgresDatabaseModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.DbName.IsNull() || plan.DbName.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "db_name is required.")
- return
- }
- if plan.DbOwner.IsNull() || plan.DbOwner.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "db_owner is required.")
- return
- }
-
- instanceUID := strings.TrimSpace(plan.PostgresID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{
- "dbName": resources_core.FormatString(plan.DbName),
- "dbOwner": resources_core.FormatString(plan.DbOwner),
- }
- identityCodes := []string{
- "dbName",
- "dbOwner",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("database", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "database", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "dbName": resources_core.FormatString(plan.DbName),
- "dbOwner": resources_core.FormatString(plan.DbOwner),
- })
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_database", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_database", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "database", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "database", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "database", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *PostgresDatabaseResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state PostgresDatabaseModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *PostgresDatabaseResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan PostgresDatabaseModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "" == "" {
- var state PostgresDatabaseModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.PostgresID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- idParams := map[string]string{
- "dbName": resources_core.FormatString(plan.DbName),
- "dbOwner": resources_core.FormatString(plan.DbOwner),
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "database", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *PostgresDatabaseResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state PostgresDatabaseModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "delete_database" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.PostgresID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{
- "dbName": resources_core.FormatString(state.DbName),
- "dbOwner": resources_core.FormatString(state.DbOwner),
- }
- identityCodes := []string{
- "dbName",
- "dbOwner",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("database", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "dbName": resources_core.FormatString(state.DbName),
- })
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "delete_database", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *PostgresDatabaseResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/90_postgres_resource.go b/provider/internal/resources_gen/90_postgres_resource.go
deleted file mode 100644
index 6924e3a..0000000
--- a/provider/internal/resources_gen/90_postgres_resource.go
+++ /dev/null
@@ -1,499 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "fmt"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: postgres
-// Service ID: 90
-
-var _ resource.Resource = &PostgresResource{}
-var _ resource.ResourceWithModifyPlan = &PostgresResource{}
-var _ resource.ResourceWithImportState = &PostgresResource{}
-
-type PostgresResource struct {
- client *core.UniversalClient
-}
-
-// PostgresAccessConfigurationModel — вложенная модель для map-fixed параметра accessConfiguration.
-type PostgresAccessConfigurationModel struct {
- MasterIpSpace types.String `tfsdk:"master_ip_space" json:"masterIpSpace"`
- MasterAccessList types.String `tfsdk:"master_access_list" json:"masterAccessList"`
- SlaveIpSpace types.String `tfsdk:"slave_ip_space" json:"slaveIpSpace"`
- SlaveAccessList types.String `tfsdk:"slave_access_list" json:"slaveAccessList"`
-}
-
-// PostgresAutoscaleConfigurationModel — вложенная модель для map-fixed параметра autoscaleConfiguration.
-type PostgresAutoscaleConfigurationModel struct {
- Percent types.Int64 `tfsdk:"percent" json:"percent"`
- Enabled types.Bool `tfsdk:"enabled" json:"enabled"`
- Schedule types.Int64 `tfsdk:"schedule" json:"schedule"`
- Quota types.Int64 `tfsdk:"quota" json:"quota"`
-}
-
-// PostgresBackupConfigurationModel — вложенная модель для map-fixed параметра backupConfiguration.
-type PostgresBackupConfigurationModel struct {
- S3Uid types.String `tfsdk:"s3_uid" json:"s3Uid"`
- Retain types.Int64 `tfsdk:"retain" json:"retain"`
- Schedule types.String `tfsdk:"schedule" json:"schedule"`
-}
-
-// PostgresClusterConfigurationModel — вложенная модель для map-fixed параметра clusterConfiguration.
-type PostgresClusterConfigurationModel struct {
- Memory types.Int64 `tfsdk:"memory" json:"memory"`
- Replicas types.Int64 `tfsdk:"replicas" json:"replicas"`
- Disk types.Int64 `tfsdk:"disk" json:"disk"`
- Cpu types.Int64 `tfsdk:"cpu" json:"cpu"`
-}
-
-// PostgresMtlsConfigurationModel — вложенная модель для map-fixed параметра mtlsConfiguration.
-type PostgresMtlsConfigurationModel struct {
- Type types.String `tfsdk:"type" json:"type"`
- DurationCA types.Int64 `tfsdk:"duration_c_a" json:"durationCA"`
- DurationServer types.Int64 `tfsdk:"duration_server" json:"durationServer"`
- CertCA types.String `tfsdk:"cert_c_a" json:"certCA"`
- CertServer types.String `tfsdk:"cert_server" json:"certServer"`
-}
-
-// PostgresPostgresConfigurationModel — вложенная модель для map-fixed параметра postgresConfiguration.
-type PostgresPostgresConfigurationModel struct {
- Version types.String `tfsdk:"version" json:"version"`
- SslRequired types.Bool `tfsdk:"ssl_required" json:"sslRequired"`
- PoolerMaster types.Bool `tfsdk:"pooler_master" json:"poolerMaster"`
- PoolerSlave types.Bool `tfsdk:"pooler_slave" json:"poolerSlave"`
-}
-
-// PostgresStartupConfigurationModel — вложенная модель для map-fixed параметра startupConfiguration.
-type PostgresStartupConfigurationModel struct {
- ResourceRealm types.String `tfsdk:"resource_realm" json:"resourceRealm"`
-}
-
-type PostgresModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- AccessConfiguration *PostgresAccessConfigurationModel `tfsdk:"access_configuration"`
- AutoscaleConfiguration *PostgresAutoscaleConfigurationModel `tfsdk:"autoscale_configuration"`
- BackupConfiguration *PostgresBackupConfigurationModel `tfsdk:"backup_configuration"`
- ClusterConfiguration *PostgresClusterConfigurationModel `tfsdk:"cluster_configuration"`
- MtlsConfiguration *PostgresMtlsConfigurationModel `tfsdk:"mtls_configuration"`
- PostgresConf types.String `tfsdk:"postgres_conf"`
- PostgresConfiguration *PostgresPostgresConfigurationModel `tfsdk:"postgres_configuration"`
- StartupConfiguration *PostgresStartupConfigurationModel `tfsdk:"startup_configuration"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewPostgresResource() resource.Resource {
- return &PostgresResource{}
-}
-
-func (r *PostgresResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_postgres"
-}
-
-func (r *PostgresResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "access_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "master_ip_space": schema.StringAttribute{Required: true, MarkdownDescription: "Из какого Ip-Space резервировать внешний IP
Список предоставляется из Организации, в котором развёрнута ресурсная платформа"},
- "master_access_list": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[]"), MarkdownDescription: "Необходимо настраивать, когда зарезервирован внешний адрес
Если передан пустой массив, доступ выделяется всем"},
- "slave_ip_space": schema.StringAttribute{Required: true, MarkdownDescription: "Из какого Ip-Space резервировать внешний IP
Список предоставляется из Организации, в котором развёрнута ресурсная платформа"},
- "slave_access_list": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[]"), MarkdownDescription: "Необходимо настраивать, когда зарезервирован внешний адрес
Если передан пустой массив, доступ выделяется всем"},
- }},
- "autoscale_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "percent": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(10), MarkdownDescription: "Требует включения autoScale. Позволяет указать в процентах расширение от текущего макс объема
Минимальный размер на который расширяется - **1Gb**"},
- "enabled": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Включает автоскейлинг PV. При включении параметра необходимо настроить autoScalePercentage и autoScaleTechWindow. Алерт при срабатывании вызывает modify у текущей услуги"},
- "schedule": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(0), MarkdownDescription: "Требует включения autoScale. Окно обновления (пока не реализовано). Указывается час в виде Integer (0 / 5 / 12 / 23)"},
- "quota": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(100), MarkdownDescription: "До какого размера возможно увеличивать диск, когда включен Autoscale"},
- }},
- "backup_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "s3_uid": schema.StringAttribute{Required: true, MarkdownDescription: "Экземпляр S3 обязателен"},
- "retain": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(7)},
- "schedule": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("0 0 * * *")},
- }},
- "cluster_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(512), MarkdownDescription: "Указывается в Megabytes"},
- "replicas": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1)},
- "disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(10), MarkdownDescription: "Указывается в GIGAbytes"},
- "cpu": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(500), MarkdownDescription: "Указывается в Milicores
`1000` Mili == `1` Ядро"},
- }},
- "mtls_configuration": schema.SingleNestedAttribute{Optional: true, Computed: true,
- Attributes: map[string]schema.Attribute{
- "type": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("off"), MarkdownDescription: "`off` - Настройка MTLS производиться не будет
`manual` - После создания кластера в полях данных будет запрос на создание сертификата. **Вам необходимо будет выписать сертификат через вашу CA** и уже после включить через операцию **modify** режим MTLS
`auto` - Сертификаты будут созданы через Cert-Manager
Режимы **auto** и **manual** требует включить настройку `Включить sslMode` - **true**
MTLS в режиме **auto** будет работать сразу, в режиме **manual** только после того как будет предоставлен **CA** и **Сертификат сервера**"},
- "duration_c_a": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(175200), MarkdownDescription: "Указывается в **часах**
Необходимо настраивать, когда параметр `Режим настройки` - **auto**"},
- "duration_server": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(87600), MarkdownDescription: "Указывается в **часах**
Не может быть больше чем время жизни СА
Обновляется **раз в год**, если выставлено значение **более 2 лет**
Обновляется **раз в пол года**, если выставлено значение **менее 2 лет**
Необходимо настраивать, когда параметр `Режим настройки` - **auto**"},
- "cert_c_a": schema.StringAttribute{Optional: true},
- "cert_server": schema.StringAttribute{Optional: true},
- }},
- "postgres_conf": schema.StringAttribute{Optional: true},
- "postgres_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "version": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("17")},
- "ssl_required": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true), MarkdownDescription: "По умолчанию подключение обязательное (sslmode=require)"},
- "pooler_master": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Включает pgPooler (на запись). Будет создан новый под
Размер пода **200m/400Mi**"},
- "pooler_slave": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Включает pgPooler (на чтение). Будет создан новый под
Размер пода **200m/400Mi**"},
- }},
- "startup_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Кластер Kubernetes, на котором будет развернут экземпляр"},
- }},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *PostgresResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *PostgresModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *PostgresModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan PostgresModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 788: resources_core.BuildJSON(map[string]string{"memory": fmt.Sprintf("%d", config.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", config.ClusterConfiguration.Replicas.ValueInt64()), "disk": fmt.Sprintf("%d", config.ClusterConfiguration.Disk.ValueInt64()), "cpu": fmt.Sprintf("%d", config.ClusterConfiguration.Cpu.ValueInt64())}),
- 789: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", config.StartupConfiguration.ResourceRealm.ValueString())}),
- 790: resources_core.BuildJSON(map[string]string{"masterIpSpace": fmt.Sprintf("\"%s\"", config.AccessConfiguration.MasterIpSpace.ValueString()), "masterAccessList": config.AccessConfiguration.MasterAccessList.ValueString(), "slaveIpSpace": fmt.Sprintf("\"%s\"", config.AccessConfiguration.SlaveIpSpace.ValueString()), "slaveAccessList": config.AccessConfiguration.SlaveAccessList.ValueString()}),
- 791: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", config.PostgresConfiguration.Version.ValueString()), "sslRequired": fmt.Sprintf("%v", config.PostgresConfiguration.SslRequired.ValueBool()), "poolerMaster": fmt.Sprintf("%v", config.PostgresConfiguration.PoolerMaster.ValueBool()), "poolerSlave": fmt.Sprintf("%v", config.PostgresConfiguration.PoolerSlave.ValueBool())}),
- 792: resources_core.FormatString(config.PostgresConf),
- 793: resources_core.BuildJSON(map[string]string{"s3Uid": fmt.Sprintf("\"%s\"", config.BackupConfiguration.S3Uid.ValueString()), "retain": fmt.Sprintf("%d", config.BackupConfiguration.Retain.ValueInt64()), "schedule": fmt.Sprintf("\"%s\"", config.BackupConfiguration.Schedule.ValueString())}),
- 794: resources_core.BuildJSON(map[string]string{"percent": fmt.Sprintf("%d", config.AutoscaleConfiguration.Percent.ValueInt64()), "enabled": fmt.Sprintf("%v", config.AutoscaleConfiguration.Enabled.ValueBool()), "schedule": fmt.Sprintf("%d", config.AutoscaleConfiguration.Schedule.ValueInt64()), "quota": fmt.Sprintf("%d", config.AutoscaleConfiguration.Quota.ValueInt64())}),
- 1094: resources_core.BuildJSON(map[string]string{"type": fmt.Sprintf("\"%s\"", config.MtlsConfiguration.Type.ValueString()), "durationCA": fmt.Sprintf("%d", config.MtlsConfiguration.DurationCA.ValueInt64()), "durationServer": fmt.Sprintf("%d", config.MtlsConfiguration.DurationServer.ValueInt64()), "certCA": fmt.Sprintf("\"%s\"", config.MtlsConfiguration.CertCA.ValueString()), "certServer": fmt.Sprintf("\"%s\"", config.MtlsConfiguration.CertServer.ValueString())}),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 90, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *PostgresResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data PostgresModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 90, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 788: resources_core.BuildJSON(map[string]string{"memory": fmt.Sprintf("%d", data.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", data.ClusterConfiguration.Replicas.ValueInt64()), "disk": fmt.Sprintf("%d", data.ClusterConfiguration.Disk.ValueInt64()), "cpu": fmt.Sprintf("%d", data.ClusterConfiguration.Cpu.ValueInt64())}),
- 789: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", data.StartupConfiguration.ResourceRealm.ValueString())}),
- 790: resources_core.BuildJSON(map[string]string{"masterIpSpace": fmt.Sprintf("\"%s\"", data.AccessConfiguration.MasterIpSpace.ValueString()), "masterAccessList": data.AccessConfiguration.MasterAccessList.ValueString(), "slaveIpSpace": fmt.Sprintf("\"%s\"", data.AccessConfiguration.SlaveIpSpace.ValueString()), "slaveAccessList": data.AccessConfiguration.SlaveAccessList.ValueString()}),
- 791: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", data.PostgresConfiguration.Version.ValueString()), "sslRequired": fmt.Sprintf("%v", data.PostgresConfiguration.SslRequired.ValueBool()), "poolerMaster": fmt.Sprintf("%v", data.PostgresConfiguration.PoolerMaster.ValueBool()), "poolerSlave": fmt.Sprintf("%v", data.PostgresConfiguration.PoolerSlave.ValueBool())}),
- 792: resources_core.FormatString(data.PostgresConf),
- 793: resources_core.BuildJSON(map[string]string{"s3Uid": fmt.Sprintf("\"%s\"", data.BackupConfiguration.S3Uid.ValueString()), "retain": fmt.Sprintf("%d", data.BackupConfiguration.Retain.ValueInt64()), "schedule": fmt.Sprintf("\"%s\"", data.BackupConfiguration.Schedule.ValueString())}),
- 794: resources_core.BuildJSON(map[string]string{"percent": fmt.Sprintf("%d", data.AutoscaleConfiguration.Percent.ValueInt64()), "enabled": fmt.Sprintf("%v", data.AutoscaleConfiguration.Enabled.ValueBool()), "schedule": fmt.Sprintf("%d", data.AutoscaleConfiguration.Schedule.ValueInt64()), "quota": fmt.Sprintf("%d", data.AutoscaleConfiguration.Quota.ValueInt64())}),
- 1094: resources_core.BuildJSON(map[string]string{"type": fmt.Sprintf("\"%s\"", data.MtlsConfiguration.Type.ValueString()), "durationCA": fmt.Sprintf("%d", data.MtlsConfiguration.DurationCA.ValueInt64()), "durationServer": fmt.Sprintf("%d", data.MtlsConfiguration.DurationServer.ValueInt64()), "certCA": fmt.Sprintf("\"%s\"", data.MtlsConfiguration.CertCA.ValueString()), "certServer": fmt.Sprintf("\"%s\"", data.MtlsConfiguration.CertServer.ValueString())}),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 90, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 90, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "autoscaleConfiguration", Field: "AutoscaleConfiguration", Type: "map-fixed"},
- {Code: "backupConfiguration", Field: "BackupConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "mtlsConfiguration", Field: "MtlsConfiguration", Type: "map-fixed"},
- {Code: "postgresConf", Field: "PostgresConf", Type: "array-map-fixed"},
- {Code: "postgresConfiguration", Field: "PostgresConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *PostgresResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state PostgresModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 90, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "autoscaleConfiguration", Field: "AutoscaleConfiguration", Type: "map-fixed"},
- {Code: "backupConfiguration", Field: "BackupConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "mtlsConfiguration", Field: "MtlsConfiguration", Type: "map-fixed"},
- {Code: "postgresConf", Field: "PostgresConf", Type: "array-map-fixed"},
- {Code: "postgresConfiguration", Field: "PostgresConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *PostgresResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan PostgresModel
- var state PostgresModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.PostgresConf.IsNull() != state.PostgresConf.IsNull() || plan.PostgresConf.IsUnknown() != state.PostgresConf.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.PostgresConf.IsNull() && !plan.PostgresConf.IsUnknown() && !state.PostgresConf.IsNull() && !state.PostgresConf.IsUnknown() {
- if !strings.EqualFold(plan.PostgresConf.ValueString(), state.PostgresConf.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 795: resources_core.BuildJSON(map[string]string{"replicas": fmt.Sprintf("%d", plan.ClusterConfiguration.Replicas.ValueInt64()), "disk": fmt.Sprintf("%d", plan.ClusterConfiguration.Disk.ValueInt64()), "cpu": fmt.Sprintf("%d", plan.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", plan.ClusterConfiguration.Memory.ValueInt64())}),
- 796: resources_core.BuildJSON(map[string]string{"masterIpSpace": fmt.Sprintf("\"%s\"", plan.AccessConfiguration.MasterIpSpace.ValueString()), "masterAccessList": plan.AccessConfiguration.MasterAccessList.ValueString(), "slaveIpSpace": fmt.Sprintf("\"%s\"", plan.AccessConfiguration.SlaveIpSpace.ValueString()), "slaveAccessList": plan.AccessConfiguration.SlaveAccessList.ValueString()}),
- 797: resources_core.BuildJSON(map[string]string{"poolerSlave": fmt.Sprintf("%v", plan.PostgresConfiguration.PoolerSlave.ValueBool()), "version": fmt.Sprintf("\"%s\"", plan.PostgresConfiguration.Version.ValueString()), "sslRequired": fmt.Sprintf("%v", plan.PostgresConfiguration.SslRequired.ValueBool()), "poolerMaster": fmt.Sprintf("%v", plan.PostgresConfiguration.PoolerMaster.ValueBool())}),
- 798: resources_core.FormatString(plan.PostgresConf),
- 799: resources_core.BuildJSON(map[string]string{"s3Uid": fmt.Sprintf("\"%s\"", plan.BackupConfiguration.S3Uid.ValueString()), "retain": fmt.Sprintf("%d", plan.BackupConfiguration.Retain.ValueInt64()), "schedule": fmt.Sprintf("\"%s\"", plan.BackupConfiguration.Schedule.ValueString())}),
- 800: resources_core.BuildJSON(map[string]string{"enabled": fmt.Sprintf("%v", plan.AutoscaleConfiguration.Enabled.ValueBool()), "schedule": fmt.Sprintf("%d", plan.AutoscaleConfiguration.Schedule.ValueInt64()), "quota": fmt.Sprintf("%d", plan.AutoscaleConfiguration.Quota.ValueInt64()), "percent": fmt.Sprintf("%d", plan.AutoscaleConfiguration.Percent.ValueInt64())}),
- 1095: resources_core.BuildJSON(map[string]string{"certServer": fmt.Sprintf("\"%s\"", plan.MtlsConfiguration.CertServer.ValueString()), "type": fmt.Sprintf("\"%s\"", plan.MtlsConfiguration.Type.ValueString()), "durationCA": fmt.Sprintf("%d", plan.MtlsConfiguration.DurationCA.ValueInt64()), "durationServer": fmt.Sprintf("%d", plan.MtlsConfiguration.DurationServer.ValueInt64()), "certCA": fmt.Sprintf("\"%s\"", plan.MtlsConfiguration.CertCA.ValueString())}),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 90, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "autoscaleConfiguration", Field: "AutoscaleConfiguration", Type: "map-fixed"},
- {Code: "backupConfiguration", Field: "BackupConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "mtlsConfiguration", Field: "MtlsConfiguration", Type: "map-fixed"},
- {Code: "postgresConf", Field: "PostgresConf", Type: "array-map-fixed"},
- {Code: "postgresConfiguration", Field: "PostgresConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *PostgresResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state PostgresModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *PostgresResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *PostgresResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/90_postgres_user_resource.go b/provider/internal/resources_gen/90_postgres_user_resource.go
deleted file mode 100644
index 8ac874c..0000000
--- a/provider/internal/resources_gen/90_postgres_user_resource.go
+++ /dev/null
@@ -1,367 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: postgres
-// Subresource: user
-
-var _ resource.Resource = &PostgresUserResource{}
-
-// PostgresUserResource manages a subresource via operations.
-type PostgresUserResource struct {
- client *core.UniversalClient
-}
-
-type PostgresUserModel struct {
- ID types.String `tfsdk:"id"`
- PostgresID types.String `tfsdk:"postgres_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- MtlsAccess types.Bool `tfsdk:"mtls_access"`
- Role types.String `tfsdk:"role"`
- Username types.String `tfsdk:"username"`
-}
-
-func NewPostgresUserResource() resource.Resource {
- return &PostgresUserResource{}
-}
-
-func (r *PostgresUserResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_postgres_user"
-}
-
-func (r *PostgresUserResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "postgres_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "mtls_access": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Подключение пользователя без ввода паролей
Политика применяется **ко всем базам** внутри Postgresql
RBAC на базы настраивать вручную Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.Bool{boolplanmodifier.RequiresReplace()}},
- "role": schema.StringAttribute{Required: true, MarkdownDescription: "Выбрать роль из списка Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- "username": schema.StringAttribute{Required: true, MarkdownDescription: "Не изменяется после создания. Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *PostgresUserResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan PostgresUserModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.Role.IsNull() || plan.Role.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "role is required.")
- return
- }
- if plan.Username.IsNull() || plan.Username.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "username is required.")
- return
- }
-
- instanceUID := strings.TrimSpace(plan.PostgresID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{
- "mtlsAccess": resources_core.FormatBool(plan.MtlsAccess),
- "role": resources_core.FormatString(plan.Role),
- "username": resources_core.FormatString(plan.Username),
- }
- identityCodes := []string{
- "mtlsAccess",
- "role",
- "username",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("user", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "username": resources_core.FormatString(plan.Username),
- "role": resources_core.FormatString(plan.Role),
- "mtlsAccess": resources_core.FormatBool(plan.MtlsAccess),
- })
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_user", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_user", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *PostgresUserResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state PostgresUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *PostgresUserResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan PostgresUserModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "" == "" {
- var state PostgresUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.PostgresID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{})
-
- idParams := map[string]string{
- "mtlsAccess": resources_core.FormatBool(plan.MtlsAccess),
- "role": resources_core.FormatString(plan.Role),
- "username": resources_core.FormatString(plan.Username),
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *PostgresUserResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state PostgresUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "delete_user" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.PostgresID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{
- "mtlsAccess": resources_core.FormatBool(state.MtlsAccess),
- "role": resources_core.FormatString(state.Role),
- "username": resources_core.FormatString(state.Username),
- }
- identityCodes := []string{
- "mtlsAccess",
- "role",
- "username",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("user", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "username": resources_core.FormatString(state.Username),
- })
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "delete_user", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *PostgresUserResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/91_redis_resource.go b/provider/internal/resources_gen/91_redis_resource.go
deleted file mode 100644
index 58f2336..0000000
--- a/provider/internal/resources_gen/91_redis_resource.go
+++ /dev/null
@@ -1,393 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "fmt"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: redis
-// Service ID: 91
-
-var _ resource.Resource = &RedisResource{}
-var _ resource.ResourceWithModifyPlan = &RedisResource{}
-var _ resource.ResourceWithImportState = &RedisResource{}
-
-type RedisResource struct {
- client *core.UniversalClient
-}
-
-// RedisAccessConfigurationModel — вложенная модель для map-fixed параметра accessConfiguration.
-type RedisAccessConfigurationModel struct {
- MasterIpSpace types.String `tfsdk:"master_ip_space" json:"masterIpSpace"`
- MasterAccessList types.String `tfsdk:"master_access_list" json:"masterAccessList"`
- SlaveIpSpace types.String `tfsdk:"slave_ip_space" json:"slaveIpSpace"`
- SlaveAccessList types.String `tfsdk:"slave_access_list" json:"slaveAccessList"`
-}
-
-// RedisClusterConfigurationModel — вложенная модель для map-fixed параметра clusterConfiguration.
-type RedisClusterConfigurationModel struct {
- Cpu types.Int64 `tfsdk:"cpu" json:"cpu"`
- Memory types.Int64 `tfsdk:"memory" json:"memory"`
- Replicas types.Int64 `tfsdk:"replicas" json:"replicas"`
- Disk types.Int64 `tfsdk:"disk" json:"disk"`
-}
-
-// RedisStartupConfigurationModel — вложенная модель для map-fixed параметра startupConfiguration.
-type RedisStartupConfigurationModel struct {
- ResourceRealm types.String `tfsdk:"resource_realm" json:"resourceRealm"`
-}
-
-type RedisModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- AccessConfiguration *RedisAccessConfigurationModel `tfsdk:"access_configuration"`
- ClusterConfiguration *RedisClusterConfigurationModel `tfsdk:"cluster_configuration"`
- StartupConfiguration *RedisStartupConfigurationModel `tfsdk:"startup_configuration"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewRedisResource() resource.Resource {
- return &RedisResource{}
-}
-
-func (r *RedisResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_redis"
-}
-
-func (r *RedisResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "access_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "master_ip_space": schema.StringAttribute{Required: true, MarkdownDescription: "Из какого Ip-Space резервировать внешний IP
Список предоставляется из Организации, в котором развёрнута ресурсная платформа"},
- "master_access_list": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[]"), MarkdownDescription: "Необходимо настраивать, когда зарезервирован внешний адрес
Если передан пустой массив, доступ выделяется всем"},
- "slave_ip_space": schema.StringAttribute{Required: true, MarkdownDescription: "Из какого Ip-Space резервировать внешний IP
Список предоставляется из Организации, в котором развёрнута ресурсная платформа"},
- "slave_access_list": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[]"), MarkdownDescription: "Необходимо настраивать, когда зарезервирован внешний адрес
Если передан пустой массив, доступ выделяется всем"},
- }},
- "cluster_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "cpu": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(500), MarkdownDescription: "Указывается в Milicores
`1000` Mili == `1` Ядро"},
- "memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(512), MarkdownDescription: "Указывается в Megabytes"},
- "replicas": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1)},
- "disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(10), MarkdownDescription: "Указывается в GIGAbytes"},
- }},
- "startup_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Кластер Kubernetes, на котором будет развернут экземпляр"},
- }},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *RedisResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *RedisModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *RedisModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan RedisModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 1061: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", config.StartupConfiguration.ResourceRealm.ValueString())}),
- 1062: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", config.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", config.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", config.ClusterConfiguration.Replicas.ValueInt64()), "disk": fmt.Sprintf("%d", config.ClusterConfiguration.Disk.ValueInt64())}),
- 1063: resources_core.BuildJSON(map[string]string{"masterIpSpace": fmt.Sprintf("\"%s\"", config.AccessConfiguration.MasterIpSpace.ValueString()), "masterAccessList": config.AccessConfiguration.MasterAccessList.ValueString(), "slaveIpSpace": fmt.Sprintf("\"%s\"", config.AccessConfiguration.SlaveIpSpace.ValueString()), "slaveAccessList": config.AccessConfiguration.SlaveAccessList.ValueString()}),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 91, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *RedisResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data RedisModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 91, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 1061: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", data.StartupConfiguration.ResourceRealm.ValueString())}),
- 1062: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", data.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", data.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", data.ClusterConfiguration.Replicas.ValueInt64()), "disk": fmt.Sprintf("%d", data.ClusterConfiguration.Disk.ValueInt64())}),
- 1063: resources_core.BuildJSON(map[string]string{"masterIpSpace": fmt.Sprintf("\"%s\"", data.AccessConfiguration.MasterIpSpace.ValueString()), "masterAccessList": data.AccessConfiguration.MasterAccessList.ValueString(), "slaveIpSpace": fmt.Sprintf("\"%s\"", data.AccessConfiguration.SlaveIpSpace.ValueString()), "slaveAccessList": data.AccessConfiguration.SlaveAccessList.ValueString()}),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 91, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 91, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *RedisResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state RedisModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 91, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *RedisResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan RedisModel
- var state RedisModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 1064: resources_core.BuildJSON(map[string]string{"replicas": fmt.Sprintf("%d", plan.ClusterConfiguration.Replicas.ValueInt64()), "disk": fmt.Sprintf("%d", plan.ClusterConfiguration.Disk.ValueInt64()), "cpu": fmt.Sprintf("%d", plan.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", plan.ClusterConfiguration.Memory.ValueInt64())}),
- 1065: resources_core.BuildJSON(map[string]string{"masterIpSpace": fmt.Sprintf("\"%s\"", plan.AccessConfiguration.MasterIpSpace.ValueString()), "masterAccessList": plan.AccessConfiguration.MasterAccessList.ValueString(), "slaveIpSpace": fmt.Sprintf("\"%s\"", plan.AccessConfiguration.SlaveIpSpace.ValueString()), "slaveAccessList": plan.AccessConfiguration.SlaveAccessList.ValueString()}),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 91, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *RedisResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state RedisModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *RedisResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *RedisResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/92_mongodb_resource.go b/provider/internal/resources_gen/92_mongodb_resource.go
deleted file mode 100644
index 81626ac..0000000
--- a/provider/internal/resources_gen/92_mongodb_resource.go
+++ /dev/null
@@ -1,389 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "fmt"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: mongodb
-// Service ID: 92
-
-var _ resource.Resource = &MongodbResource{}
-var _ resource.ResourceWithModifyPlan = &MongodbResource{}
-var _ resource.ResourceWithImportState = &MongodbResource{}
-
-type MongodbResource struct {
- client *core.UniversalClient
-}
-
-// MongodbAccessConfigurationModel — вложенная модель для map-fixed параметра accessConfiguration.
-type MongodbAccessConfigurationModel struct {
- MasterAccessList types.String `tfsdk:"master_access_list" json:"masterAccessList"`
- MasterIpSpace types.String `tfsdk:"master_ip_space" json:"masterIpSpace"`
-}
-
-// MongodbClusterConfigurationModel — вложенная модель для map-fixed параметра clusterConfiguration.
-type MongodbClusterConfigurationModel struct {
- Memory types.Int64 `tfsdk:"memory" json:"memory"`
- Replicas types.Int64 `tfsdk:"replicas" json:"replicas"`
- Disk types.Int64 `tfsdk:"disk" json:"disk"`
- Cpu types.Int64 `tfsdk:"cpu" json:"cpu"`
-}
-
-// MongodbStartupConfigurationModel — вложенная модель для map-fixed параметра startupConfiguration.
-type MongodbStartupConfigurationModel struct {
- ResourceRealm types.String `tfsdk:"resource_realm" json:"resourceRealm"`
-}
-
-type MongodbModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- AccessConfiguration *MongodbAccessConfigurationModel `tfsdk:"access_configuration"`
- ClusterConfiguration *MongodbClusterConfigurationModel `tfsdk:"cluster_configuration"`
- StartupConfiguration *MongodbStartupConfigurationModel `tfsdk:"startup_configuration"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewMongodbResource() resource.Resource {
- return &MongodbResource{}
-}
-
-func (r *MongodbResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_mongodb"
-}
-
-func (r *MongodbResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "access_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "master_access_list": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[]"), MarkdownDescription: "Необходимо настраивать, когда зарезервирован внешний адрес
Если передан пустой массив, доступ выделяется всем"},
- "master_ip_space": schema.StringAttribute{Required: true, MarkdownDescription: "Из какого Ip-Space резервировать внешний IP
Список предоставляется из Организации, в котором развёрнута ресурсная платформа"},
- }},
- "cluster_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1024)},
- "replicas": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1)},
- "disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(5), MarkdownDescription: "Указывается в Gb"},
- "cpu": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1000)},
- }},
- "startup_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Кластер Kubernetes, на котором будет развернут экземпляр"},
- }},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *MongodbResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *MongodbModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *MongodbModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan MongodbModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 1089: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", config.StartupConfiguration.ResourceRealm.ValueString())}),
- 1090: resources_core.BuildJSON(map[string]string{"memory": fmt.Sprintf("%d", config.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", config.ClusterConfiguration.Replicas.ValueInt64()), "disk": fmt.Sprintf("%d", config.ClusterConfiguration.Disk.ValueInt64()), "cpu": fmt.Sprintf("%d", config.ClusterConfiguration.Cpu.ValueInt64())}),
- 1091: resources_core.BuildJSON(map[string]string{"masterAccessList": config.AccessConfiguration.MasterAccessList.ValueString(), "masterIpSpace": fmt.Sprintf("\"%s\"", config.AccessConfiguration.MasterIpSpace.ValueString())}),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 92, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *MongodbResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data MongodbModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 92, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 1089: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", data.StartupConfiguration.ResourceRealm.ValueString())}),
- 1090: resources_core.BuildJSON(map[string]string{"memory": fmt.Sprintf("%d", data.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", data.ClusterConfiguration.Replicas.ValueInt64()), "disk": fmt.Sprintf("%d", data.ClusterConfiguration.Disk.ValueInt64()), "cpu": fmt.Sprintf("%d", data.ClusterConfiguration.Cpu.ValueInt64())}),
- 1091: resources_core.BuildJSON(map[string]string{"masterAccessList": data.AccessConfiguration.MasterAccessList.ValueString(), "masterIpSpace": fmt.Sprintf("\"%s\"", data.AccessConfiguration.MasterIpSpace.ValueString())}),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 92, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 92, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *MongodbResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state MongodbModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 92, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *MongodbResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan MongodbModel
- var state MongodbModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 1092: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", plan.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", plan.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", plan.ClusterConfiguration.Replicas.ValueInt64()), "disk": fmt.Sprintf("%d", plan.ClusterConfiguration.Disk.ValueInt64())}),
- 1093: resources_core.BuildJSON(map[string]string{"masterIpSpace": fmt.Sprintf("\"%s\"", plan.AccessConfiguration.MasterIpSpace.ValueString()), "masterAccessList": plan.AccessConfiguration.MasterAccessList.ValueString()}),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 92, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *MongodbResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state MongodbModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *MongodbResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *MongodbResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/92_mongodb_user_resource.go b/provider/internal/resources_gen/92_mongodb_user_resource.go
deleted file mode 100644
index 6f0e40d..0000000
--- a/provider/internal/resources_gen/92_mongodb_user_resource.go
+++ /dev/null
@@ -1,364 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: mongodb
-// Subresource: user
-
-var _ resource.Resource = &MongodbUserResource{}
-
-// MongodbUserResource manages a subresource via operations.
-type MongodbUserResource struct {
- client *core.UniversalClient
-}
-
-type MongodbUserModel struct {
- ID types.String `tfsdk:"id"`
- MongodbID types.String `tfsdk:"mongodb_id"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- SkipMissingOnDelete types.Bool `tfsdk:"skip_missing_on_delete"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- DbName types.String `tfsdk:"db_name"`
- Role types.String `tfsdk:"role"`
- Username types.String `tfsdk:"username"`
-}
-
-func NewMongodbUserResource() resource.Resource {
- return &MongodbUserResource{}
-}
-
-func (r *MongodbUserResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_mongodb_user"
-}
-
-func (r *MongodbUserResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "mongodb_id": schema.StringAttribute{
- Required: true,
- PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
- },
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "skip_missing_on_delete": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "db_name": schema.StringAttribute{Required: true},
- "role": schema.StringAttribute{Required: true},
- "username": schema.StringAttribute{Required: true, MarkdownDescription: "Изменение требует пересоздания.", PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}},
- }
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *MongodbUserResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var plan MongodbUserModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.DbName.IsNull() || plan.DbName.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "db_name is required.")
- return
- }
- if plan.Role.IsNull() || plan.Role.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "role is required.")
- return
- }
- if plan.Username.IsNull() || plan.Username.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "username is required.")
- return
- }
-
- instanceUID := strings.TrimSpace(plan.MongodbID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
- adoptExistingOnCreate := !plan.AdoptExistingOnCreate.IsNull() && !plan.AdoptExistingOnCreate.IsUnknown() && plan.AdoptExistingOnCreate.ValueBool()
-
- idParams := map[string]string{
- "username": resources_core.FormatString(plan.Username),
- }
- identityCodes := []string{
- "username",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("user", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- if adoptExistingOnCreate {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Объект уже есть, выполняется усыновление: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- resp.Diagnostics.AddError("Подресурс уже существует", "Найден объект с таким именем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "username": resources_core.FormatString(plan.Username),
- "dbName": resources_core.FormatString(plan.DbName),
- "role": resources_core.FormatString(plan.Role),
- })
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- createErr := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_user", params, operationTimeout)
- if createErr != nil && resources_core.IsSubresourceTransientDependencyError(createErr) {
- createErr = resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_user", params, operationTimeout)
- }
- if createErr != nil {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс подтверждён в state_out", "Операция create вернула ошибку, но объект найден в state_out и принят в state: "+targetValue)
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(createErr) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if found || !known {
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект принят в state")
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
- }
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в state_out")
- return
- }
- resp.Diagnostics.AddError("Ошибка клиента", createErr.Error())
- return
- }
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция create завершилась успешно, но объект не найден в state_out: "+targetValue)
- return
- }
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *MongodbUserResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state MongodbUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *MongodbUserResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan MongodbUserModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "modify_user" == "" {
- var state MongodbUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if plan.ID.IsNull() || plan.ID.IsUnknown() {
- plan.ID = state.ID
- }
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- instanceUID := strings.TrimSpace(plan.MongodbID.ValueString())
- if instanceUID == "" {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра")
- return
- }
-
- params := resources_core.CompactParams(map[string]string{
- "username": resources_core.FormatString(plan.Username),
- "dbName": resources_core.FormatString(plan.DbName),
- "role": resources_core.FormatString(plan.Role),
- })
-
- idParams := map[string]string{
- "username": resources_core.FormatString(plan.Username),
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "modify_user", params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams))
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
-}
-
-func (r *MongodbUserResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state MongodbUserModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- if "delete_user" == "" {
- return
- }
-
- instanceUID := strings.TrimSpace(state.MongodbID.ValueString())
- if instanceUID == "" {
- return
- }
- skipMissingOnDelete := !state.SkipMissingOnDelete.IsNull() && !state.SkipMissingOnDelete.IsUnknown() && state.SkipMissingOnDelete.ValueBool()
-
- idParams := map[string]string{
- "username": resources_core.FormatString(state.Username),
- }
- identityCodes := []string{
- "username",
- }
- listKey, idKey := resources_core.ResolveSubresourceStateKeys("user", identityCodes)
- targetValue := strings.TrimSpace(idParams[idKey])
- if targetValue == "" {
- for _, code := range identityCodes {
- candidate := strings.TrimSpace(idParams[code])
- if candidate == "" {
- continue
- }
- targetValue = candidate
- idKey = code
- break
- }
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && !found {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Объект уже удалён, пропускаем: "+targetValue)
- return
- }
- }
-
- params := resources_core.CompactParams(map[string]string{
- "username": resources_core.FormatString(state.Username),
- })
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "delete_user", params, operationTimeout); err != nil {
- if resources_core.IsSubresourceMissingError(err) {
- if targetValue != "" {
- found, known, checkErr := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if checkErr != nil {
- resp.Diagnostics.AddError("Ошибка клиента", checkErr.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete вернула not found, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
- if skipMissingOnDelete {
- resp.Diagnostics.AddWarning("Подресурс не найден", "Операция delete вернула not found, объект отсутствует в state_out, удаление пропущено")
- return
- }
- }
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- if targetValue != "" {
- found, known, err := resources_core.FindSubresourceInStateOut(ctx, r.client, instanceUID, listKey, idKey, targetValue)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if known && found {
- resp.Diagnostics.AddError("Нарушена консистентность", "Операция delete завершилась успешно, но объект всё ещё присутствует в state_out: "+targetValue)
- return
- }
- }
-}
-
-func (r *MongodbUserResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/93_rabbitmq_resource.go b/provider/internal/resources_gen/93_rabbitmq_resource.go
deleted file mode 100644
index a43cd4d..0000000
--- a/provider/internal/resources_gen/93_rabbitmq_resource.go
+++ /dev/null
@@ -1,474 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: rabbitmq
-// Service ID: 93
-
-var _ resource.Resource = &RabbitmqResource{}
-var _ resource.ResourceWithModifyPlan = &RabbitmqResource{}
-var _ resource.ResourceWithImportState = &RabbitmqResource{}
-
-type RabbitmqResource struct {
- client *core.UniversalClient
-}
-
-type RabbitmqModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- IpSpaceNameMaster types.String `tfsdk:"ip_space_name_master"`
- MasterAccessList types.String `tfsdk:"master_access_list"`
- ResourceCPU types.Int64 `tfsdk:"resource_c_p_u"`
- ResourceDisk types.Int64 `tfsdk:"resource_disk"`
- ResourceInstances types.Int64 `tfsdk:"resource_instances"`
- ResourceMemory types.Int64 `tfsdk:"resource_memory"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewRabbitmqResource() resource.Resource {
- return &RabbitmqResource{}
-}
-
-func (r *RabbitmqResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_rabbitmq"
-}
-
-func (r *RabbitmqResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "ip_space_name_master": schema.StringAttribute{Required: true, MarkdownDescription: "Пример: `internet-no-antiddos-v1`"},
- "master_access_list": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("[]"), MarkdownDescription: "Список IP-адресов, с которых разрешён доступ. Если оставить пустым — доступ открыт всем.", PlanModifiers: []planmodifier.String{resources_core.JsonNormalize()}},
- "resource_c_p_u": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1000), MarkdownDescription: "Пример: `2000`"},
- "resource_disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(30), MarkdownDescription: "Пример: `20`"},
- "resource_instances": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Пример: `1`"},
- "resource_memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1124), MarkdownDescription: "Пример: `2048`"},
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Выбрать платформу из списка Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *RabbitmqResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *RabbitmqModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *RabbitmqModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan RabbitmqModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.IpSpaceNameMaster.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "ip_space_name_master is required.")
- return
- }
- if config.IpSpaceNameMaster.IsUnknown() {
- return
- }
- if config.ResourceRealm.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
- if config.ResourceRealm.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 116: resources_core.FormatInt64(config.ResourceCPU),
- 117: resources_core.FormatInt64(config.ResourceMemory),
- 118: resources_core.FormatInt64(config.ResourceDisk),
- 119: resources_core.FormatString(config.ResourceRealm),
- 224: resources_core.FormatInt64(config.ResourceInstances),
- 225: resources_core.FormatString(config.MasterAccessList),
- 543: resources_core.FormatString(config.IpSpaceNameMaster),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 93, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *RabbitmqResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data RabbitmqModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.IpSpaceNameMaster.IsNull() || data.IpSpaceNameMaster.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "ip_space_name_master is required.")
- return
- }
- if data.ResourceRealm.IsNull() || data.ResourceRealm.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 93, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 116: resources_core.FormatInt64(data.ResourceCPU),
- 117: resources_core.FormatInt64(data.ResourceMemory),
- 118: resources_core.FormatInt64(data.ResourceDisk),
- 119: resources_core.FormatString(data.ResourceRealm),
- 224: resources_core.FormatInt64(data.ResourceInstances),
- 225: resources_core.FormatString(data.MasterAccessList),
- 543: resources_core.FormatString(data.IpSpaceNameMaster),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 93, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 93, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "ipSpaceNameMaster", Field: "IpSpaceNameMaster", Type: "string"},
- {Code: "masterAccessList", Field: "MasterAccessList", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *RabbitmqResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state RabbitmqModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 93, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "ipSpaceNameMaster", Field: "IpSpaceNameMaster", Type: "string"},
- {Code: "masterAccessList", Field: "MasterAccessList", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *RabbitmqResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan RabbitmqModel
- var state RabbitmqModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.ResourceCPU.IsNull() != state.ResourceCPU.IsNull() || plan.ResourceCPU.IsUnknown() != state.ResourceCPU.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceCPU.IsNull() && !plan.ResourceCPU.IsUnknown() && !state.ResourceCPU.IsNull() && !state.ResourceCPU.IsUnknown() {
- if plan.ResourceCPU.ValueInt64() != state.ResourceCPU.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.ResourceMemory.IsNull() != state.ResourceMemory.IsNull() || plan.ResourceMemory.IsUnknown() != state.ResourceMemory.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceMemory.IsNull() && !plan.ResourceMemory.IsUnknown() && !state.ResourceMemory.IsNull() && !state.ResourceMemory.IsUnknown() {
- if plan.ResourceMemory.ValueInt64() != state.ResourceMemory.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.ResourceDisk.IsNull() != state.ResourceDisk.IsNull() || plan.ResourceDisk.IsUnknown() != state.ResourceDisk.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceDisk.IsNull() && !plan.ResourceDisk.IsUnknown() && !state.ResourceDisk.IsNull() && !state.ResourceDisk.IsUnknown() {
- if plan.ResourceDisk.ValueInt64() != state.ResourceDisk.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.ResourceInstances.IsNull() != state.ResourceInstances.IsNull() || plan.ResourceInstances.IsUnknown() != state.ResourceInstances.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceInstances.IsNull() && !plan.ResourceInstances.IsUnknown() && !state.ResourceInstances.IsNull() && !state.ResourceInstances.IsUnknown() {
- if plan.ResourceInstances.ValueInt64() != state.ResourceInstances.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.MasterAccessList.IsNull() != state.MasterAccessList.IsNull() || plan.MasterAccessList.IsUnknown() != state.MasterAccessList.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.MasterAccessList.IsNull() && !plan.MasterAccessList.IsUnknown() && !state.MasterAccessList.IsNull() && !state.MasterAccessList.IsUnknown() {
- if !strings.EqualFold(plan.MasterAccessList.ValueString(), state.MasterAccessList.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.IpSpaceNameMaster.IsNull() != state.IpSpaceNameMaster.IsNull() || plan.IpSpaceNameMaster.IsUnknown() != state.IpSpaceNameMaster.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.IpSpaceNameMaster.IsNull() && !plan.IpSpaceNameMaster.IsUnknown() && !state.IpSpaceNameMaster.IsNull() && !state.IpSpaceNameMaster.IsUnknown() {
- if !strings.EqualFold(plan.IpSpaceNameMaster.ValueString(), state.IpSpaceNameMaster.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 304: resources_core.FormatInt64(plan.ResourceCPU),
- 305: resources_core.FormatInt64(plan.ResourceMemory),
- 306: resources_core.FormatInt64(plan.ResourceDisk),
- 307: resources_core.FormatInt64(plan.ResourceInstances),
- 308: resources_core.FormatString(plan.MasterAccessList),
- 545: resources_core.FormatString(plan.IpSpaceNameMaster),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 93, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "ipSpaceNameMaster", Field: "IpSpaceNameMaster", Type: "string"},
- {Code: "masterAccessList", Field: "MasterAccessList", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *RabbitmqResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state RabbitmqModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *RabbitmqResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *RabbitmqResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/94_lucee_resource.go b/provider/internal/resources_gen/94_lucee_resource.go
deleted file mode 100644
index d78129f..0000000
--- a/provider/internal/resources_gen/94_lucee_resource.go
+++ /dev/null
@@ -1,449 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "fmt"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: lucee
-// Service ID: 94
-
-var _ resource.Resource = &LuceeResource{}
-var _ resource.ResourceWithModifyPlan = &LuceeResource{}
-var _ resource.ResourceWithImportState = &LuceeResource{}
-
-type LuceeResource struct {
- client *core.UniversalClient
-}
-
-// LuceeAccessConfigurationModel — вложенная модель для map-fixed параметра accessConfiguration.
-type LuceeAccessConfigurationModel struct {
- Domain types.String `tfsdk:"domain" json:"domain"`
-}
-
-// LuceeAppConfigurationModel — вложенная модель для map-fixed параметра appConfiguration.
-type LuceeAppConfigurationModel struct {
- Version types.String `tfsdk:"version" json:"version"`
- GitPath types.String `tfsdk:"git_path" json:"gitPath"`
- HealthPath types.String `tfsdk:"health_path" json:"healthPath"`
-}
-
-// LuceeClusterConfigurationModel — вложенная модель для map-fixed параметра clusterConfiguration.
-type LuceeClusterConfigurationModel struct {
- Cpu types.Int64 `tfsdk:"cpu" json:"cpu"`
- Memory types.Int64 `tfsdk:"memory" json:"memory"`
- Replicas types.Int64 `tfsdk:"replicas" json:"replicas"`
-}
-
-// LuceeStartupConfigurationModel — вложенная модель для map-fixed параметра startupConfiguration.
-type LuceeStartupConfigurationModel struct {
- ResourceRealm types.String `tfsdk:"resource_realm" json:"resourceRealm"`
-}
-
-type LuceeModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- // --- Redeploy support (ARCHITECTURE.md) ---
- // git_revision: при изменении вызывает redeploy вместо modify.
- // Опциональное поле — если не задано, modify работает как обычно.
- GitRevision types.String `tfsdk:"git_revision"`
- AccessConfiguration *LuceeAccessConfigurationModel `tfsdk:"access_configuration"`
- AppConfiguration *LuceeAppConfigurationModel `tfsdk:"app_configuration"`
- ClusterConfiguration *LuceeClusterConfigurationModel `tfsdk:"cluster_configuration"`
- JsonEnv types.String `tfsdk:"json_env"`
- StartupConfiguration *LuceeStartupConfigurationModel `tfsdk:"startup_configuration"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewLuceeResource() resource.Resource {
- return &LuceeResource{}
-}
-
-func (r *LuceeResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_lucee"
-}
-
-func (r *LuceeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "access_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("lucee-kctea8wd"), MarkdownDescription: "Если указан FQDN в формате: `myapp.example.com`, предварительно будет проверяться DNS-запись (А-запись **должна смотреть на IP Ingress кластера ресурсной платформы**)
Если указан в формате `myapp`, DNS-запись будет автоматически создана в служебной DNS-зоне"},
- }},
- "app_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "version": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("6.0")},
- "git_path": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("https://github.com/xahys/testlucee"), MarkdownDescription: "Путь до репозитория приложения
Обязательно должен быть передан как URL: `https://....`
Должен быть сетевой доступ до URL для скачивания исходников"},
- "health_path": schema.StringAttribute{Optional: true, MarkdownDescription: "Путь до healtcheck для запуска пода в Kubernetes, который отдаст 200 код
Пустое значение означает, что будет проверяться исключительно доступность приложения по порту"},
- }},
- "cluster_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "cpu": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(200), MarkdownDescription: "Указывается в Milicores
`1000` Mili == `1` Ядро"},
- "memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(256), MarkdownDescription: "Указывается в Megabytes"},
- "replicas": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1)},
- }},
- "json_env": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("{}"), MarkdownDescription: "Передаётся в формате КЛЮЧ:ЗНАЧЕНИЕ"},
- "startup_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Кластер Kubernetes, на котором будет развернут экземпляр"},
- }},
- // --- Redeploy support (ARCHITECTURE.md) ---
- // При изменении git_revision вызывается redeploy вместо modify.
- // Если не задано — modify работает без изменений.
- "git_revision": schema.StringAttribute{Optional: true, MarkdownDescription: "Git revision (commit hash/tag). Changing this triggers redeploy instead of modify."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *LuceeResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *LuceeModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *LuceeModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan LuceeModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 1019: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", config.StartupConfiguration.ResourceRealm.ValueString())}),
- 1020: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", config.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", config.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", config.ClusterConfiguration.Replicas.ValueInt64())}),
- 1021: resources_core.BuildJSON(map[string]string{"domain": fmt.Sprintf("\"%s\"", config.AccessConfiguration.Domain.ValueString())}),
- 1022: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", config.AppConfiguration.Version.ValueString()), "gitPath": fmt.Sprintf("\"%s\"", config.AppConfiguration.GitPath.ValueString()), "healthPath": fmt.Sprintf("\"%s\"", config.AppConfiguration.HealthPath.ValueString())}),
- 1023: resources_core.FormatString(config.JsonEnv),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 94, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *LuceeResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data LuceeModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 94, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 1019: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", data.StartupConfiguration.ResourceRealm.ValueString())}),
- 1020: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", data.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", data.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", data.ClusterConfiguration.Replicas.ValueInt64())}),
- 1021: resources_core.BuildJSON(map[string]string{"domain": fmt.Sprintf("\"%s\"", data.AccessConfiguration.Domain.ValueString())}),
- 1022: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", data.AppConfiguration.Version.ValueString()), "gitPath": fmt.Sprintf("\"%s\"", data.AppConfiguration.GitPath.ValueString()), "healthPath": fmt.Sprintf("\"%s\"", data.AppConfiguration.HealthPath.ValueString())}),
- 1023: resources_core.FormatString(data.JsonEnv),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 94, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 94, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "appConfiguration", Field: "AppConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "jsonEnv", Field: "JsonEnv", Type: "string"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *LuceeResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state LuceeModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 94, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "appConfiguration", Field: "AppConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "jsonEnv", Field: "JsonEnv", Type: "string"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *LuceeResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan LuceeModel
- var state LuceeModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.JsonEnv.IsNull() != state.JsonEnv.IsNull() || plan.JsonEnv.IsUnknown() != state.JsonEnv.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.JsonEnv.IsNull() && !plan.JsonEnv.IsUnknown() && !state.JsonEnv.IsNull() && !state.JsonEnv.IsUnknown() {
- if !strings.EqualFold(plan.JsonEnv.ValueString(), state.JsonEnv.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
- // --- Redeploy support (ARCHITECTURE.md) ---
- // Проверяем изменился ли git_revision.
- // Если да — вызываем redeploy вместо modify.
- // git_revision = "" (не задано) → обычный modify.
- redeployRequested := false
- if !plan.GitRevision.IsNull() && !plan.GitRevision.IsUnknown() {
- if state.GitRevision.IsNull() || state.GitRevision.IsUnknown() || plan.GitRevision.ValueString() != state.GitRevision.ValueString() {
- redeployRequested = true
- }
- }
-
- if !hasServiceParamChanges && !redeployRequested {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- // --- Redeploy support (ARCHITECTURE.md) ---
- if redeployRequested {
- // Вызываем redeploy — пустой params (операция не требует CFS-параметров)
- if err := r.client.RunRedeployOperation(ctx, instanceID.ValueString(), operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- } else {
- params := map[int]string{
- 1024: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", plan.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", plan.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", plan.ClusterConfiguration.Replicas.ValueInt64())}),
- 1025: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", plan.AppConfiguration.Version.ValueString()), "gitPath": fmt.Sprintf("\"%s\"", plan.AppConfiguration.GitPath.ValueString()), "healthPath": fmt.Sprintf("\"%s\"", plan.AppConfiguration.HealthPath.ValueString())}),
- 1026: resources_core.FormatString(plan.JsonEnv),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 94, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "appConfiguration", Field: "AppConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "jsonEnv", Field: "JsonEnv", Type: "string"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *LuceeResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state LuceeModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *LuceeResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *LuceeResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/95_nodejs_resource.go b/provider/internal/resources_gen/95_nodejs_resource.go
deleted file mode 100644
index 10900b8..0000000
--- a/provider/internal/resources_gen/95_nodejs_resource.go
+++ /dev/null
@@ -1,449 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "fmt"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: nodejs
-// Service ID: 95
-
-var _ resource.Resource = &NodejsResource{}
-var _ resource.ResourceWithModifyPlan = &NodejsResource{}
-var _ resource.ResourceWithImportState = &NodejsResource{}
-
-type NodejsResource struct {
- client *core.UniversalClient
-}
-
-// NodejsAccessConfigurationModel — вложенная модель для map-fixed параметра accessConfiguration.
-type NodejsAccessConfigurationModel struct {
- Domain types.String `tfsdk:"domain" json:"domain"`
-}
-
-// NodejsAppConfigurationModel — вложенная модель для map-fixed параметра appConfiguration.
-type NodejsAppConfigurationModel struct {
- Version types.String `tfsdk:"version" json:"version"`
- GitPath types.String `tfsdk:"git_path" json:"gitPath"`
- HealthPath types.String `tfsdk:"health_path" json:"healthPath"`
-}
-
-// NodejsClusterConfigurationModel — вложенная модель для map-fixed параметра clusterConfiguration.
-type NodejsClusterConfigurationModel struct {
- Cpu types.Int64 `tfsdk:"cpu" json:"cpu"`
- Memory types.Int64 `tfsdk:"memory" json:"memory"`
- Replicas types.Int64 `tfsdk:"replicas" json:"replicas"`
-}
-
-// NodejsStartupConfigurationModel — вложенная модель для map-fixed параметра startupConfiguration.
-type NodejsStartupConfigurationModel struct {
- ResourceRealm types.String `tfsdk:"resource_realm" json:"resourceRealm"`
-}
-
-type NodejsModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- // --- Redeploy support (ARCHITECTURE.md) ---
- // git_revision: при изменении вызывает redeploy вместо modify.
- // Опциональное поле — если не задано, modify работает как обычно.
- GitRevision types.String `tfsdk:"git_revision"`
- AccessConfiguration *NodejsAccessConfigurationModel `tfsdk:"access_configuration"`
- AppConfiguration *NodejsAppConfigurationModel `tfsdk:"app_configuration"`
- ClusterConfiguration *NodejsClusterConfigurationModel `tfsdk:"cluster_configuration"`
- JsonEnv types.String `tfsdk:"json_env"`
- StartupConfiguration *NodejsStartupConfigurationModel `tfsdk:"startup_configuration"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewNodejsResource() resource.Resource {
- return &NodejsResource{}
-}
-
-func (r *NodejsResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_nodejs"
-}
-
-func (r *NodejsResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "access_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("node-bd1l2h8o"), MarkdownDescription: "Если указан FQDN в формате: `myapp.example.com`, предварительно будет проверяться DNS-запись (А-запись **должна смотреть на IP Ingress кластера ресурсной платформы**)
Если указан в формате `myapp`, DNS-запись будет автоматически создана в служебной DNS-зоне"},
- }},
- "app_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "version": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("23")},
- "git_path": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("https://github.com/xahys/testnode.git"), MarkdownDescription: "Путь до репозитория приложения
Обязательно должен быть передан как URL: `https://....`
Должен быть сетевой доступ до URL для скачивания исходников"},
- "health_path": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("1"), MarkdownDescription: "Путь до healtcheck для запуска пода в Kubernetes, который отдаст 200 код
Пустое значение означает, что будет проверяться исключительно доступность приложения по порту"},
- }},
- "cluster_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "cpu": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(200), MarkdownDescription: "Указывается в Milicores
`1000` Mili == `1` Ядро"},
- "memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(256), MarkdownDescription: "Указывается в Megabytes"},
- "replicas": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1)},
- }},
- "json_env": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("{}"), MarkdownDescription: "Передаётся в формате КЛЮЧ:ЗНАЧЕНИЕ"},
- "startup_configuration": schema.SingleNestedAttribute{Required: true,
- Attributes: map[string]schema.Attribute{
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Кластер Kubernetes, на котором будет развернут экземпляр"},
- }},
- // --- Redeploy support (ARCHITECTURE.md) ---
- // При изменении git_revision вызывается redeploy вместо modify.
- // Если не задано — modify работает без изменений.
- "git_revision": schema.StringAttribute{Optional: true, MarkdownDescription: "Git revision (commit hash/tag). Changing this triggers redeploy instead of modify."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *NodejsResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *NodejsModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *NodejsModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan NodejsModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 1028: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", config.StartupConfiguration.ResourceRealm.ValueString())}),
- 1029: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", config.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", config.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", config.ClusterConfiguration.Replicas.ValueInt64())}),
- 1030: resources_core.BuildJSON(map[string]string{"domain": fmt.Sprintf("\"%s\"", config.AccessConfiguration.Domain.ValueString())}),
- 1031: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", config.AppConfiguration.Version.ValueString()), "gitPath": fmt.Sprintf("\"%s\"", config.AppConfiguration.GitPath.ValueString()), "healthPath": fmt.Sprintf("\"%s\"", config.AppConfiguration.HealthPath.ValueString())}),
- 1032: resources_core.FormatString(config.JsonEnv),
- }
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 95, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *NodejsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data NodejsModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 95, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 1028: resources_core.BuildJSON(map[string]string{"resourceRealm": fmt.Sprintf("\"%s\"", data.StartupConfiguration.ResourceRealm.ValueString())}),
- 1029: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", data.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", data.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", data.ClusterConfiguration.Replicas.ValueInt64())}),
- 1030: resources_core.BuildJSON(map[string]string{"domain": fmt.Sprintf("\"%s\"", data.AccessConfiguration.Domain.ValueString())}),
- 1031: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", data.AppConfiguration.Version.ValueString()), "gitPath": fmt.Sprintf("\"%s\"", data.AppConfiguration.GitPath.ValueString()), "healthPath": fmt.Sprintf("\"%s\"", data.AppConfiguration.HealthPath.ValueString())}),
- 1032: resources_core.FormatString(data.JsonEnv),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 95, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 95, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "appConfiguration", Field: "AppConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "jsonEnv", Field: "JsonEnv", Type: "string"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *NodejsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state NodejsModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 95, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "appConfiguration", Field: "AppConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "jsonEnv", Field: "JsonEnv", Type: "string"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *NodejsResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan NodejsModel
- var state NodejsModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.JsonEnv.IsNull() != state.JsonEnv.IsNull() || plan.JsonEnv.IsUnknown() != state.JsonEnv.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.JsonEnv.IsNull() && !plan.JsonEnv.IsUnknown() && !state.JsonEnv.IsNull() && !state.JsonEnv.IsUnknown() {
- if !strings.EqualFold(plan.JsonEnv.ValueString(), state.JsonEnv.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
- // --- Redeploy support (ARCHITECTURE.md) ---
- // Проверяем изменился ли git_revision.
- // Если да — вызываем redeploy вместо modify.
- // git_revision = "" (не задано) → обычный modify.
- redeployRequested := false
- if !plan.GitRevision.IsNull() && !plan.GitRevision.IsUnknown() {
- if state.GitRevision.IsNull() || state.GitRevision.IsUnknown() || plan.GitRevision.ValueString() != state.GitRevision.ValueString() {
- redeployRequested = true
- }
- }
-
- if !hasServiceParamChanges && !redeployRequested {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- // --- Redeploy support (ARCHITECTURE.md) ---
- if redeployRequested {
- // Вызываем redeploy — пустой params (операция не требует CFS-параметров)
- if err := r.client.RunRedeployOperation(ctx, instanceID.ValueString(), operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- } else {
- params := map[int]string{
- 1033: resources_core.BuildJSON(map[string]string{"cpu": fmt.Sprintf("%d", plan.ClusterConfiguration.Cpu.ValueInt64()), "memory": fmt.Sprintf("%d", plan.ClusterConfiguration.Memory.ValueInt64()), "replicas": fmt.Sprintf("%d", plan.ClusterConfiguration.Replicas.ValueInt64())}),
- 1034: resources_core.BuildJSON(map[string]string{"version": fmt.Sprintf("\"%s\"", plan.AppConfiguration.Version.ValueString()), "gitPath": fmt.Sprintf("\"%s\"", plan.AppConfiguration.GitPath.ValueString()), "healthPath": fmt.Sprintf("\"%s\"", plan.AppConfiguration.HealthPath.ValueString())}),
- 1035: resources_core.FormatString(plan.JsonEnv),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 95, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "accessConfiguration", Field: "AccessConfiguration", Type: "map-fixed"},
- {Code: "appConfiguration", Field: "AppConfiguration", Type: "map-fixed"},
- {Code: "clusterConfiguration", Field: "ClusterConfiguration", Type: "map-fixed"},
- {Code: "jsonEnv", Field: "JsonEnv", Type: "string"},
- {Code: "startupConfiguration", Field: "StartupConfiguration", Type: "map-fixed"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *NodejsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state NodejsModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *NodejsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *NodejsResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/96_pgadmin_resource.go b/provider/internal/resources_gen/96_pgadmin_resource.go
deleted file mode 100644
index aac4518..0000000
--- a/provider/internal/resources_gen/96_pgadmin_resource.go
+++ /dev/null
@@ -1,515 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: pgadmin
-// Service ID: 96
-
-var _ resource.Resource = &PgadminResource{}
-var _ resource.ResourceWithModifyPlan = &PgadminResource{}
-var _ resource.ResourceWithImportState = &PgadminResource{}
-
-type PgadminResource struct {
- client *core.UniversalClient
-}
-
-type PgadminModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- // --- Redeploy support (ARCHITECTURE.md) ---
- // git_revision: при изменении вызывает redeploy вместо modify.
- // Опциональное поле — если не задано, modify работает как обычно.
- GitRevision types.String `tfsdk:"git_revision"`
- Domain types.String `tfsdk:"domain"`
- Login types.String `tfsdk:"login"`
- Password types.String `tfsdk:"password"`
- ResourceCPU types.Int64 `tfsdk:"resource_c_p_u"`
- ResourceDisk types.Int64 `tfsdk:"resource_disk"`
- ResourceMemory types.Int64 `tfsdk:"resource_memory"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewPgadminResource() resource.Resource {
- return &PgadminResource{}
-}
-
-func (r *PgadminResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_pgadmin"
-}
-
-func (r *PgadminResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("pgadmin-1"), MarkdownDescription: "Если будет указан FQDN, то происходят проверки DNS на валидность А-записи, или будет добавлено в зону resourceRealm Не изменяется после создания."},
- "login": schema.StringAttribute{Required: true, MarkdownDescription: "Логин для подключения к pgAdmin, в формате email (login@email.net) Не изменяется после создания."},
- "password": schema.StringAttribute{Required: true, MarkdownDescription: "Пароль для подключения к pgAdmin Не изменяется после создания.", Sensitive: true},
- "resource_c_p_u": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(500), MarkdownDescription: "Квота ядра пода (milicores). 1000Mili = 1 Ядро"},
- "resource_disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Квота диска (Указывается в GIGAbytes)"},
- "resource_memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(512), MarkdownDescription: "Квота памяти пода (MBytes)"},
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Платформа для развертывания Не изменяется после создания."},
- // --- Redeploy support (ARCHITECTURE.md) ---
- // При изменении git_revision вызывается redeploy вместо modify.
- // Если не задано — modify работает без изменений.
- "git_revision": schema.StringAttribute{Optional: true, MarkdownDescription: "Git revision (commit hash/tag). Changing this triggers redeploy instead of modify."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *PgadminResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *PgadminModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *PgadminModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan PgadminModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.Domain.IsNull() && !plan.Domain.IsUnknown() && !state.Domain.IsNull() && !state.Domain.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.Domain.ValueString(), state.Domain.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить domain", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.Login.IsNull() && !plan.Login.IsUnknown() && !state.Login.IsNull() && !state.Login.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.Login.ValueString(), state.Login.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить login", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.Password.IsNull() && !plan.Password.IsUnknown() && !state.Password.IsNull() && !state.Password.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.Password.ValueString(), state.Password.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить password", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.Login.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "login is required.")
- return
- }
- if config.Login.IsUnknown() {
- return
- }
- if config.Password.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "password is required.")
- return
- }
- if config.Password.IsUnknown() {
- return
- }
- if config.ResourceRealm.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
- if config.ResourceRealm.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 164: resources_core.FormatString(config.Domain),
- 165: resources_core.FormatInt64(config.ResourceCPU),
- 166: resources_core.FormatInt64(config.ResourceMemory),
- 167: resources_core.FormatInt64(config.ResourceDisk),
- 169: resources_core.FormatString(config.ResourceRealm),
- 170: resources_core.FormatString(config.Login),
- 171: resources_core.FormatString(config.Password),
- }
- desiredDomain := ""
- if !config.Domain.IsNull() && !config.Domain.IsUnknown() {
- desiredDomain = config.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 96, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *PgadminResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data PgadminModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.Login.IsNull() || data.Login.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "login is required.")
- return
- }
- if data.Password.IsNull() || data.Password.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "password is required.")
- return
- }
- if data.ResourceRealm.IsNull() || data.ResourceRealm.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- if !data.Domain.IsNull() && !data.Domain.IsUnknown() {
- desiredDomain = data.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 96, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 164: resources_core.FormatString(data.Domain),
- 165: resources_core.FormatInt64(data.ResourceCPU),
- 166: resources_core.FormatInt64(data.ResourceMemory),
- 167: resources_core.FormatInt64(data.ResourceDisk),
- 169: resources_core.FormatString(data.ResourceRealm),
- 170: resources_core.FormatString(data.Login),
- 171: resources_core.FormatString(data.Password),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 96, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 96, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "login", Field: "Login", Type: "string"},
- {Code: "password", Field: "Password", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *PgadminResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state PgadminModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 96, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "login", Field: "Login", Type: "string"},
- {Code: "password", Field: "Password", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *PgadminResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan PgadminModel
- var state PgadminModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.ResourceCPU.IsNull() != state.ResourceCPU.IsNull() || plan.ResourceCPU.IsUnknown() != state.ResourceCPU.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceCPU.IsNull() && !plan.ResourceCPU.IsUnknown() && !state.ResourceCPU.IsNull() && !state.ResourceCPU.IsUnknown() {
- if plan.ResourceCPU.ValueInt64() != state.ResourceCPU.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.ResourceMemory.IsNull() != state.ResourceMemory.IsNull() || plan.ResourceMemory.IsUnknown() != state.ResourceMemory.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceMemory.IsNull() && !plan.ResourceMemory.IsUnknown() && !state.ResourceMemory.IsNull() && !state.ResourceMemory.IsUnknown() {
- if plan.ResourceMemory.ValueInt64() != state.ResourceMemory.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.ResourceDisk.IsNull() != state.ResourceDisk.IsNull() || plan.ResourceDisk.IsUnknown() != state.ResourceDisk.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceDisk.IsNull() && !plan.ResourceDisk.IsUnknown() && !state.ResourceDisk.IsNull() && !state.ResourceDisk.IsUnknown() {
- if plan.ResourceDisk.ValueInt64() != state.ResourceDisk.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- // --- Redeploy support (ARCHITECTURE.md) ---
- // Проверяем изменился ли git_revision.
- // Если да — вызываем redeploy вместо modify.
- // git_revision = "" (не задано) → обычный modify.
- redeployRequested := false
- if !plan.GitRevision.IsNull() && !plan.GitRevision.IsUnknown() {
- if state.GitRevision.IsNull() || state.GitRevision.IsUnknown() || plan.GitRevision.ValueString() != state.GitRevision.ValueString() {
- redeployRequested = true
- }
- }
-
- if !hasServiceParamChanges && !redeployRequested {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- // --- Redeploy support (ARCHITECTURE.md) ---
- if redeployRequested {
- // Вызываем redeploy — пустой params (операция не требует CFS-параметров)
- if err := r.client.RunRedeployOperation(ctx, instanceID.ValueString(), operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- } else {
- params := map[int]string{
- 172: resources_core.FormatInt64(plan.ResourceCPU),
- 173: resources_core.FormatInt64(plan.ResourceMemory),
- 174: resources_core.FormatInt64(plan.ResourceDisk),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 96, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "login", Field: "Login", Type: "string"},
- {Code: "password", Field: "Password", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *PgadminResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state PgadminModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *PgadminResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *PgadminResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/97_nodered_resource.go b/provider/internal/resources_gen/97_nodered_resource.go
deleted file mode 100644
index 7b00a75..0000000
--- a/provider/internal/resources_gen/97_nodered_resource.go
+++ /dev/null
@@ -1,431 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: nodered
-// Service ID: 97
-
-var _ resource.Resource = &NoderedResource{}
-var _ resource.ResourceWithModifyPlan = &NoderedResource{}
-var _ resource.ResourceWithImportState = &NoderedResource{}
-
-type NoderedResource struct {
- client *core.UniversalClient
-}
-
-type NoderedModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- Domain types.String `tfsdk:"domain"`
- ResourceCPU types.Int64 `tfsdk:"resource_c_p_u"`
- ResourceDisk types.Int64 `tfsdk:"resource_disk"`
- ResourceInstances types.Int64 `tfsdk:"resource_instances"`
- ResourceMemory types.Int64 `tfsdk:"resource_memory"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewNoderedResource() resource.Resource {
- return &NoderedResource{}
-}
-
-func (r *NoderedResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_nodered"
-}
-
-func (r *NoderedResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("nodered-1"), MarkdownDescription: "Наименование поддомена, будет добавлено в k8stemplate.dev.nubes.ru Не изменяется после создания."},
- "resource_c_p_u": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(500), MarkdownDescription: "Квота ядра пода (Указывается в mili). 1000Mili = 1 Ядро Не изменяется после создания."},
- "resource_disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Квота диска (Указывается в GIGAbytes) Не изменяется после создания."},
- "resource_instances": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Количество узлов Не изменяется после создания."},
- "resource_memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(512), MarkdownDescription: "Квота памяти пода (Указывается в Megabytes) Не изменяется после создания."},
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Платформа для развертывания Не изменяется после создания."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *NoderedResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *NoderedModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *NoderedModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan NoderedModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.Domain.IsNull() && !plan.Domain.IsUnknown() && !state.Domain.IsNull() && !state.Domain.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.Domain.ValueString(), state.Domain.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить domain", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceCPU.IsNull() && !plan.ResourceCPU.IsUnknown() && !state.ResourceCPU.IsNull() && !state.ResourceCPU.IsUnknown() {
- if plan.ResourceCPU.ValueInt64() != state.ResourceCPU.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить resource_c_p_u", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceDisk.IsNull() && !plan.ResourceDisk.IsUnknown() && !state.ResourceDisk.IsNull() && !state.ResourceDisk.IsUnknown() {
- if plan.ResourceDisk.ValueInt64() != state.ResourceDisk.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить resource_disk", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceInstances.IsNull() && !plan.ResourceInstances.IsUnknown() && !state.ResourceInstances.IsNull() && !state.ResourceInstances.IsUnknown() {
- if plan.ResourceInstances.ValueInt64() != state.ResourceInstances.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить resource_instances", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceMemory.IsNull() && !plan.ResourceMemory.IsUnknown() && !state.ResourceMemory.IsNull() && !state.ResourceMemory.IsUnknown() {
- if plan.ResourceMemory.ValueInt64() != state.ResourceMemory.ValueInt64() {
- resp.Diagnostics.AddError("Нельзя изменить resource_memory", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.ResourceRealm.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
- if config.ResourceRealm.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 193: resources_core.FormatInt64(config.ResourceCPU),
- 194: resources_core.FormatInt64(config.ResourceMemory),
- 195: resources_core.FormatInt64(config.ResourceDisk),
- 196: resources_core.FormatString(config.ResourceRealm),
- 197: resources_core.FormatString(config.Domain),
- 323: resources_core.FormatInt64(config.ResourceInstances),
- }
- desiredDomain := ""
- if !config.Domain.IsNull() && !config.Domain.IsUnknown() {
- desiredDomain = config.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 97, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *NoderedResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data NoderedModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.ResourceRealm.IsNull() || data.ResourceRealm.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- if !data.Domain.IsNull() && !data.Domain.IsUnknown() {
- desiredDomain = data.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 97, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 193: resources_core.FormatInt64(data.ResourceCPU),
- 194: resources_core.FormatInt64(data.ResourceMemory),
- 195: resources_core.FormatInt64(data.ResourceDisk),
- 196: resources_core.FormatString(data.ResourceRealm),
- 197: resources_core.FormatString(data.Domain),
- 323: resources_core.FormatInt64(data.ResourceInstances),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 97, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 97, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *NoderedResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state NoderedModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 97, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *NoderedResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan NoderedModel
- var state NoderedModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{}
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 97, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *NoderedResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state NoderedModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "delete"
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *NoderedResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *NoderedResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/98_http_resource.go b/provider/internal/resources_gen/98_http_resource.go
deleted file mode 100644
index 5d287fa..0000000
--- a/provider/internal/resources_gen/98_http_resource.go
+++ /dev/null
@@ -1,509 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: http
-// Service ID: 98
-
-var _ resource.Resource = &HttpResource{}
-var _ resource.ResourceWithModifyPlan = &HttpResource{}
-var _ resource.ResourceWithImportState = &HttpResource{}
-
-type HttpResource struct {
- client *core.UniversalClient
-}
-
-type HttpModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- // --- Redeploy support (ARCHITECTURE.md) ---
- // git_revision: при изменении вызывает redeploy вместо modify.
- // Опциональное поле — если не задано, modify работает как обычно.
- GitRevision types.String `tfsdk:"git_revision"`
- Domain types.String `tfsdk:"domain"`
- IngressAnnotations types.String `tfsdk:"ingress_annotations"`
- JsonEnv types.String `tfsdk:"json_env"`
- RegistryPath types.String `tfsdk:"registry_path"`
- ResourceCPU types.Int64 `tfsdk:"resource_c_p_u"`
- ResourceInstances types.Int64 `tfsdk:"resource_instances"`
- ResourceMemory types.Int64 `tfsdk:"resource_memory"`
- ResourceRealm types.String `tfsdk:"resource_realm"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewHttpResource() resource.Resource {
- return &HttpResource{}
-}
-
-func (r *HttpResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_http"
-}
-
-func (r *HttpResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("http-1"), MarkdownDescription: "Если будет указан FQDN, то происходят проверки DNS на валидность А-записи, или будет добавлено в зону resourceRealm Не изменяется после создания."},
- "ingress_annotations": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("{}"), MarkdownDescription: "Формат ключ/значение
Поддерживает пока простые аннотации Не изменяется после создания."},
- "json_env": schema.StringAttribute{Optional: true, MarkdownDescription: "Массив переменных, будут переданы в env приложения Не изменяется после создания."},
- "registry_path": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("nexus-sa.tst.nubes.ru/docker-nubes/jolt"), MarkdownDescription: "Путь до image, который будет установлен как deployment Не изменяется после создания."},
- "resource_c_p_u": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(100), MarkdownDescription: "Квота ядра пода (Указывается в mili)"},
- "resource_instances": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Количество узлов"},
- "resource_memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(200), MarkdownDescription: "Квота памяти пода (Указывается в Megabytes)"},
- "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Платформа для развертывания Не изменяется после создания."},
- // --- Redeploy support (ARCHITECTURE.md) ---
- // При изменении git_revision вызывается redeploy вместо modify.
- // Если не задано — modify работает без изменений.
- "git_revision": schema.StringAttribute{Optional: true, MarkdownDescription: "Git revision (commit hash/tag). Changing this triggers redeploy instead of modify."},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *HttpResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *HttpModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *HttpModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan HttpModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.Domain.IsNull() && !plan.Domain.IsUnknown() && !state.Domain.IsNull() && !state.Domain.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.Domain.ValueString(), state.Domain.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить domain", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.IngressAnnotations.IsNull() && !plan.IngressAnnotations.IsUnknown() && !state.IngressAnnotations.IsNull() && !state.IngressAnnotations.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.IngressAnnotations.ValueString(), state.IngressAnnotations.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить ingress_annotations", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.JsonEnv.IsNull() && !plan.JsonEnv.IsUnknown() && !state.JsonEnv.IsNull() && !state.JsonEnv.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.JsonEnv.ValueString(), state.JsonEnv.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить json_env", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.RegistryPath.IsNull() && !plan.RegistryPath.IsUnknown() && !state.RegistryPath.IsNull() && !state.RegistryPath.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.RegistryPath.ValueString(), state.RegistryPath.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить registry_path", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.ResourceRealm.ValueString(), state.ResourceRealm.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.ResourceRealm.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
- if config.ResourceRealm.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- params := map[int]string{
- 212: resources_core.FormatString(config.Domain),
- 213: resources_core.FormatInt64(config.ResourceCPU),
- 214: resources_core.FormatInt64(config.ResourceMemory),
- 215: resources_core.FormatInt64(config.ResourceInstances),
- 216: resources_core.FormatString(config.ResourceRealm),
- 217: resources_core.FormatString(config.RegistryPath),
- 241: resources_core.FormatString(config.JsonEnv),
- 782: resources_core.FormatString(config.IngressAnnotations),
- }
- desiredDomain := ""
- if !config.Domain.IsNull() && !config.Domain.IsUnknown() {
- desiredDomain = config.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 98, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *HttpResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data HttpModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.ResourceRealm.IsNull() || data.ResourceRealm.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.")
- return
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- if !data.Domain.IsNull() && !data.Domain.IsUnknown() {
- desiredDomain = data.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 98, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 212: resources_core.FormatString(data.Domain),
- 213: resources_core.FormatInt64(data.ResourceCPU),
- 214: resources_core.FormatInt64(data.ResourceMemory),
- 215: resources_core.FormatInt64(data.ResourceInstances),
- 216: resources_core.FormatString(data.ResourceRealm),
- 217: resources_core.FormatString(data.RegistryPath),
- 241: resources_core.FormatString(data.JsonEnv),
- 782: resources_core.FormatString(data.IngressAnnotations),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 98, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 98, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "ingressAnnotations", Field: "IngressAnnotations", Type: "string"},
- {Code: "jsonEnv", Field: "JsonEnv", Type: "string"},
- {Code: "registryPath", Field: "RegistryPath", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *HttpResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state HttpModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 98, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "ingressAnnotations", Field: "IngressAnnotations", Type: "string"},
- {Code: "jsonEnv", Field: "JsonEnv", Type: "string"},
- {Code: "registryPath", Field: "RegistryPath", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *HttpResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan HttpModel
- var state HttpModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.ResourceCPU.IsNull() != state.ResourceCPU.IsNull() || plan.ResourceCPU.IsUnknown() != state.ResourceCPU.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceCPU.IsNull() && !plan.ResourceCPU.IsUnknown() && !state.ResourceCPU.IsNull() && !state.ResourceCPU.IsUnknown() {
- if plan.ResourceCPU.ValueInt64() != state.ResourceCPU.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.ResourceMemory.IsNull() != state.ResourceMemory.IsNull() || plan.ResourceMemory.IsUnknown() != state.ResourceMemory.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceMemory.IsNull() && !plan.ResourceMemory.IsUnknown() && !state.ResourceMemory.IsNull() && !state.ResourceMemory.IsUnknown() {
- if plan.ResourceMemory.ValueInt64() != state.ResourceMemory.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.ResourceInstances.IsNull() != state.ResourceInstances.IsNull() || plan.ResourceInstances.IsUnknown() != state.ResourceInstances.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceInstances.IsNull() && !plan.ResourceInstances.IsUnknown() && !state.ResourceInstances.IsNull() && !state.ResourceInstances.IsUnknown() {
- if plan.ResourceInstances.ValueInt64() != state.ResourceInstances.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- // --- Redeploy support (ARCHITECTURE.md) ---
- // Проверяем изменился ли git_revision.
- // Если да — вызываем redeploy вместо modify.
- // git_revision = "" (не задано) → обычный modify.
- redeployRequested := false
- if !plan.GitRevision.IsNull() && !plan.GitRevision.IsUnknown() {
- if state.GitRevision.IsNull() || state.GitRevision.IsUnknown() || plan.GitRevision.ValueString() != state.GitRevision.ValueString() {
- redeployRequested = true
- }
- }
-
- if !hasServiceParamChanges && !redeployRequested {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- // --- Redeploy support (ARCHITECTURE.md) ---
- if redeployRequested {
- // Вызываем redeploy — пустой params (операция не требует CFS-параметров)
- if err := r.client.RunRedeployOperation(ctx, instanceID.ValueString(), operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- } else {
- params := map[int]string{
- 218: resources_core.FormatInt64(plan.ResourceCPU),
- 219: resources_core.FormatInt64(plan.ResourceMemory),
- 220: resources_core.FormatInt64(plan.ResourceInstances),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 98, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "ingressAnnotations", Field: "IngressAnnotations", Type: "string"},
- {Code: "jsonEnv", Field: "JsonEnv", Type: "string"},
- {Code: "registryPath", Field: "RegistryPath", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- {Code: "resourceRealm", Field: "ResourceRealm", Type: "string"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *HttpResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state HttpModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *HttpResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *HttpResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/99_gitea_resource.go b/provider/internal/resources_gen/99_gitea_resource.go
deleted file mode 100644
index 97139b1..0000000
--- a/provider/internal/resources_gen/99_gitea_resource.go
+++ /dev/null
@@ -1,579 +0,0 @@
-package resources_gen
-
-import (
- "context"
- "strings"
-
- "terraform-provider-nubes/internal/core"
- "terraform-provider-nubes/internal/resources_core"
-
- "github.com/hashicorp/terraform-plugin-framework/path"
- "github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
- "github.com/hashicorp/terraform-plugin-framework/types"
-)
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-// Service: gitea
-// Service ID: 99
-
-var _ resource.Resource = &GiteaResource{}
-var _ resource.ResourceWithModifyPlan = &GiteaResource{}
-var _ resource.ResourceWithImportState = &GiteaResource{}
-
-type GiteaResource struct {
- client *core.UniversalClient
-}
-
-type GiteaModel struct {
- ID types.String `tfsdk:"id"`
- ResourceName types.String `tfsdk:"resource_name"`
- OperationTimeout types.String `tfsdk:"operation_timeout"`
- LogLevel types.String `tfsdk:"log_level"`
- Domain types.String `tfsdk:"domain"`
- IngressExtraAnnotations types.String `tfsdk:"ingress_extra_annotations"`
- IniServerParams types.String `tfsdk:"ini_server_params"`
- PsqlUid types.String `tfsdk:"psql_uid"`
- ResourceCPU types.Int64 `tfsdk:"resource_c_p_u"`
- ResourceDisk types.Int64 `tfsdk:"resource_disk"`
- ResourceInstances types.Int64 `tfsdk:"resource_instances"`
- ResourceMemory types.Int64 `tfsdk:"resource_memory"`
- SuspendOnDestroy types.Bool `tfsdk:"suspend_on_destroy"`
- AdoptExistingOnCreate types.Bool `tfsdk:"adopt_existing_on_create"`
- StateParams types.Map `tfsdk:"state_params"`
- StateOut types.Map `tfsdk:"state_out"`
- StateParamsFlat types.Map `tfsdk:"state_params_flat"`
- StateOutFlat types.Map `tfsdk:"state_out_flat"`
- VaultSecrets types.Map `tfsdk:"vault_secrets"`
- VaultUrl types.String `tfsdk:"vault_url"`
- VaultUserPath types.String `tfsdk:"vault_user_path"`
- VaultFields types.List `tfsdk:"vault_fields"`
-}
-
-func NewGiteaResource() resource.Resource {
- return &GiteaResource{}
-}
-
-func (r *GiteaResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
- resp.TypeName = req.ProviderTypeName + "_gitea"
-}
-
-func (r *GiteaResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
- attrs := map[string]schema.Attribute{
- "id": schema.StringAttribute{Computed: true, PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}},
- "resource_name": schema.StringAttribute{Required: true},
- "operation_timeout": schema.StringAttribute{Optional: true},
- "log_level": schema.StringAttribute{Optional: true, MarkdownDescription: "Operation stages log level: none (default), info, debug. Overrides provider-level log_level."},
- "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("gitea-1"), MarkdownDescription: "Если будет указан FQDN, то происходят проверки DNS на валидность А-записи, или будет добавлено в зону resourceRealm Не изменяется после создания."},
- "ingress_extra_annotations": schema.StringAttribute{Optional: true},
- "ini_server_params": schema.StringAttribute{Optional: true},
- "psql_uid": schema.StringAttribute{Optional: true, Computed: true, MarkdownDescription: "UUID Услуги k8sPgsql. Пользователя techGitea, базу данных gitea создаёт автоматически Не изменяется после создания."},
- "resource_c_p_u": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(500), MarkdownDescription: "Квота ядра пода (Указывается в mili). 1000Mili = 1 Ядро"},
- "resource_disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Квота диска (Указывается в GIGAbytes)"},
- "resource_instances": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Количество узлов"},
- "resource_memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(512), MarkdownDescription: "Квота памяти пода (Указывается в Megabytes)"},
- "suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(true)},
- "adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false)},
- "state_params": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_params_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "state_out_flat": schema.MapAttribute{Computed: true, ElementType: types.StringType},
- "vault_secrets": schema.MapAttribute{Computed: true, ElementType: types.StringType, Sensitive: true},
- "vault_url": schema.StringAttribute{Computed: true},
- "vault_user_path": schema.StringAttribute{Computed: true},
- "vault_fields": schema.ListAttribute{Computed: true, ElementType: types.StringType},
- }
-
- resp.Schema = schema.Schema{Attributes: attrs}
-}
-
-func (r *GiteaResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
- if r.client == nil {
- return
- }
-
- var config *GiteaModel
- resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if config == nil {
- return
- }
-
- var state *GiteaModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if req.State.Raw.IsNull() && req.Plan.Raw.IsNull() {
- return
- }
-
- if state != nil && !state.ID.IsNull() && !state.ID.IsUnknown() {
- var plan GiteaModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- if resp.Diagnostics.HasError() {
- return
- }
- // FIX(uuid-case): resolve ref_svc params НЕ делаем в ModifyPlan.
- // Terraform правило: plan ОБЯЗАН равняться config для user-provided атрибутов.
- // Resolve (displayName → UUID или uppercase → lowercase) нужен только для
- // API-вызова в Create/Update. Делать его здесь = менять plan = ошибка
- // "Provider produced invalid plan: planned value does not match config value".
- if !plan.ResourceName.IsNull() && !plan.ResourceName.IsUnknown() && !state.ResourceName.IsNull() && !state.ResourceName.IsUnknown() {
- if plan.ResourceName.ValueString() != state.ResourceName.ValueString() {
- resp.Diagnostics.AddError("Нельзя изменить resource_name", "Параметр resource_name задается при создании и не может быть изменен. Создайте новый ресурс с другим именем.")
- return
- }
- }
- if !plan.Domain.IsNull() && !plan.Domain.IsUnknown() && !state.Domain.IsNull() && !state.Domain.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.Domain.ValueString(), state.Domain.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить domain", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- if !plan.PsqlUid.IsNull() && !plan.PsqlUid.IsUnknown() && !state.PsqlUid.IsNull() && !state.PsqlUid.IsUnknown() {
- // FIX(uuid-case): сравниваем без учёта регистра — API возвращает UUID
- // в lowercase, пользователь мог написать upper/mixed. Это одно и то же
- // значение, менять его нельзя только если оно реально другое.
- if !strings.EqualFold(plan.PsqlUid.ValueString(), state.PsqlUid.ValueString()) {
- resp.Diagnostics.AddError("Нельзя изменить psql_uid", "Параметр задается при создании и не может быть изменен.")
- return
- }
- }
- return
- }
- if config.PsqlUid.IsNull() {
- resp.Diagnostics.AddError("Missing required attribute", "psql_uid is required.")
- return
- }
- if config.PsqlUid.IsUnknown() {
- return
- }
-
- if config.ResourceName.IsNull() || config.ResourceName.IsUnknown() {
- return
- }
- adoptExistingOnCreate := false
- if !config.AdoptExistingOnCreate.IsNull() && !config.AdoptExistingOnCreate.IsUnknown() {
- adoptExistingOnCreate = config.AdoptExistingOnCreate.ValueBool()
- }
- if !config.PsqlUid.IsNull() && !config.PsqlUid.IsUnknown() {
- resolvedPsqlUid, err := r.client.ResolveRefSvcParamValue(ctx, 90, config.PsqlUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve psql_uid", err.Error())
- } else if resolvedPsqlUid != "" && resolvedPsqlUid != config.PsqlUid.ValueString() {
- config.PsqlUid = types.StringValue(resolvedPsqlUid)
- }
- }
- params := map[int]string{
- 232: resources_core.FormatInt64(config.ResourceCPU),
- 233: resources_core.FormatInt64(config.ResourceMemory),
- 234: resources_core.FormatInt64(config.ResourceDisk),
- 235: resources_core.FormatInt64(config.ResourceInstances),
- 237: resources_core.FormatString(config.Domain),
- 238: resources_core.FormatString(config.PsqlUid),
- 818: resources_core.FormatString(config.IngressExtraAnnotations),
- 821: resources_core.FormatString(config.IniServerParams),
- }
- desiredDomain := ""
- if !config.Domain.IsNull() && !config.Domain.IsUnknown() {
- desiredDomain = config.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
-
- resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParamsAndDomainAndServices(ctx, r.client, 99, config.ResourceName.ValueString(), adoptExistingOnCreate, params, desiredDomain, domainServiceIDs)...)
-}
-
-func (r *GiteaResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
- var data GiteaModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if data.PsqlUid.IsNull() || data.PsqlUid.IsUnknown() {
- resp.Diagnostics.AddError("Missing required attribute", "psql_uid is required.")
- return
- }
- // ══════════════════════════════════════════════════════════════════════════
- // ПРАВИЛО TERRAFORM (официальная документация):
- // «If an attribute value is configured, it is NEVER valid to change that
- // value in the plan.» — то есть plan ОБЯЗАН равняться config (= тому что
- // написал пользователь). Менять plan запрещено на уровне фреймворка.
- //
- // ПРОБЛЕМА: API нашего облака возвращает UUID в нижнем регистре.
- // Пользователь пишет: vapp_uid = "6214BA32-..." (верхний или смешанный).
- // После apply API вернул: "6214ba32-..." → state != plan → Terraform кричит:
- // «Provider produced inconsistent result after apply».
- //
- // РЕШЕНИЕ: корректировать STATE под PLAN, а не наоборот.
- // Шаг 1 (здесь): сохраняем оригинальное значение из plan ДО того как
- // ResolveRefSvcParamValue переведёт UUID в нижний регистр (нужен для API).
- // Шаг 2 (ниже, после RefreshResourceState): восстанавливаем оригинальный
- // регистр в state через strings.EqualFold (сравниваем без учёта регистра).
- // ══════════════════════════════════════════════════════════════════════════
- originalPsqlUid := data.PsqlUid
- if !data.PsqlUid.IsNull() && !data.PsqlUid.IsUnknown() {
- resolvedPsqlUid, err := r.client.ResolveRefSvcParamValue(ctx, 90, data.PsqlUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if resolvedPsqlUid != "" && resolvedPsqlUid != data.PsqlUid.ValueString() {
- data.PsqlUid = types.StringValue(resolvedPsqlUid)
- }
- }
-
- resourceName := data.ResourceName.ValueString()
- desiredDomain := ""
- if !data.Domain.IsNull() && !data.Domain.IsUnknown() {
- desiredDomain = data.Domain.ValueString()
- }
- domainServiceIDs := []int{81, 82, 88, 96, 97, 98, 99, 119, 149, 151, 153}
- resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnosticsWithDomainAndServices(ctx, r.client, 99, resourceName, data.AdoptExistingOnCreate.ValueBool(), desiredDomain, domainServiceIDs)...)
- // ⛔ Проверяем HasError ДО create — при hard-error (running без adopt, suspend без adopt,
- // not created, конфликт) сайд-эффект create не должен выполняться.
- if resp.Diagnostics.HasError() {
- return
- }
-
- params := map[int]string{
- 232: resources_core.FormatInt64(data.ResourceCPU),
- 233: resources_core.FormatInt64(data.ResourceMemory),
- 234: resources_core.FormatInt64(data.ResourceDisk),
- 235: resources_core.FormatInt64(data.ResourceInstances),
- 237: resources_core.FormatString(data.Domain),
- 238: resources_core.FormatString(data.PsqlUid),
- 818: resources_core.FormatString(data.IngressExtraAnnotations),
- 821: resources_core.FormatString(data.IniServerParams),
- }
-
- operationTimeout := ""
- if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() {
- operationTimeout = data.OperationTimeout.ValueString()
- }
- if !data.LogLevel.IsNull() && !data.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, data.LogLevel.ValueString())
- }
- id, err := resources_core.CreateResourceWithTimeout(ctx, r.client, 99, resourceName, data.AdoptExistingOnCreate.ValueBool(), params, operationTimeout)
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- data.ID = types.StringValue(id)
-
- state, diags := resources_core.RefreshResourceState(ctx, r.client, id, 99, data, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "ingressExtraAnnotations", Field: "IngressExtraAnnotations", Type: "string"},
- {Code: "iniServerParams", Field: "IniServerParams", Type: "string"},
- {Code: "psqlUid", Field: "PsqlUid", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !state.PsqlUid.IsNull() && !state.PsqlUid.IsUnknown() {
- resolvedPsqlUid, err := r.client.ResolveRefSvcParamValue(ctx, 90, state.PsqlUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve psql_uid", err.Error())
- } else if resolvedPsqlUid != "" && resolvedPsqlUid != state.PsqlUid.ValueString() {
- state.PsqlUid = types.StringValue(resolvedPsqlUid)
- }
- }
- // Restore user-provided casing в state (Create).
- // EqualFold = «совпадают ли значения без учёта регистра?»
- // Если да — значит API вернул «туже» строку, только в другом регистре.
- // Заменяем state на original (то что было в plan/config пользователя).
- // Итог: plan=="6214BA32-..." и state=="6214BA32-..." → нет diff → нет taint.
- if !originalPsqlUid.IsNull() && !originalPsqlUid.IsUnknown() && !state.PsqlUid.IsNull() && !state.PsqlUid.IsUnknown() {
- if strings.EqualFold(state.PsqlUid.ValueString(), originalPsqlUid.ValueString()) {
- state.PsqlUid = originalPsqlUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *GiteaResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
- var state GiteaModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- if r.client != nil {
- remove, err := resources_core.ShouldRemoveFromState(ctx, r.client, state.ID.ValueString())
- if err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
- if remove {
- resp.State.RemoveResource(ctx)
- return
- }
- }
-
- newState, diags := resources_core.RefreshResourceState(ctx, r.client, state.ID.ValueString(), 99, state, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "ingressExtraAnnotations", Field: "IngressExtraAnnotations", Type: "string"},
- {Code: "iniServerParams", Field: "IniServerParams", Type: "string"},
- {Code: "psqlUid", Field: "PsqlUid", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !newState.PsqlUid.IsNull() && !newState.PsqlUid.IsUnknown() {
- resolvedPsqlUid, err := r.client.ResolveRefSvcParamValue(ctx, 90, newState.PsqlUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve psql_uid", err.Error())
- } else if resolvedPsqlUid != "" && resolvedPsqlUid != newState.PsqlUid.ValueString() {
- newState.PsqlUid = types.StringValue(resolvedPsqlUid)
- }
- }
- // Restore user-provided casing в state (Read).
- // При чтении у нас нет plan — но предыдущий state уже хранит значение
- // в регистре пользователя (после первого Create оно было восстановлено).
- // Берём prior state (переменная state) как эталон регистра.
- // Если API вернул то же UUID только строчными буквами — восстанавливаем.
- if !state.PsqlUid.IsNull() && !state.PsqlUid.IsUnknown() && !newState.PsqlUid.IsNull() && !newState.PsqlUid.IsUnknown() {
- if strings.EqualFold(newState.PsqlUid.ValueString(), state.PsqlUid.ValueString()) {
- newState.PsqlUid = state.PsqlUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &newState)...)
-}
-
-func (r *GiteaResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
- var plan GiteaModel
- var state GiteaModel
- resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
-
- instanceID := state.ID
- if instanceID.IsNull() || instanceID.IsUnknown() {
- instanceID = plan.ID
- }
- if instanceID.IsNull() || instanceID.IsUnknown() {
- resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра для modify")
- return
- }
-
- hasServiceParamChanges := false
- if !hasServiceParamChanges {
- if plan.ResourceCPU.IsNull() != state.ResourceCPU.IsNull() || plan.ResourceCPU.IsUnknown() != state.ResourceCPU.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceCPU.IsNull() && !plan.ResourceCPU.IsUnknown() && !state.ResourceCPU.IsNull() && !state.ResourceCPU.IsUnknown() {
- if plan.ResourceCPU.ValueInt64() != state.ResourceCPU.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.ResourceMemory.IsNull() != state.ResourceMemory.IsNull() || plan.ResourceMemory.IsUnknown() != state.ResourceMemory.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceMemory.IsNull() && !plan.ResourceMemory.IsUnknown() && !state.ResourceMemory.IsNull() && !state.ResourceMemory.IsUnknown() {
- if plan.ResourceMemory.ValueInt64() != state.ResourceMemory.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.ResourceDisk.IsNull() != state.ResourceDisk.IsNull() || plan.ResourceDisk.IsUnknown() != state.ResourceDisk.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceDisk.IsNull() && !plan.ResourceDisk.IsUnknown() && !state.ResourceDisk.IsNull() && !state.ResourceDisk.IsUnknown() {
- if plan.ResourceDisk.ValueInt64() != state.ResourceDisk.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.ResourceInstances.IsNull() != state.ResourceInstances.IsNull() || plan.ResourceInstances.IsUnknown() != state.ResourceInstances.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.ResourceInstances.IsNull() && !plan.ResourceInstances.IsUnknown() && !state.ResourceInstances.IsNull() && !state.ResourceInstances.IsUnknown() {
- if plan.ResourceInstances.ValueInt64() != state.ResourceInstances.ValueInt64() {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.IngressExtraAnnotations.IsNull() != state.IngressExtraAnnotations.IsNull() || plan.IngressExtraAnnotations.IsUnknown() != state.IngressExtraAnnotations.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.IngressExtraAnnotations.IsNull() && !plan.IngressExtraAnnotations.IsUnknown() && !state.IngressExtraAnnotations.IsNull() && !state.IngressExtraAnnotations.IsUnknown() {
- if !strings.EqualFold(plan.IngressExtraAnnotations.ValueString(), state.IngressExtraAnnotations.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
- if !hasServiceParamChanges {
- if plan.IniServerParams.IsNull() != state.IniServerParams.IsNull() || plan.IniServerParams.IsUnknown() != state.IniServerParams.IsUnknown() {
- hasServiceParamChanges = true
- } else if !plan.IniServerParams.IsNull() && !plan.IniServerParams.IsUnknown() && !state.IniServerParams.IsNull() && !state.IniServerParams.IsUnknown() {
- if !strings.EqualFold(plan.IniServerParams.ValueString(), state.IniServerParams.ValueString()) {
- hasServiceParamChanges = true
- }
- }
- }
-
- if !hasServiceParamChanges {
- plan.ID = instanceID
- plan.StateParams = state.StateParams
- plan.StateOut = state.StateOut
- plan.StateParamsFlat = state.StateParamsFlat
- plan.StateOutFlat = state.StateOutFlat
- plan.VaultSecrets = state.VaultSecrets
- plan.VaultUrl = state.VaultUrl
- plan.VaultUserPath = state.VaultUserPath
- plan.VaultFields = state.VaultFields
- resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
- return
- }
-
- operationTimeout := ""
- if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
- operationTimeout = plan.OperationTimeout.ValueString()
- }
- if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
- }
- params := map[int]string{
- 259: resources_core.FormatInt64(plan.ResourceCPU),
- 260: resources_core.FormatInt64(plan.ResourceMemory),
- 261: resources_core.FormatInt64(plan.ResourceDisk),
- 262: resources_core.FormatInt64(plan.ResourceInstances),
- 819: resources_core.FormatString(plan.IngressExtraAnnotations),
- 820: resources_core.FormatString(plan.IniServerParams),
- }
- if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-
- plan.ID = instanceID
- state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), 99, plan, []resources_core.StateField{
- {Code: "state_params"},
- {Code: "state_out"},
- {Code: "state_params_flat"},
- {Code: "state_out_flat"},
- {Code: "vault_secrets"},
- {Code: "vault_url"},
- {Code: "vault_user_path"},
- {Code: "vault_fields"},
- }, []resources_core.InputField{
- {Code: "domain", Field: "Domain", Type: "string"},
- {Code: "ingressExtraAnnotations", Field: "IngressExtraAnnotations", Type: "string"},
- {Code: "iniServerParams", Field: "IniServerParams", Type: "string"},
- {Code: "psqlUid", Field: "PsqlUid", Type: "string"},
- {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"},
- {Code: "resourceDisk", Field: "ResourceDisk", Type: "int64"},
- {Code: "resourceInstances", Field: "ResourceInstances", Type: "int64"},
- {Code: "resourceMemory", Field: "ResourceMemory", Type: "int64"},
- })
- resp.Diagnostics.Append(diags...)
- if resp.Diagnostics.HasError() {
- return
- }
- if !state.PsqlUid.IsNull() && !state.PsqlUid.IsUnknown() {
- resolvedPsqlUid, err := r.client.ResolveRefSvcParamValue(ctx, 90, state.PsqlUid.ValueString())
- if err != nil {
- resp.Diagnostics.AddWarning("Failed to resolve psql_uid", err.Error())
- } else if resolvedPsqlUid != "" && resolvedPsqlUid != state.PsqlUid.ValueString() {
- state.PsqlUid = types.StringValue(resolvedPsqlUid)
- }
- }
- // Restore user-provided casing в state (Update).
- // После API-вызова modify state содержит значения в lower-case от API.
- // Plan == config == то что написал пользователь (регистр неизменён).
- // EqualFold: если UUID совпадает без учёта регистра — берём из plan.
- if !plan.PsqlUid.IsNull() && !plan.PsqlUid.IsUnknown() && !state.PsqlUid.IsNull() && !state.PsqlUid.IsUnknown() {
- if strings.EqualFold(state.PsqlUid.ValueString(), plan.PsqlUid.ValueString()) {
- state.PsqlUid = plan.PsqlUid
- }
- }
-
- resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
-}
-
-func (r *GiteaResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
- var state GiteaModel
- resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
- if resp.Diagnostics.HasError() {
- return
- }
- if state.ID.IsNull() || state.ID.IsUnknown() {
- return
- }
- deleteMode := "state_only"
- if !state.SuspendOnDestroy.IsNull() && !state.SuspendOnDestroy.IsUnknown() && state.SuspendOnDestroy.ValueBool() {
- deleteMode = "suspend"
- }
-
- operationTimeout := ""
- if !state.OperationTimeout.IsNull() && !state.OperationTimeout.IsUnknown() {
- operationTimeout = state.OperationTimeout.ValueString()
- }
- if !state.LogLevel.IsNull() && !state.LogLevel.IsUnknown() {
- ctx = core.CtxWithLogLevel(ctx, state.LogLevel.ValueString())
- }
- if err := resources_core.DeleteResourceWithTimeout(ctx, r.client, state.ID.ValueString(), deleteMode, operationTimeout); err != nil {
- resp.Diagnostics.AddError("Ошибка клиента", err.Error())
- return
- }
-}
-
-func (r *GiteaResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func (r *GiteaResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
- if req.ProviderData == nil {
- return
- }
- client, ok := req.ProviderData.(*core.UniversalClient)
- if !ok {
- resp.Diagnostics.AddError("Error", "Invalid client type")
- return
- }
- r.client = client
-}
diff --git a/provider/internal/resources_gen/registry.go b/provider/internal/resources_gen/registry.go
deleted file mode 100644
index 893cf0d..0000000
--- a/provider/internal/resources_gen/registry.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package resources_gen
-
-import "github.com/hashicorp/terraform-plugin-framework/resource"
-
-// Code generated by tools/gen_v2. DO NOT EDIT.
-func AllResources() []func() resource.Resource {
- return []func() resource.Resource{
- NewAkhqResource,
- NewClickhouseResource,
- NewDnsrecordResource,
- NewDnszoneResource,
- NewDummyResource,
- NewFlaskResource,
- NewGiteaResource,
- NewHarborResource,
- NewHttpResource,
- NewK8sGoResource,
- NewK8sOpenbaoResource,
- NewK8sSthutrvalClusterResource,
- NewK8sVeleroResource,
- NewK8sZitiControllerResource,
- NewK8svalkeyResource,
- NewKafkaResource,
- NewLlmAiResource,
- NewLuceeResource,
- NewMariadbResource,
- NewMongodbResource,
- NewNextcloudResource,
- NewNifiResource,
- NewNodejsResource,
- NewNoderedResource,
- NewOpenwhiskResource,
- NewPgadminResource,
- NewPostgresResource,
- NewRabbitmqResource,
- NewRedisResource,
- NewS3Resource,
- NewS3bucketResource,
- NewSupersetResource,
- NewTemplateResource,
- NewTenantResource,
- NewValoTenantResource,
- NewVappResource,
- NewVcComplexResource,
- NewVcMgmtSthutrvalClusterResource,
- NewVcNatResource,
- NewVcNsxtResource,
- NewVcOrgResource,
- NewVcOrgSaasResource,
- NewVcVdcResource,
- NewVcVdcGroupResource,
- NewVcVmResource,
- NewVcVmV2Resource,
- NewVcVmV3Resource,
- NewVcexternalipResource,
- NewVmpostgreResource,
- NewZonesV2Resource,
- NewClickhouseDatabaseResource,
- NewClickhouseUserResource,
- NewK8sOpenbaoKvResource,
- NewK8sOpenbaoPolicyResource,
- NewK8sOpenbaoSecretsResource,
- NewK8sSthutrvalClusterUserResource,
- NewK8svalkeyUserResource,
- NewKafkaTopicResource,
- NewKafkaUserResource,
- NewLlmAiSecretsResource,
- NewLlmAiTeamResource,
- NewMariadbDatabaseResource,
- NewMariadbUserResource,
- NewMongodbUserResource,
- NewNextcloudBackupResource,
- NewPostgresBackupResource,
- NewPostgresDatabaseResource,
- NewPostgresUserResource,
- NewS3SubUserResource,
- NewVcOrgUserResource,
- NewVcVdcGroupVdcResource,
- NewZonesV2RecordResource,
- }
-}