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 }