diff --git a/universal_rebuild/internal/resources_gen/25_vcexternalip_resource.go b/universal_rebuild/internal/resources_gen/25_vcexternalip_resource.go new file mode 100644 index 0000000..c8beddf --- /dev/null +++ b/universal_rebuild/internal/resources_gen/25_vcexternalip_resource.go @@ -0,0 +1,558 @@ +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/stringdefault" + "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"` + 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "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{Required: true, 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() { + if 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() { + if 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() { + if 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() { + if 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() { + if 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() { + if 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() { + if 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() { + if plan.ResourceRealm.ValueString() != state.ResourceRealm.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.") + return + } + } + return + } + if config.FromServiceNamespace.IsNull() || config.FromServiceNamespace.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "from_service_namespace is required.") + return + } + if config.InternalAddrAccess.IsNull() || config.InternalAddrAccess.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "internal_addr_access is required.") + return + } + if config.IpSpaceName.IsNull() || config.IpSpaceName.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "ip_space_name is required.") + return + } + if config.ResourceRealm.IsNull() || config.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + return + } + if config.ServiceUid.IsNull() || config.ServiceUid.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "service_uid is required.") + 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), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 25, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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.ResourceRealm.IsNull() || data.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm 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() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 25, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + 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() + } + 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 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 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 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 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 + } + + 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), + } + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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(), 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 := "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 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/universal_rebuild/internal/resources_gen/26_vapp_resource.go b/universal_rebuild/internal/resources_gen/26_vapp_resource.go new file mode 100644 index 0000000..35e9615 --- /dev/null +++ b/universal_rebuild/internal/resources_gen/26_vapp_resource.go @@ -0,0 +1,482 @@ +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/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"` + 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "nsxt_uid": schema.StringAttribute{Required: true, MarkdownDescription: "UUID Услуги `Сетевой шлюз периметра (Edge)` Не изменяется после создания."}, + "vapp_name": schema.StringAttribute{Required: true, MarkdownDescription: "Уникальное в рамках организации Не изменяется после создания."}, + "vdc_uid": schema.StringAttribute{Required: 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 + } + planChanged := false + if !plan.NsxtUid.IsNull() && !plan.NsxtUid.IsUnknown() { + resolvedNsxtUid, err := r.client.ResolveRefSvcParamValue(ctx, 22, plan.NsxtUid.ValueString()) + if err != nil { + resp.Diagnostics.AddWarning("Failed to resolve nsxt_uid", err.Error()) + } else if resolvedNsxtUid != "" && resolvedNsxtUid != plan.NsxtUid.ValueString() { + plan.NsxtUid = types.StringValue(resolvedNsxtUid) + planChanged = true + } + } + if !plan.VdcUid.IsNull() && !plan.VdcUid.IsUnknown() { + resolvedVdcUid, err := r.client.ResolveRefSvcParamValue(ctx, 21, plan.VdcUid.ValueString()) + if err != nil { + resp.Diagnostics.AddWarning("Failed to resolve vdc_uid", err.Error()) + } else if resolvedVdcUid != "" && resolvedVdcUid != plan.VdcUid.ValueString() { + plan.VdcUid = types.StringValue(resolvedVdcUid) + planChanged = true + } + } + if planChanged { + resp.Diagnostics.Append(resp.Plan.Set(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.NsxtUid.IsNull() && !plan.NsxtUid.IsUnknown() && !state.NsxtUid.IsNull() && !state.NsxtUid.IsUnknown() { + if 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() { + if 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() { + if plan.VdcUid.ValueString() != state.VdcUid.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить vdc_uid", "Параметр задается при создании и не может быть изменен.") + return + } + } + return + } + if config.NsxtUid.IsNull() || config.NsxtUid.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "nsxt_uid is required.") + return + } + if config.VappName.IsNull() || config.VappName.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "vapp_name is required.") + return + } + if config.VdcUid.IsNull() || config.VdcUid.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "vdc_uid is required.") + 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), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 26, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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.VappName.IsNull() || data.VappName.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "vapp_name is required.") + return + } + if data.VdcUid.IsNull() || data.VdcUid.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "vdc_uid is required.") + return + } + 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() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 26, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + 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() + } + 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) + } + } + + 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) + } + } + + 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 + } + + params := map[int]string{} + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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(), 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) + } + } + + 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 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/universal_rebuild/internal/resources_gen/27_vc_vm_v2_resource.go b/universal_rebuild/internal/resources_gen/27_vc_vm_v2_resource.go new file mode 100644 index 0000000..53b57db --- /dev/null +++ b/universal_rebuild/internal/resources_gen/27_vc_vm_v2_resource.go @@ -0,0 +1,329 @@ +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/stringdefault" + "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"` + 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "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)"}, + "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), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 27, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 27, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + params := map[int]string{ + 301: resources_core.FormatString(data.ServerListJson), + } + + operationTimeout := "" + if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() { + operationTimeout = data.OperationTimeout.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 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 + } + + params := map[int]string{ + 302: resources_core.FormatString(plan.ServerListJson), + } + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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(), 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 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/universal_rebuild/internal/resources_gen/28_vc_vm_v3_redeploy_action.go b/universal_rebuild/internal/resources_gen/28_vc_vm_v3_redeploy_action.go new file mode 100644 index 0000000..f2212aa --- /dev/null +++ b/universal_rebuild/internal/resources_gen/28_vc_vm_v3_redeploy_action.go @@ -0,0 +1,198 @@ +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/types" +) + +// Code generated by tools/gen_v2. DO NOT EDIT. +// Service: vc_vm_v3 +// Action: redeploy + +var _ resource.Resource = &VcVmV3RedeployResource{} + +// VcVmV3RedeployResource triggers a one-time action. +type VcVmV3RedeployResource struct { + client *core.UniversalClient +} + +type VcVmV3RedeployModel struct { + ID types.String `tfsdk:"id"` + VcVmV3ID types.String `tfsdk:"vc_vm_v3_id"` + RunID types.String `tfsdk:"run_id"` + OperationTimeout types.String `tfsdk:"operation_timeout"` + VmName types.String `tfsdk:"vm_name"` + VmCpu types.Int64 `tfsdk:"vm_cpu"` + VmRam types.Int64 `tfsdk:"vm_ram"` + VmDisk types.Int64 `tfsdk:"vm_disk"` + IpSpaceName types.String `tfsdk:"ip_space_name"` + AccessIpList types.String `tfsdk:"access_ip_list"` + ImageVm types.String `tfsdk:"image_vm"` + UserLogin types.String `tfsdk:"user_login"` + UserPublicKey types.String `tfsdk:"user_public_key"` + CloudInit types.String `tfsdk:"cloud_init"` + AccessPortList types.String `tfsdk:"access_port_list"` +} + +func NewVcVmV3RedeployResource() resource.Resource { + return &VcVmV3RedeployResource{} +} + +func (r *VcVmV3RedeployResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_vc_vm_v3_redeploy" +} + +func (r *VcVmV3RedeployResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + attrs := map[string]schema.Attribute{ + "id": schema.StringAttribute{Computed: true}, + "vc_vm_v3_id": schema.StringAttribute{Required: true}, + "run_id": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "vm_name": schema.StringAttribute{Required: true}, + "vm_cpu": schema.Int64Attribute{Required: true, MarkdownDescription: "шт"}, + "vm_ram": schema.Int64Attribute{Required: true, MarkdownDescription: "Gb"}, + "vm_disk": schema.Int64Attribute{Optional: true, MarkdownDescription: "Основной диск у vm зависит от образа (см. документацию)
Если необходимо дополнительное место для vm, введите колличество Gb в эту форму"}, + "ip_space_name": schema.StringAttribute{Optional: true, MarkdownDescription: "no-needed, без внешнего ip
internet-antiddos-v1, с функцией защиты от ddos атак
internet-no-antiddos-v1, с функцией защиты от ddos атак
internet-ipv4-v1 тестовое простанство dev"}, + "access_ip_list": schema.StringAttribute{Optional: true, MarkdownDescription: "Формат массива
Каким адресам будет предоставлен доступ до вм

Требует выделенного внешнего IP
Если ничего не передано, то выставлено ["0.0.0.0/0"]"}, + "image_vm": schema.StringAttribute{Required: true}, + "user_login": schema.StringAttribute{Required: true, MarkdownDescription: "Учётка SSH"}, + "user_public_key": schema.StringAttribute{Required: true, MarkdownDescription: "Публичная часть SSH-Ключа для пользователя"}, + "cloud_init": schema.StringAttribute{Optional: true, MarkdownDescription: "Можно передать создание дополнительных пользователей.
На текущий момент не реализовано выполнения в cloud-init, установки пакетов, выполнения команд и записи файлов."}, + "access_port_list": schema.StringAttribute{Optional: true, MarkdownDescription: "По каким портам открыть доступ к ВМ.
Порты 22, 10050 проставляются автоматически
Пока доступно:
22 - SSH,
80 - HTTP,
443 - HTTPS,
10050 - ZABBIX"}, + } + resp.Schema = schema.Schema{Attributes: attrs} +} + +func (r *VcVmV3RedeployResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan VcVmV3RedeployModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + if plan.VmName.IsNull() || plan.VmName.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "vm_name is required.") + return + } + if plan.VmCpu.IsNull() || plan.VmCpu.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "vm_cpu is required.") + return + } + if plan.VmRam.IsNull() || plan.VmRam.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "vm_ram is required.") + return + } + if plan.ImageVm.IsNull() || plan.ImageVm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "image_vm is required.") + return + } + if plan.UserLogin.IsNull() || plan.UserLogin.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "user_login is required.") + return + } + if plan.UserPublicKey.IsNull() || plan.UserPublicKey.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "user_public_key is required.") + return + } + + instanceUID := strings.TrimSpace(plan.VcVmV3ID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{ + "vmName": resources_core.FormatString(plan.VmName), + "vmCpu": resources_core.FormatInt64(plan.VmCpu), + "vmRam": resources_core.FormatInt64(plan.VmRam), + "vmDisk": resources_core.FormatInt64(plan.VmDisk), + "ipSpaceName": resources_core.FormatString(plan.IpSpaceName), + "accessIpList": resources_core.FormatString(plan.AccessIpList), + "imageVm": resources_core.FormatString(plan.ImageVm), + "userLogin": resources_core.FormatString(plan.UserLogin), + "userPublicKey": resources_core.FormatString(plan.UserPublicKey), + "cloudInit": resources_core.FormatString(plan.CloudInit), + "accessPortList": resources_core.FormatString(plan.AccessPortList), + } + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.ValueString() + } + if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "redeploy", params, operationTimeout); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "redeploy", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *VcVmV3RedeployResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state VcVmV3RedeployModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *VcVmV3RedeployResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan VcVmV3RedeployModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + instanceUID := strings.TrimSpace(plan.VcVmV3ID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{ + "vmName": resources_core.FormatString(plan.VmName), + "vmCpu": resources_core.FormatInt64(plan.VmCpu), + "vmRam": resources_core.FormatInt64(plan.VmRam), + "vmDisk": resources_core.FormatInt64(plan.VmDisk), + "ipSpaceName": resources_core.FormatString(plan.IpSpaceName), + "accessIpList": resources_core.FormatString(plan.AccessIpList), + "imageVm": resources_core.FormatString(plan.ImageVm), + "userLogin": resources_core.FormatString(plan.UserLogin), + "userPublicKey": resources_core.FormatString(plan.UserPublicKey), + "cloudInit": resources_core.FormatString(plan.CloudInit), + "accessPortList": resources_core.FormatString(plan.AccessPortList), + } + + if err := resources_core.RunOperationByCode(ctx, r.client, instanceUID, "redeploy", params); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "redeploy", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *VcVmV3RedeployResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + // No-op: removing the resource does not trigger a remote action. +} + +func (r *VcVmV3RedeployResource) 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/universal_rebuild/internal/resources_gen/28_vc_vm_v3_resource.go b/universal_rebuild/internal/resources_gen/28_vc_vm_v3_resource.go new file mode 100644 index 0000000..fdfdd1e --- /dev/null +++ b/universal_rebuild/internal/resources_gen/28_vc_vm_v3_resource.go @@ -0,0 +1,583 @@ +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/int64default" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "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"` + 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "access_ip_list": schema.StringAttribute{Optional: true, MarkdownDescription: "Формат массива
Каким адресам будет предоставлен доступ до вм

Требует выделенного внешнего IP
Если ничего не передано, то выставлено ["0.0.0.0/0"]"}, + "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{Required: 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"}, + "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 + } + planChanged := false + if !plan.VappUid.IsNull() && !plan.VappUid.IsUnknown() { + resolvedVappUid, err := r.client.ResolveRefSvcParamValue(ctx, 26, plan.VappUid.ValueString()) + if err != nil { + resp.Diagnostics.AddWarning("Failed to resolve vapp_uid", err.Error()) + } else if resolvedVappUid != "" && resolvedVappUid != plan.VappUid.ValueString() { + plan.VappUid = types.StringValue(resolvedVappUid) + planChanged = true + } + } + if planChanged { + resp.Diagnostics.Append(resp.Plan.Set(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.CloudInit.IsNull() && !plan.CloudInit.IsUnknown() && !state.CloudInit.IsNull() && !state.CloudInit.IsUnknown() { + if 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() { + if 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() { + if 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() { + if 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() { + if 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() { + if plan.VmName.ValueString() != state.VmName.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить vm_name", "Параметр задается при создании и не может быть изменен.") + return + } + } + return + } + if config.ImageVm.IsNull() || config.ImageVm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "image_vm is required.") + return + } + if config.IpSpaceName.IsNull() || config.IpSpaceName.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "ip_space_name is required.") + return + } + if config.UserPublicKey.IsNull() || config.UserPublicKey.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "user_public_key is required.") + return + } + if config.VappUid.IsNull() || config.VappUid.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "vapp_uid is required.") + 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), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 28, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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 + } + 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() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 28, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + 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() + } + 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) + } + } + + 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) + } + } + + 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 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 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 plan.AccessPortList.ValueString() != state.AccessPortList.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 + } + + 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), + } + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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(), 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) + } + } + + 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 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/universal_rebuild/internal/resources_gen/29_vc_vdc_group_add_vdc_action.go b/universal_rebuild/internal/resources_gen/29_vc_vdc_group_add_vdc_action.go new file mode 100644 index 0000000..0ae19b7 --- /dev/null +++ b/universal_rebuild/internal/resources_gen/29_vc_vdc_group_add_vdc_action.go @@ -0,0 +1,138 @@ +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/types" +) + +// Code generated by tools/gen_v2. DO NOT EDIT. +// Service: vc_vdc_group +// Action: add_vdc + +var _ resource.Resource = &VcVdcGroupAddVdcResource{} + +// VcVdcGroupAddVdcResource triggers a one-time action. +type VcVdcGroupAddVdcResource struct { + client *core.UniversalClient +} + +type VcVdcGroupAddVdcModel struct { + ID types.String `tfsdk:"id"` + VcVdcGroupID types.String `tfsdk:"vc_vdc_group_id"` + RunID types.String `tfsdk:"run_id"` + OperationTimeout types.String `tfsdk:"operation_timeout"` + VdcUid types.String `tfsdk:"vdc_uid"` +} + +func NewVcVdcGroupAddVdcResource() resource.Resource { + return &VcVdcGroupAddVdcResource{} +} + +func (r *VcVdcGroupAddVdcResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_vc_vdc_group_add_vdc" +} + +func (r *VcVdcGroupAddVdcResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + attrs := map[string]schema.Attribute{ + "id": schema.StringAttribute{Computed: true}, + "vc_vdc_group_id": schema.StringAttribute{Required: true}, + "run_id": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "vdc_uid": schema.StringAttribute{Required: true, MarkdownDescription: "UI display_name for service_id=21 (mapped to UUID in core)"}, + } + resp.Schema = schema.Schema{Attributes: attrs} +} + +func (r *VcVdcGroupAddVdcResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan VcVdcGroupAddVdcModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + if plan.VdcUid.IsNull() || plan.VdcUid.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "vdc_uid is required.") + return + } + + instanceUID := strings.TrimSpace(plan.VcVdcGroupID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{ + "vdcUid": resources_core.FormatString(plan.VdcUid), + } + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.ValueString() + } + if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "add_vdc", params, operationTimeout); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "add_vdc", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *VcVdcGroupAddVdcResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state VcVdcGroupAddVdcModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *VcVdcGroupAddVdcResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan VcVdcGroupAddVdcModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + instanceUID := strings.TrimSpace(plan.VcVdcGroupID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{ + "vdcUid": resources_core.FormatString(plan.VdcUid), + } + + if err := resources_core.RunOperationByCode(ctx, r.client, instanceUID, "add_vdc", params); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "add_vdc", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *VcVdcGroupAddVdcResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + // No-op: removing the resource does not trigger a remote action. +} + +func (r *VcVdcGroupAddVdcResource) 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/universal_rebuild/internal/resources_gen/29_vc_vdc_group_reconcile_action.go b/universal_rebuild/internal/resources_gen/29_vc_vdc_group_reconcile_action.go new file mode 100644 index 0000000..0676cc7 --- /dev/null +++ b/universal_rebuild/internal/resources_gen/29_vc_vdc_group_reconcile_action.go @@ -0,0 +1,128 @@ +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/types" +) + +// Code generated by tools/gen_v2. DO NOT EDIT. +// Service: vc_vdc_group +// Action: reconcile + +var _ resource.Resource = &VcVdcGroupReconcileResource{} + +// VcVdcGroupReconcileResource triggers a one-time action. +type VcVdcGroupReconcileResource struct { + client *core.UniversalClient +} + +type VcVdcGroupReconcileModel struct { + ID types.String `tfsdk:"id"` + VcVdcGroupID types.String `tfsdk:"vc_vdc_group_id"` + RunID types.String `tfsdk:"run_id"` + OperationTimeout types.String `tfsdk:"operation_timeout"` +} + +func NewVcVdcGroupReconcileResource() resource.Resource { + return &VcVdcGroupReconcileResource{} +} + +func (r *VcVdcGroupReconcileResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_vc_vdc_group_reconcile" +} + +func (r *VcVdcGroupReconcileResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + attrs := map[string]schema.Attribute{ + "id": schema.StringAttribute{Computed: true}, + "vc_vdc_group_id": schema.StringAttribute{Required: true}, + "run_id": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + } + resp.Schema = schema.Schema{Attributes: attrs} +} + +func (r *VcVdcGroupReconcileResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan VcVdcGroupReconcileModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + instanceUID := strings.TrimSpace(plan.VcVdcGroupID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{} + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.ValueString() + } + if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "reconcile", params, operationTimeout); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "reconcile", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *VcVdcGroupReconcileResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state VcVdcGroupReconcileModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *VcVdcGroupReconcileResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan VcVdcGroupReconcileModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + instanceUID := strings.TrimSpace(plan.VcVdcGroupID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{} + + if err := resources_core.RunOperationByCode(ctx, r.client, instanceUID, "reconcile", params); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "reconcile", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *VcVdcGroupReconcileResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + // No-op: removing the resource does not trigger a remote action. +} + +func (r *VcVdcGroupReconcileResource) 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/universal_rebuild/internal/resources_gen/29_vc_vdc_group_remove_vdc_action.go b/universal_rebuild/internal/resources_gen/29_vc_vdc_group_remove_vdc_action.go new file mode 100644 index 0000000..381161d --- /dev/null +++ b/universal_rebuild/internal/resources_gen/29_vc_vdc_group_remove_vdc_action.go @@ -0,0 +1,138 @@ +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/types" +) + +// Code generated by tools/gen_v2. DO NOT EDIT. +// Service: vc_vdc_group +// Action: remove_vdc + +var _ resource.Resource = &VcVdcGroupRemoveVdcResource{} + +// VcVdcGroupRemoveVdcResource triggers a one-time action. +type VcVdcGroupRemoveVdcResource struct { + client *core.UniversalClient +} + +type VcVdcGroupRemoveVdcModel struct { + ID types.String `tfsdk:"id"` + VcVdcGroupID types.String `tfsdk:"vc_vdc_group_id"` + RunID types.String `tfsdk:"run_id"` + OperationTimeout types.String `tfsdk:"operation_timeout"` + VdcName types.String `tfsdk:"vdc_name"` +} + +func NewVcVdcGroupRemoveVdcResource() resource.Resource { + return &VcVdcGroupRemoveVdcResource{} +} + +func (r *VcVdcGroupRemoveVdcResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_vc_vdc_group_remove_vdc" +} + +func (r *VcVdcGroupRemoveVdcResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + attrs := map[string]schema.Attribute{ + "id": schema.StringAttribute{Computed: true}, + "vc_vdc_group_id": schema.StringAttribute{Required: true}, + "run_id": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "vdc_name": schema.StringAttribute{Required: true}, + } + resp.Schema = schema.Schema{Attributes: attrs} +} + +func (r *VcVdcGroupRemoveVdcResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan VcVdcGroupRemoveVdcModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + if plan.VdcName.IsNull() || plan.VdcName.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "vdc_name is required.") + return + } + + instanceUID := strings.TrimSpace(plan.VcVdcGroupID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{ + "vdcName": resources_core.FormatString(plan.VdcName), + } + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.ValueString() + } + if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "remove_vdc", params, operationTimeout); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "remove_vdc", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *VcVdcGroupRemoveVdcResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state VcVdcGroupRemoveVdcModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *VcVdcGroupRemoveVdcResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan VcVdcGroupRemoveVdcModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + instanceUID := strings.TrimSpace(plan.VcVdcGroupID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{ + "vdcName": resources_core.FormatString(plan.VdcName), + } + + if err := resources_core.RunOperationByCode(ctx, r.client, instanceUID, "remove_vdc", params); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "remove_vdc", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *VcVdcGroupRemoveVdcResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + // No-op: removing the resource does not trigger a remote action. +} + +func (r *VcVdcGroupRemoveVdcResource) 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/universal_rebuild/internal/resources_gen/29_vc_vdc_group_resource.go b/universal_rebuild/internal/resources_gen/29_vc_vdc_group_resource.go new file mode 100644 index 0000000..f8f43fa --- /dev/null +++ b/universal_rebuild/internal/resources_gen/29_vc_vdc_group_resource.go @@ -0,0 +1,389 @@ +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/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"` + 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "vdc_uid": schema.StringAttribute{Required: 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 + } + planChanged := false + if !plan.VdcUid.IsNull() && !plan.VdcUid.IsUnknown() { + resolvedVdcUid, err := r.client.ResolveRefSvcParamValue(ctx, 21, plan.VdcUid.ValueString()) + if err != nil { + resp.Diagnostics.AddWarning("Failed to resolve vdc_uid", err.Error()) + } else if resolvedVdcUid != "" && resolvedVdcUid != plan.VdcUid.ValueString() { + plan.VdcUid = types.StringValue(resolvedVdcUid) + planChanged = true + } + } + if planChanged { + resp.Diagnostics.Append(resp.Plan.Set(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.VdcUid.IsNull() && !plan.VdcUid.IsUnknown() && !state.VdcUid.IsNull() && !state.VdcUid.IsUnknown() { + if plan.VdcUid.ValueString() != state.VdcUid.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить vdc_uid", "Параметр задается при создании и не может быть изменен.") + return + } + } + return + } + if config.VdcUid.IsNull() || config.VdcUid.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "vdc_uid is required.") + 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), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 29, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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 + } + 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() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 29, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + params := map[int]string{ + 618: resources_core.FormatString(data.VdcUid), + } + + operationTimeout := "" + if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() { + operationTimeout = data.OperationTimeout.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) + } + } + + 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) + } + } + + 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 + } + + params := map[int]string{} + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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(), 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) + } + } + + 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 := "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 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/universal_rebuild/internal/resources_gen/32_vmpostgre_resource.go b/universal_rebuild/internal/resources_gen/32_vmpostgre_resource.go new file mode 100644 index 0000000..11236dc --- /dev/null +++ b/universal_rebuild/internal/resources_gen/32_vmpostgre_resource.go @@ -0,0 +1,594 @@ +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/stringdefault" + "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"` + NsxtUid types.String `tfsdk:"nsxt_uid"` + ResourceRealm types.String `tfsdk:"resource_realm"` + UserDb types.String `tfsdk:"user_db"` + UserLogin types.String `tfsdk:"user_login"` + UserPassword types.String `tfsdk:"user_password"` + VdcUid types.String `tfsdk:"vdc_uid"` + 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "nsxt_uid": schema.StringAttribute{Required: true, MarkdownDescription: "InstanceUid nsxt. Nsxt должен быть создан
Не изменяется после создания."}, + "resource_realm": schema.StringAttribute{Required: true, 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: "Пароль от доступа к Базе данных
Не изменяется после создания."}, + "vdc_uid": schema.StringAttribute{Required: true, MarkdownDescription: "InstanceUid vdc. Vdc должен быть создан
Не изменяется после создания."}, + "vm_uid": schema.StringAttribute{Required: 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 + } + planChanged := false + if !plan.NsxtUid.IsNull() && !plan.NsxtUid.IsUnknown() { + resolvedNsxtUid, err := r.client.ResolveRefSvcParamValue(ctx, 22, plan.NsxtUid.ValueString()) + if err != nil { + resp.Diagnostics.AddWarning("Failed to resolve nsxt_uid", err.Error()) + } else if resolvedNsxtUid != "" && resolvedNsxtUid != plan.NsxtUid.ValueString() { + plan.NsxtUid = types.StringValue(resolvedNsxtUid) + planChanged = true + } + } + if !plan.VdcUid.IsNull() && !plan.VdcUid.IsUnknown() { + resolvedVdcUid, err := r.client.ResolveRefSvcParamValue(ctx, 21, plan.VdcUid.ValueString()) + if err != nil { + resp.Diagnostics.AddWarning("Failed to resolve vdc_uid", err.Error()) + } else if resolvedVdcUid != "" && resolvedVdcUid != plan.VdcUid.ValueString() { + plan.VdcUid = types.StringValue(resolvedVdcUid) + planChanged = true + } + } + if !plan.VmUid.IsNull() && !plan.VmUid.IsUnknown() { + resolvedVmUid, err := r.client.ResolveRefSvcParamValue(ctx, 23, plan.VmUid.ValueString()) + if err != nil { + resp.Diagnostics.AddWarning("Failed to resolve vm_uid", err.Error()) + } else if resolvedVmUid != "" && resolvedVmUid != plan.VmUid.ValueString() { + plan.VmUid = types.StringValue(resolvedVmUid) + planChanged = true + } + } + if planChanged { + resp.Diagnostics.Append(resp.Plan.Set(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.NsxtUid.IsNull() && !plan.NsxtUid.IsUnknown() && !state.NsxtUid.IsNull() && !state.NsxtUid.IsUnknown() { + if plan.NsxtUid.ValueString() != state.NsxtUid.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить nsxt_uid", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() { + if 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() { + if 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() { + if 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() { + if plan.UserPassword.ValueString() != state.UserPassword.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить user_password", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.VdcUid.IsNull() && !plan.VdcUid.IsUnknown() && !state.VdcUid.IsNull() && !state.VdcUid.IsUnknown() { + if plan.VdcUid.ValueString() != state.VdcUid.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить vdc_uid", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.VmUid.IsNull() && !plan.VmUid.IsUnknown() && !state.VmUid.IsNull() && !state.VmUid.IsUnknown() { + if plan.VmUid.ValueString() != state.VmUid.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить vm_uid", "Параметр задается при создании и не может быть изменен.") + return + } + } + return + } + if config.NsxtUid.IsNull() || config.NsxtUid.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "nsxt_uid is required.") + return + } + if config.ResourceRealm.IsNull() || config.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + return + } + if config.VdcUid.IsNull() || config.VdcUid.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "vdc_uid is required.") + return + } + if config.VmUid.IsNull() || config.VmUid.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "vm_uid is required.") + 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) + } + } + 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{ + 43: resources_core.FormatString(config.VdcUid), + 44: resources_core.FormatString(config.NsxtUid), + 45: resources_core.FormatString(config.VmUid), + 46: resources_core.FormatString(config.UserDb), + 47: resources_core.FormatString(config.UserLogin), + 48: resources_core.FormatString(config.UserPassword), + 859: resources_core.FormatString(config.ResourceRealm), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 32, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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.NsxtUid.IsNull() || data.NsxtUid.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "nsxt_uid is required.") + return + } + if data.ResourceRealm.IsNull() || data.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + return + } + if data.VdcUid.IsNull() || data.VdcUid.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "vdc_uid is required.") + return + } + if data.VmUid.IsNull() || data.VmUid.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "vm_uid is required.") + return + } + 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) + } + } + 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() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 32, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + params := map[int]string{ + 43: resources_core.FormatString(data.VdcUid), + 44: resources_core.FormatString(data.NsxtUid), + 45: resources_core.FormatString(data.VmUid), + 46: resources_core.FormatString(data.UserDb), + 47: resources_core.FormatString(data.UserLogin), + 48: resources_core.FormatString(data.UserPassword), + 859: resources_core.FormatString(data.ResourceRealm), + } + + operationTimeout := "" + if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() { + operationTimeout = data.OperationTimeout.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: "nsxtUid", Field: "NsxtUid", Type: "string"}, + {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: "vdcUid", Field: "VdcUid", Type: "string"}, + {Code: "vmUid", Field: "VmUid", 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) + } + } + 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) + } + } + + 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: "nsxtUid", Field: "NsxtUid", Type: "string"}, + {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: "vdcUid", Field: "VdcUid", Type: "string"}, + {Code: "vmUid", Field: "VmUid", 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) + } + } + 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) + } + } + + 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 + } + + params := map[int]string{} + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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(), 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: "nsxtUid", Field: "NsxtUid", Type: "string"}, + {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: "vdcUid", Field: "VdcUid", Type: "string"}, + {Code: "vmUid", Field: "VmUid", 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) + } + } + 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) + } + } + + 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 := "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 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/universal_rebuild/internal/resources_gen/50_nextcloud_resource.go b/universal_rebuild/internal/resources_gen/50_nextcloud_resource.go new file mode 100644 index 0000000..5509d65 --- /dev/null +++ b/universal_rebuild/internal/resources_gen/50_nextcloud_resource.go @@ -0,0 +1,575 @@ +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/int64default" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "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 +} + +type NextcloudModel struct { + ID types.String `tfsdk:"id"` + ResourceName types.String `tfsdk:"resource_name"` + OperationTimeout types.String `tfsdk:"operation_timeout"` + AppVersion types.String `tfsdk:"app_version"` + DocumentServer types.String `tfsdk:"document_server"` + Domain types.String `tfsdk:"domain"` + PsqlUid types.String `tfsdk:"psql_uid"` + RedisUid types.String `tfsdk:"redis_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 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "app_version": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("32.0.1")}, + "document_server": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("collabora"), MarkdownDescription: "Выбор сервера документов (onlyoffice)/(collabora). onlyoffice пока не доступен
Размер пода collabora:
1.8 ядра. 2Gi ОЗУ Не изменяется после создания."}, + "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("web01"), MarkdownDescription: "Если будет указан FQDN, то происходят проверки DNS на валидность А-записи, или будет добавлено в зону resourceRealm Не изменяется после создания."}, + "psql_uid": schema.StringAttribute{Required: true, MarkdownDescription: "UI display_name for service_id=90 (mapped to UUID in core) Не изменяется после создания."}, + "redis_uid": schema.StringAttribute{Required: true, MarkdownDescription: "UI display_name for service_id=91 (mapped to UUID in core) Не изменяется после создания."}, + "resource_c_p_u": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1000), MarkdownDescription: "Квота ядра пода (Указывается в mili). 1 ядро = 1000 Mili"}, + "resource_disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(2), MarkdownDescription: "Квота диска (Указывается в GIGAbytes)
Диск не может быть меньше 2G (!)"}, + "resource_instances": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Количество узлов
Не может пока быть больше одного, так как нужны SC под RWMany"}, + "resource_memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1024), 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 *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 + } + planChanged := false + if !plan.PsqlUid.IsNull() && !plan.PsqlUid.IsUnknown() { + resolvedPsqlUid, err := r.client.ResolveRefSvcParamValue(ctx, 90, plan.PsqlUid.ValueString()) + if err != nil { + resp.Diagnostics.AddWarning("Failed to resolve psql_uid", err.Error()) + } else if resolvedPsqlUid != "" && resolvedPsqlUid != plan.PsqlUid.ValueString() { + plan.PsqlUid = types.StringValue(resolvedPsqlUid) + planChanged = true + } + } + if !plan.RedisUid.IsNull() && !plan.RedisUid.IsUnknown() { + resolvedRedisUid, err := r.client.ResolveRefSvcParamValue(ctx, 91, plan.RedisUid.ValueString()) + if err != nil { + resp.Diagnostics.AddWarning("Failed to resolve redis_uid", err.Error()) + } else if resolvedRedisUid != "" && resolvedRedisUid != plan.RedisUid.ValueString() { + plan.RedisUid = types.StringValue(resolvedRedisUid) + planChanged = true + } + } + if planChanged { + resp.Diagnostics.Append(resp.Plan.Set(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.DocumentServer.IsNull() && !plan.DocumentServer.IsUnknown() && !state.DocumentServer.IsNull() && !state.DocumentServer.IsUnknown() { + if plan.DocumentServer.ValueString() != state.DocumentServer.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить document_server", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.Domain.IsNull() && !plan.Domain.IsUnknown() && !state.Domain.IsNull() && !state.Domain.IsUnknown() { + if plan.Domain.ValueString() != state.Domain.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить domain", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.PsqlUid.IsNull() && !plan.PsqlUid.IsUnknown() && !state.PsqlUid.IsNull() && !state.PsqlUid.IsUnknown() { + if plan.PsqlUid.ValueString() != state.PsqlUid.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить psql_uid", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.RedisUid.IsNull() && !plan.RedisUid.IsUnknown() && !state.RedisUid.IsNull() && !state.RedisUid.IsUnknown() { + if plan.RedisUid.ValueString() != state.RedisUid.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить redis_uid", "Параметр задается при создании и не может быть изменен.") + return + } + } + return + } + if config.PsqlUid.IsNull() || config.PsqlUid.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "psql_uid is required.") + return + } + if config.RedisUid.IsNull() || config.RedisUid.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "redis_uid is required.") + 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) + } + } + if !config.RedisUid.IsNull() && !config.RedisUid.IsUnknown() { + resolvedRedisUid, err := r.client.ResolveRefSvcParamValue(ctx, 91, config.RedisUid.ValueString()) + if err != nil { + resp.Diagnostics.AddWarning("Failed to resolve redis_uid", err.Error()) + } else if resolvedRedisUid != "" && resolvedRedisUid != config.RedisUid.ValueString() { + config.RedisUid = types.StringValue(resolvedRedisUid) + } + } + params := map[int]string{ + 21: resources_core.FormatString(config.Domain), + 99: resources_core.FormatInt64(config.ResourceCPU), + 100: resources_core.FormatInt64(config.ResourceMemory), + 101: resources_core.FormatInt64(config.ResourceDisk), + 192: resources_core.FormatString(config.DocumentServer), + 470: resources_core.FormatInt64(config.ResourceInstances), + 564: resources_core.FormatString(config.PsqlUid), + 569: resources_core.FormatString(config.AppVersion), + 570: resources_core.FormatString(config.RedisUid), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 50, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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 + } + if data.PsqlUid.IsNull() || data.PsqlUid.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "psql_uid is required.") + return + } + if data.RedisUid.IsNull() || data.RedisUid.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "redis_uid is required.") + return + } + 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) + } + } + if !data.RedisUid.IsNull() && !data.RedisUid.IsUnknown() { + resolvedRedisUid, err := r.client.ResolveRefSvcParamValue(ctx, 91, data.RedisUid.ValueString()) + if err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + if resolvedRedisUid != "" && resolvedRedisUid != data.RedisUid.ValueString() { + data.RedisUid = types.StringValue(resolvedRedisUid) + } + } + + resourceName := data.ResourceName.ValueString() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 50, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + params := map[int]string{ + 21: resources_core.FormatString(data.Domain), + 99: resources_core.FormatInt64(data.ResourceCPU), + 100: resources_core.FormatInt64(data.ResourceMemory), + 101: resources_core.FormatInt64(data.ResourceDisk), + 192: resources_core.FormatString(data.DocumentServer), + 470: resources_core.FormatInt64(data.ResourceInstances), + 564: resources_core.FormatString(data.PsqlUid), + 569: resources_core.FormatString(data.AppVersion), + 570: resources_core.FormatString(data.RedisUid), + } + + operationTimeout := "" + if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() { + operationTimeout = data.OperationTimeout.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: "appVersion", Field: "AppVersion", Type: "string"}, + {Code: "documentServer", Field: "DocumentServer", Type: "string"}, + {Code: "domain", Field: "Domain", Type: "string"}, + {Code: "psqlUid", Field: "PsqlUid", Type: "string"}, + {Code: "redisUid", Field: "RedisUid", 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) + } + } + if !state.RedisUid.IsNull() && !state.RedisUid.IsUnknown() { + resolvedRedisUid, err := r.client.ResolveRefSvcParamValue(ctx, 91, state.RedisUid.ValueString()) + if err != nil { + resp.Diagnostics.AddWarning("Failed to resolve redis_uid", err.Error()) + } else if resolvedRedisUid != "" && resolvedRedisUid != state.RedisUid.ValueString() { + state.RedisUid = types.StringValue(resolvedRedisUid) + } + } + + 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: "appVersion", Field: "AppVersion", Type: "string"}, + {Code: "documentServer", Field: "DocumentServer", Type: "string"}, + {Code: "domain", Field: "Domain", Type: "string"}, + {Code: "psqlUid", Field: "PsqlUid", Type: "string"}, + {Code: "redisUid", Field: "RedisUid", 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) + } + } + if !newState.RedisUid.IsNull() && !newState.RedisUid.IsUnknown() { + resolvedRedisUid, err := r.client.ResolveRefSvcParamValue(ctx, 91, newState.RedisUid.ValueString()) + if err != nil { + resp.Diagnostics.AddWarning("Failed to resolve redis_uid", err.Error()) + } else if resolvedRedisUid != "" && resolvedRedisUid != newState.RedisUid.ValueString() { + newState.RedisUid = types.StringValue(resolvedRedisUid) + } + } + + 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 { + 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.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 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 + } + + params := map[int]string{ + 178: resources_core.FormatInt64(plan.ResourceCPU), + 179: resources_core.FormatInt64(plan.ResourceMemory), + 180: resources_core.FormatInt64(plan.ResourceDisk), + 547: resources_core.FormatInt64(plan.ResourceInstances), + 571: resources_core.FormatString(plan.AppVersion), + } + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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: "appVersion", Field: "AppVersion", Type: "string"}, + {Code: "documentServer", Field: "DocumentServer", Type: "string"}, + {Code: "domain", Field: "Domain", Type: "string"}, + {Code: "psqlUid", Field: "PsqlUid", Type: "string"}, + {Code: "redisUid", Field: "RedisUid", 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) + } + } + if !state.RedisUid.IsNull() && !state.RedisUid.IsUnknown() { + resolvedRedisUid, err := r.client.ResolveRefSvcParamValue(ctx, 91, state.RedisUid.ValueString()) + if err != nil { + resp.Diagnostics.AddWarning("Failed to resolve redis_uid", err.Error()) + } else if resolvedRedisUid != "" && resolvedRedisUid != state.RedisUid.ValueString() { + state.RedisUid = types.StringValue(resolvedRedisUid) + } + } + + 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 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/universal_rebuild/internal/resources_gen/50_nextcloud_restart_action.go b/universal_rebuild/internal/resources_gen/50_nextcloud_restart_action.go new file mode 100644 index 0000000..7568ac5 --- /dev/null +++ b/universal_rebuild/internal/resources_gen/50_nextcloud_restart_action.go @@ -0,0 +1,128 @@ +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/types" +) + +// Code generated by tools/gen_v2. DO NOT EDIT. +// Service: nextcloud +// Action: restart + +var _ resource.Resource = &NextcloudRestartResource{} + +// NextcloudRestartResource triggers a one-time action. +type NextcloudRestartResource struct { + client *core.UniversalClient +} + +type NextcloudRestartModel struct { + ID types.String `tfsdk:"id"` + NextcloudID types.String `tfsdk:"nextcloud_id"` + RunID types.String `tfsdk:"run_id"` + OperationTimeout types.String `tfsdk:"operation_timeout"` +} + +func NewNextcloudRestartResource() resource.Resource { + return &NextcloudRestartResource{} +} + +func (r *NextcloudRestartResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_nextcloud_restart" +} + +func (r *NextcloudRestartResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + attrs := map[string]schema.Attribute{ + "id": schema.StringAttribute{Computed: true}, + "nextcloud_id": schema.StringAttribute{Required: true}, + "run_id": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + } + resp.Schema = schema.Schema{Attributes: attrs} +} + +func (r *NextcloudRestartResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan NextcloudRestartModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + instanceUID := strings.TrimSpace(plan.NextcloudID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{} + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.ValueString() + } + if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "restart", params, operationTimeout); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "restart", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *NextcloudRestartResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state NextcloudRestartModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *NextcloudRestartResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan NextcloudRestartModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + instanceUID := strings.TrimSpace(plan.NextcloudID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{} + + if err := resources_core.RunOperationByCode(ctx, r.client, instanceUID, "restart", params); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "restart", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *NextcloudRestartResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + // No-op: removing the resource does not trigger a remote action. +} + +func (r *NextcloudRestartResource) 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/universal_rebuild/internal/resources_gen/81_superset_resource.go b/universal_rebuild/internal/resources_gen/81_superset_resource.go new file mode 100644 index 0000000..ab9d101 --- /dev/null +++ b/universal_rebuild/internal/resources_gen/81_superset_resource.go @@ -0,0 +1,411 @@ +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/int64default" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "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"` + 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("web01"), 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() { + if plan.Domain.ValueString() != state.Domain.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить domain", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.Emails.IsNull() && !plan.Emails.IsUnknown() && !state.Emails.IsNull() && !state.Emails.IsUnknown() { + if 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() { + if plan.ResourceRealm.ValueString() != state.ResourceRealm.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.") + return + } + } + return + } + if config.ResourceRealm.IsNull() || config.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + 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), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 81, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 81, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + 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() + } + 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 + } + + params := map[int]string{} + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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(), 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 := "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 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/universal_rebuild/internal/resources_gen/82_harbor_resource.go b/universal_rebuild/internal/resources_gen/82_harbor_resource.go new file mode 100644 index 0000000..4e1e3e3 --- /dev/null +++ b/universal_rebuild/internal/resources_gen/82_harbor_resource.go @@ -0,0 +1,440 @@ +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/int64default" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "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"` + Domain types.String `tfsdk:"domain"` + Emails types.String `tfsdk:"emails"` + 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("web01"), MarkdownDescription: "Если будет указан FQDN, то происходят проверки DNS на валидность А-записи, или будет добавлено в зону resourceRealm Не изменяется после создания."}, + "emails": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("testuser1"), MarkdownDescription: "Учётная запись, которой будут выданы админские права. Обязана находиться в Keycloak. Можно передавать несколько через пробел Не изменяется после создания."}, + "resource_c_p_u": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(100), 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(200), MarkdownDescription: "Квота памяти пода (Указывается в Megabytes) Не изменяется после создания."}, + "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Платформа для развертывания Не изменяется после создания."}, + "s3_uid": schema.StringAttribute{Required: 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 + } + planChanged := false + if !plan.S3Uid.IsNull() && !plan.S3Uid.IsUnknown() { + resolvedS3Uid, err := r.client.ResolveRefSvcParamValue(ctx, 12, plan.S3Uid.ValueString()) + if err != nil { + resp.Diagnostics.AddWarning("Failed to resolve s3_uid", err.Error()) + } else if resolvedS3Uid != "" && resolvedS3Uid != plan.S3Uid.ValueString() { + plan.S3Uid = types.StringValue(resolvedS3Uid) + planChanged = true + } + } + if planChanged { + resp.Diagnostics.Append(resp.Plan.Set(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() { + if plan.Domain.ValueString() != state.Domain.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить domain", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.Emails.IsNull() && !plan.Emails.IsUnknown() && !state.Emails.IsNull() && !state.Emails.IsUnknown() { + if 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.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() { + if 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() { + if plan.S3Uid.ValueString() != state.S3Uid.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить s3_uid", "Параметр задается при создании и не может быть изменен.") + return + } + } + return + } + if config.ResourceRealm.IsNull() || config.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + return + } + if config.S3Uid.IsNull() || config.S3Uid.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "s3_uid is required.") + 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), + 17: resources_core.FormatString(config.Emails), + 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), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 82, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 82, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + params := map[int]string{ + 16: resources_core.FormatString(data.Domain), + 17: resources_core.FormatString(data.Emails), + 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() + } + 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: "emails", Field: "Emails", 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 *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: "emails", Field: "Emails", 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 *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 { + 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 + } + + params := map[int]string{} + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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(), 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: "emails", Field: "Emails", 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 *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 := "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 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/universal_rebuild/internal/resources_gen/88_k8s_ziti_controller_resource.go b/universal_rebuild/internal/resources_gen/88_k8s_ziti_controller_resource.go new file mode 100644 index 0000000..4ff2545 --- /dev/null +++ b/universal_rebuild/internal/resources_gen/88_k8s_ziti_controller_resource.go @@ -0,0 +1,398 @@ +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/int64default" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "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"` + 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("web01"), 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() { + if 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() { + if plan.ResourceRealm.ValueString() != state.ResourceRealm.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.") + return + } + } + return + } + if config.ResourceRealm.IsNull() || config.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + 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), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 88, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 88, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + 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() + } + 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 + } + + params := map[int]string{} + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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(), 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 := "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 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/universal_rebuild/internal/resources_gen/89_flask_resource.go b/universal_rebuild/internal/resources_gen/89_flask_resource.go new file mode 100644 index 0000000..10cf82a --- /dev/null +++ b/universal_rebuild/internal/resources_gen/89_flask_resource.go @@ -0,0 +1,445 @@ +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/int64default" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "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 +} + +type FlaskModel struct { + ID types.String `tfsdk:"id"` + ResourceName types.String `tfsdk:"resource_name"` + OperationTimeout types.String `tfsdk:"operation_timeout"` + Domain types.String `tfsdk:"domain"` + GitPath types.String `tfsdk:"git_path"` + HealthPath types.String `tfsdk:"health_path"` + JsonEnv types.String `tfsdk:"json_env"` + 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 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("web01"), MarkdownDescription: "Если будет указан FQDN, то происходят проверки DNS на валидность А-записи, или будет добавлено в зону resourceRealm Не изменяется после создания."}, + "git_path": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("https://github.com/Foxyhhd/Baldurs-Gate-test.git"), MarkdownDescription: "Путь до Git, который будет webroot для сайта"}, + "health_path": schema.StringAttribute{Optional: true, MarkdownDescription: "Путь до healtcheck для запуска пода в Kubernetes, который отдаст 200 код Не изменяется после создания."}, + "json_env": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("{ "param": "value" }"), MarkdownDescription: "Массив переменных, будут переданы в env приложения"}, + "resource_c_p_u": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(300), MarkdownDescription: "Квота ядра пода (milicores)"}, + "resource_instances": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Количество узлов"}, + "resource_memory": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(256), MarkdownDescription: "Квота памяти пода (MBytes)"}, + "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 *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 + } + } + if !plan.Domain.IsNull() && !plan.Domain.IsUnknown() && !state.Domain.IsNull() && !state.Domain.IsUnknown() { + if plan.Domain.ValueString() != state.Domain.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить domain", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.HealthPath.IsNull() && !plan.HealthPath.IsUnknown() && !state.HealthPath.IsNull() && !state.HealthPath.IsUnknown() { + if plan.HealthPath.ValueString() != state.HealthPath.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить health_path", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() { + if plan.ResourceRealm.ValueString() != state.ResourceRealm.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.") + return + } + } + return + } + if config.ResourceRealm.IsNull() || config.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + 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{ + 248: resources_core.FormatString(config.Domain), + 249: resources_core.FormatString(config.ResourceRealm), + 250: resources_core.FormatInt64(config.ResourceCPU), + 251: resources_core.FormatInt64(config.ResourceMemory), + 252: resources_core.FormatInt64(config.ResourceInstances), + 253: resources_core.FormatString(config.GitPath), + 254: resources_core.FormatString(config.JsonEnv), + 255: resources_core.FormatString(config.HealthPath), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 89, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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 + } + if data.ResourceRealm.IsNull() || data.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + return + } + + resourceName := data.ResourceName.ValueString() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 89, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + params := map[int]string{ + 248: resources_core.FormatString(data.Domain), + 249: resources_core.FormatString(data.ResourceRealm), + 250: resources_core.FormatInt64(data.ResourceCPU), + 251: resources_core.FormatInt64(data.ResourceMemory), + 252: resources_core.FormatInt64(data.ResourceInstances), + 253: resources_core.FormatString(data.GitPath), + 254: resources_core.FormatString(data.JsonEnv), + 255: resources_core.FormatString(data.HealthPath), + } + + operationTimeout := "" + if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() { + operationTimeout = data.OperationTimeout.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: "domain", Field: "Domain", Type: "string"}, + {Code: "gitPath", Field: "GitPath", Type: "string"}, + {Code: "healthPath", Field: "HealthPath", Type: "string"}, + {Code: "jsonEnv", Field: "JsonEnv", 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 *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: "domain", Field: "Domain", Type: "string"}, + {Code: "gitPath", Field: "GitPath", Type: "string"}, + {Code: "healthPath", Field: "HealthPath", Type: "string"}, + {Code: "jsonEnv", Field: "JsonEnv", 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 *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.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 + } + } + } + if !hasServiceParamChanges { + if plan.GitPath.IsNull() != state.GitPath.IsNull() || plan.GitPath.IsUnknown() != state.GitPath.IsUnknown() { + hasServiceParamChanges = true + } else if !plan.GitPath.IsNull() && !plan.GitPath.IsUnknown() && !state.GitPath.IsNull() && !state.GitPath.IsUnknown() { + if plan.GitPath.ValueString() != state.GitPath.ValueString() { + hasServiceParamChanges = true + } + } + } + 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 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 + } + + params := map[int]string{ + 451: resources_core.FormatInt64(plan.ResourceCPU), + 452: resources_core.FormatInt64(plan.ResourceMemory), + 453: resources_core.FormatInt64(plan.ResourceInstances), + 454: resources_core.FormatString(plan.GitPath), + 455: resources_core.FormatString(plan.JsonEnv), + } + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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(), 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: "domain", Field: "Domain", Type: "string"}, + {Code: "gitPath", Field: "GitPath", Type: "string"}, + {Code: "healthPath", Field: "HealthPath", Type: "string"}, + {Code: "jsonEnv", Field: "JsonEnv", 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 *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 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/universal_rebuild/internal/resources_gen/90_postgres_database_resource.go b/universal_rebuild/internal/resources_gen/90_postgres_database_resource.go new file mode 100644 index 0000000..79ea316 --- /dev/null +++ b/universal_rebuild/internal/resources_gen/90_postgres_database_resource.go @@ -0,0 +1,334 @@ +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"` + 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}, + "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(false)}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "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 err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_database", params, operationTimeout); err != nil { + if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(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 { + plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "database", idParams)) + resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект подтверждён в state_out, выполняется усыновление") + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) + return + } + } + resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в 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("Нарушена консистентность", "Операция 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 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 { + if skipMissingOnDelete { + resp.Diagnostics.AddWarning("Подресурс не найден", "Объект отсутствует и будет пропущен: "+targetValue) + return + } + resp.Diagnostics.AddError("Подресурс не найден", "Объект отсутствует: "+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 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/universal_rebuild/internal/resources_gen/90_postgres_recovery_action.go b/universal_rebuild/internal/resources_gen/90_postgres_recovery_action.go new file mode 100644 index 0000000..51004dc --- /dev/null +++ b/universal_rebuild/internal/resources_gen/90_postgres_recovery_action.go @@ -0,0 +1,155 @@ +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/int64default" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +// Code generated by tools/gen_v2. DO NOT EDIT. +// Service: postgres +// Action: recovery + +var _ resource.Resource = &PostgresRecoveryResource{} + +// PostgresRecoveryResource triggers a one-time action. +type PostgresRecoveryResource struct { + client *core.UniversalClient +} + +type PostgresRecoveryModel struct { + ID types.String `tfsdk:"id"` + PostgresID types.String `tfsdk:"postgres_id"` + RunID types.String `tfsdk:"run_id"` + OperationTimeout types.String `tfsdk:"operation_timeout"` + ResourceInstances types.Int64 `tfsdk:"resource_instances"` + ResourceMemory types.Int64 `tfsdk:"resource_memory"` + ResourceCPU types.Int64 `tfsdk:"resource_c_p_u"` + ResourceDisk types.Int64 `tfsdk:"resource_disk"` + ResourceRealm types.String `tfsdk:"resource_realm"` +} + +func NewPostgresRecoveryResource() resource.Resource { + return &PostgresRecoveryResource{} +} + +func (r *PostgresRecoveryResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_postgres_recovery" +} + +func (r *PostgresRecoveryResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + attrs := map[string]schema.Attribute{ + "id": schema.StringAttribute{Computed: true}, + "postgres_id": schema.StringAttribute{Required: true}, + "run_id": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "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_c_p_u": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(500), MarkdownDescription: "Квота ядра пода (Указывается в mili)
"}, + "resource_disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1), MarkdownDescription: "Квота диска (Указывается в GIGAbytes)"}, + "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Платформа для развертывания"}, + } + resp.Schema = schema.Schema{Attributes: attrs} +} + +func (r *PostgresRecoveryResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan PostgresRecoveryModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + if plan.ResourceRealm.IsNull() || plan.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + return + } + + instanceUID := strings.TrimSpace(plan.PostgresID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{ + "resourceInstances": resources_core.FormatInt64(plan.ResourceInstances), + "resourceMemory": resources_core.FormatInt64(plan.ResourceMemory), + "resourceCPU": resources_core.FormatInt64(plan.ResourceCPU), + "resourceDisk": resources_core.FormatInt64(plan.ResourceDisk), + "resourceRealm": resources_core.FormatString(plan.ResourceRealm), + } + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.ValueString() + } + if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "recovery", params, operationTimeout); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "recovery", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *PostgresRecoveryResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state PostgresRecoveryModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *PostgresRecoveryResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan PostgresRecoveryModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + instanceUID := strings.TrimSpace(plan.PostgresID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{ + "resourceInstances": resources_core.FormatInt64(plan.ResourceInstances), + "resourceMemory": resources_core.FormatInt64(plan.ResourceMemory), + "resourceCPU": resources_core.FormatInt64(plan.ResourceCPU), + "resourceDisk": resources_core.FormatInt64(plan.ResourceDisk), + "resourceRealm": resources_core.FormatString(plan.ResourceRealm), + } + + if err := resources_core.RunOperationByCode(ctx, r.client, instanceUID, "recovery", params); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "recovery", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *PostgresRecoveryResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + // No-op: removing the resource does not trigger a remote action. +} + +func (r *PostgresRecoveryResource) 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/universal_rebuild/internal/resources_gen/90_postgres_resource.go b/universal_rebuild/internal/resources_gen/90_postgres_resource.go new file mode 100644 index 0000000..bf9c85b --- /dev/null +++ b/universal_rebuild/internal/resources_gen/90_postgres_resource.go @@ -0,0 +1,683 @@ +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/int64default" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "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 +} + +type PostgresModel struct { + ID types.String `tfsdk:"id"` + ResourceName types.String `tfsdk:"resource_name"` + OperationTimeout types.String `tfsdk:"operation_timeout"` + AllowNoSSL types.Bool `tfsdk:"allow_no_s_s_l"` + AppVersion types.String `tfsdk:"app_version"` + AutoScale types.Bool `tfsdk:"auto_scale"` + AutoScalePercentage types.Int64 `tfsdk:"auto_scale_percentage"` + AutoScaleQuotaGb types.String `tfsdk:"auto_scale_quota_gb"` + AutoScaleTechWindow types.Int64 `tfsdk:"auto_scale_tech_window"` + EnablePgPoolerMaster types.Bool `tfsdk:"enable_pg_pooler_master"` + EnablePgPoolerSlave types.Bool `tfsdk:"enable_pg_pooler_slave"` + ExtBACKUPNUMTORETAIN types.Int64 `tfsdk:"ext__b_a_c_k_u_p__n_u_m__t_o__r_e_t_a_i_n"` + ExtBACKUPSCHEDULE types.String `tfsdk:"ext__b_a_c_k_u_p__s_c_h_e_d_u_l_e"` + IpSpaceNameMaster types.String `tfsdk:"ip_space_name_master"` + IpSpaceNameSlave types.String `tfsdk:"ip_space_name_slave"` + JsonParameters types.String `tfsdk:"json_parameters"` + NeedExternalAddressMaster types.Bool `tfsdk:"need_external_address_master"` + NeedExternalAddressSlave types.Bool `tfsdk:"need_external_address_slave"` + ResourceCPU types.Int64 `tfsdk:"resource_c_p_u"` + ResourceDisk types.String `tfsdk:"resource_disk"` + 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 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "allow_no_s_s_l": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "По умолчанию подключение обязательное (sslmode=require). Выставление в true отключит этот параметр"}, + "app_version": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("17"), MarkdownDescription: "Версия PostgreSQL"}, + "auto_scale": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Включает автоскейлинг PV. При включении параметра необходимо настроить autoScalePercentage и autoScaleTechWindow. Алерт при срабатывании вызывает modify у текущей услуги Не изменяется после создания."}, + "auto_scale_percentage": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(10), MarkdownDescription: "Требует включения autoScale. Позволяет указать в процентах расширение от текущего макс объема Не изменяется после создания."}, + "auto_scale_quota_gb": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("1"), MarkdownDescription: "Квота для autoScale Не изменяется после создания."}, + "auto_scale_tech_window": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(0), MarkdownDescription: "Требует включения autoScale. Окно обновления (пока не реализовано). Указывается час в виде Integer (0 / 5 / 12 / 23) Не изменяется после создания."}, + "enable_pg_pooler_master": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Включает pgPooler (на запись). Будет создан новый под"}, + "enable_pg_pooler_slave": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Включает pgPooler (на чтение). Будет создан новый под"}, + "ext__b_a_c_k_u_p__n_u_m__t_o__r_e_t_a_i_n": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(7), MarkdownDescription: "Не обязательный. Количество сохраняемых бекапов"}, + "ext__b_a_c_k_u_p__s_c_h_e_d_u_l_e": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("0 0 * * *"), MarkdownDescription: "Не обязательный. Время запуска бекапа"}, + "ip_space_name_master": schema.StringAttribute{Optional: true, MarkdownDescription: "Имя ipSpace для публикации VIP master. Не может быть пустым, если включен needExternalAddressMaster. Пример: `internet-no-antiddos-v1`"}, + "ip_space_name_slave": schema.StringAttribute{Optional: true, MarkdownDescription: "Имя ipSpace для публикации VIP slave. Не может быть пустым, если включен needExternalAddressSlave"}, + "json_parameters": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("{ \"log_connections\": \"off\", \"log_disconnections\": \"off\" }"), MarkdownDescription: "Массив переменных, более подробнее про настройку можно посмотреть https://www.postgresql.org/docs/current/runtime-config.html"}, + "need_external_address_master": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Выделяет внешний (белый) IP для доступа к master"}, + "need_external_address_slave": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Выделяет внешний (белый) IP для доступа к slave. Будет работать, если slave в принципе есть"}, + "resource_c_p_u": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(500), MarkdownDescription: "Квота ядра пода (milicores)"}, + "resource_disk": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("10"), 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: "Платформа для развертывания Не изменяется после создания."}, + "s3_uid": schema.StringAttribute{Required: true, MarkdownDescription: "Экземпляр (учетная запись) S3 для резервного копирования. Резервное копирование обязательно Не изменяется после создания."}, + "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 + } + planChanged := false + if !plan.S3Uid.IsNull() && !plan.S3Uid.IsUnknown() { + resolvedS3Uid, err := r.client.ResolveRefSvcParamValue(ctx, 12, plan.S3Uid.ValueString()) + if err != nil { + resp.Diagnostics.AddWarning("Failed to resolve s3_uid", err.Error()) + } else if resolvedS3Uid != "" && resolvedS3Uid != plan.S3Uid.ValueString() { + plan.S3Uid = types.StringValue(resolvedS3Uid) + planChanged = true + } + } + if planChanged { + resp.Diagnostics.Append(resp.Plan.Set(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.AutoScale.IsNull() && !plan.AutoScale.IsUnknown() && !state.AutoScale.IsNull() && !state.AutoScale.IsUnknown() { + if plan.AutoScale.ValueBool() != state.AutoScale.ValueBool() { + resp.Diagnostics.AddError("Нельзя изменить auto_scale", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.AutoScalePercentage.IsNull() && !plan.AutoScalePercentage.IsUnknown() && !state.AutoScalePercentage.IsNull() && !state.AutoScalePercentage.IsUnknown() { + if plan.AutoScalePercentage.ValueInt64() != state.AutoScalePercentage.ValueInt64() { + resp.Diagnostics.AddError("Нельзя изменить auto_scale_percentage", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.AutoScaleQuotaGb.IsNull() && !plan.AutoScaleQuotaGb.IsUnknown() && !state.AutoScaleQuotaGb.IsNull() && !state.AutoScaleQuotaGb.IsUnknown() { + if plan.AutoScaleQuotaGb.ValueString() != state.AutoScaleQuotaGb.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить auto_scale_quota_gb", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.AutoScaleTechWindow.IsNull() && !plan.AutoScaleTechWindow.IsUnknown() && !state.AutoScaleTechWindow.IsNull() && !state.AutoScaleTechWindow.IsUnknown() { + if plan.AutoScaleTechWindow.ValueInt64() != state.AutoScaleTechWindow.ValueInt64() { + resp.Diagnostics.AddError("Нельзя изменить auto_scale_tech_window", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() { + if 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() { + if plan.S3Uid.ValueString() != state.S3Uid.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить s3_uid", "Параметр задается при создании и не может быть изменен.") + return + } + } + return + } + if config.ResourceRealm.IsNull() || config.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + return + } + if config.S3Uid.IsNull() || config.S3Uid.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "s3_uid is required.") + 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{ + 23: resources_core.FormatString(config.S3Uid), + 80: resources_core.FormatInt64(config.ResourceInstances), + 81: resources_core.FormatInt64(config.ResourceMemory), + 82: resources_core.FormatInt64(config.ResourceCPU), + 83: resources_core.FormatString(config.ResourceDisk), + 102: resources_core.FormatString(config.ResourceRealm), + 145: resources_core.FormatBool(config.NeedExternalAddressMaster), + 146: resources_core.FormatBool(config.NeedExternalAddressSlave), + 265: resources_core.FormatString(config.ExtBACKUPSCHEDULE), + 266: resources_core.FormatInt64(config.ExtBACKUPNUMTORETAIN), + 310: resources_core.FormatString(config.AppVersion), + 311: resources_core.FormatString(config.JsonParameters), + 312: resources_core.FormatBool(config.EnablePgPoolerMaster), + 313: resources_core.FormatBool(config.EnablePgPoolerSlave), + 314: resources_core.FormatBool(config.AllowNoSSL), + 329: resources_core.FormatBool(config.AutoScale), + 330: resources_core.FormatInt64(config.AutoScalePercentage), + 331: resources_core.FormatInt64(config.AutoScaleTechWindow), + 337: resources_core.FormatString(config.IpSpaceNameMaster), + 338: resources_core.FormatString(config.IpSpaceNameSlave), + 339: resources_core.FormatString(config.AutoScaleQuotaGb), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 90, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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 + } + 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() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 90, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + params := map[int]string{ + 23: resources_core.FormatString(data.S3Uid), + 80: resources_core.FormatInt64(data.ResourceInstances), + 81: resources_core.FormatInt64(data.ResourceMemory), + 82: resources_core.FormatInt64(data.ResourceCPU), + 83: resources_core.FormatString(data.ResourceDisk), + 102: resources_core.FormatString(data.ResourceRealm), + 145: resources_core.FormatBool(data.NeedExternalAddressMaster), + 146: resources_core.FormatBool(data.NeedExternalAddressSlave), + 265: resources_core.FormatString(data.ExtBACKUPSCHEDULE), + 266: resources_core.FormatInt64(data.ExtBACKUPNUMTORETAIN), + 310: resources_core.FormatString(data.AppVersion), + 311: resources_core.FormatString(data.JsonParameters), + 312: resources_core.FormatBool(data.EnablePgPoolerMaster), + 313: resources_core.FormatBool(data.EnablePgPoolerSlave), + 314: resources_core.FormatBool(data.AllowNoSSL), + 329: resources_core.FormatBool(data.AutoScale), + 330: resources_core.FormatInt64(data.AutoScalePercentage), + 331: resources_core.FormatInt64(data.AutoScaleTechWindow), + 337: resources_core.FormatString(data.IpSpaceNameMaster), + 338: resources_core.FormatString(data.IpSpaceNameSlave), + 339: resources_core.FormatString(data.AutoScaleQuotaGb), + } + + operationTimeout := "" + if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() { + operationTimeout = data.OperationTimeout.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: "allowNoSSL", Field: "AllowNoSSL", Type: "bool"}, + {Code: "appVersion", Field: "AppVersion", Type: "string"}, + {Code: "autoScale", Field: "AutoScale", Type: "bool"}, + {Code: "autoScalePercentage", Field: "AutoScalePercentage", Type: "int64"}, + {Code: "autoScaleQuotaGb", Field: "AutoScaleQuotaGb", Type: "string"}, + {Code: "autoScaleTechWindow", Field: "AutoScaleTechWindow", Type: "int64"}, + {Code: "enablePgPoolerMaster", Field: "EnablePgPoolerMaster", Type: "bool"}, + {Code: "enablePgPoolerSlave", Field: "EnablePgPoolerSlave", Type: "bool"}, + {Code: "ext_BACKUP_NUM_TO_RETAIN", Field: "ExtBACKUPNUMTORETAIN", Type: "int64"}, + {Code: "ext_BACKUP_SCHEDULE", Field: "ExtBACKUPSCHEDULE", Type: "string"}, + {Code: "ipSpaceNameMaster", Field: "IpSpaceNameMaster", Type: "string"}, + {Code: "ipSpaceNameSlave", Field: "IpSpaceNameSlave", Type: "string"}, + {Code: "jsonParameters", Field: "JsonParameters", Type: "string"}, + {Code: "needExternalAddressMaster", Field: "NeedExternalAddressMaster", Type: "bool"}, + {Code: "needExternalAddressSlave", Field: "NeedExternalAddressSlave", Type: "bool"}, + {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"}, + {Code: "resourceDisk", Field: "ResourceDisk", Type: "string"}, + {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 *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: "allowNoSSL", Field: "AllowNoSSL", Type: "bool"}, + {Code: "appVersion", Field: "AppVersion", Type: "string"}, + {Code: "autoScale", Field: "AutoScale", Type: "bool"}, + {Code: "autoScalePercentage", Field: "AutoScalePercentage", Type: "int64"}, + {Code: "autoScaleQuotaGb", Field: "AutoScaleQuotaGb", Type: "string"}, + {Code: "autoScaleTechWindow", Field: "AutoScaleTechWindow", Type: "int64"}, + {Code: "enablePgPoolerMaster", Field: "EnablePgPoolerMaster", Type: "bool"}, + {Code: "enablePgPoolerSlave", Field: "EnablePgPoolerSlave", Type: "bool"}, + {Code: "ext_BACKUP_NUM_TO_RETAIN", Field: "ExtBACKUPNUMTORETAIN", Type: "int64"}, + {Code: "ext_BACKUP_SCHEDULE", Field: "ExtBACKUPSCHEDULE", Type: "string"}, + {Code: "ipSpaceNameMaster", Field: "IpSpaceNameMaster", Type: "string"}, + {Code: "ipSpaceNameSlave", Field: "IpSpaceNameSlave", Type: "string"}, + {Code: "jsonParameters", Field: "JsonParameters", Type: "string"}, + {Code: "needExternalAddressMaster", Field: "NeedExternalAddressMaster", Type: "bool"}, + {Code: "needExternalAddressSlave", Field: "NeedExternalAddressSlave", Type: "bool"}, + {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"}, + {Code: "resourceDisk", Field: "ResourceDisk", Type: "string"}, + {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 *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.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.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.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.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.ValueString() != state.ResourceDisk.ValueString() { + hasServiceParamChanges = true + } + } + } + if !hasServiceParamChanges { + if plan.NeedExternalAddressMaster.IsNull() != state.NeedExternalAddressMaster.IsNull() || plan.NeedExternalAddressMaster.IsUnknown() != state.NeedExternalAddressMaster.IsUnknown() { + hasServiceParamChanges = true + } else if !plan.NeedExternalAddressMaster.IsNull() && !plan.NeedExternalAddressMaster.IsUnknown() && !state.NeedExternalAddressMaster.IsNull() && !state.NeedExternalAddressMaster.IsUnknown() { + if plan.NeedExternalAddressMaster.ValueBool() != state.NeedExternalAddressMaster.ValueBool() { + hasServiceParamChanges = true + } + } + } + if !hasServiceParamChanges { + if plan.NeedExternalAddressSlave.IsNull() != state.NeedExternalAddressSlave.IsNull() || plan.NeedExternalAddressSlave.IsUnknown() != state.NeedExternalAddressSlave.IsUnknown() { + hasServiceParamChanges = true + } else if !plan.NeedExternalAddressSlave.IsNull() && !plan.NeedExternalAddressSlave.IsUnknown() && !state.NeedExternalAddressSlave.IsNull() && !state.NeedExternalAddressSlave.IsUnknown() { + if plan.NeedExternalAddressSlave.ValueBool() != state.NeedExternalAddressSlave.ValueBool() { + hasServiceParamChanges = true + } + } + } + if !hasServiceParamChanges { + if plan.ExtBACKUPSCHEDULE.IsNull() != state.ExtBACKUPSCHEDULE.IsNull() || plan.ExtBACKUPSCHEDULE.IsUnknown() != state.ExtBACKUPSCHEDULE.IsUnknown() { + hasServiceParamChanges = true + } else if !plan.ExtBACKUPSCHEDULE.IsNull() && !plan.ExtBACKUPSCHEDULE.IsUnknown() && !state.ExtBACKUPSCHEDULE.IsNull() && !state.ExtBACKUPSCHEDULE.IsUnknown() { + if plan.ExtBACKUPSCHEDULE.ValueString() != state.ExtBACKUPSCHEDULE.ValueString() { + hasServiceParamChanges = true + } + } + } + if !hasServiceParamChanges { + if plan.ExtBACKUPNUMTORETAIN.IsNull() != state.ExtBACKUPNUMTORETAIN.IsNull() || plan.ExtBACKUPNUMTORETAIN.IsUnknown() != state.ExtBACKUPNUMTORETAIN.IsUnknown() { + hasServiceParamChanges = true + } else if !plan.ExtBACKUPNUMTORETAIN.IsNull() && !plan.ExtBACKUPNUMTORETAIN.IsUnknown() && !state.ExtBACKUPNUMTORETAIN.IsNull() && !state.ExtBACKUPNUMTORETAIN.IsUnknown() { + if plan.ExtBACKUPNUMTORETAIN.ValueInt64() != state.ExtBACKUPNUMTORETAIN.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 plan.AppVersion.ValueString() != state.AppVersion.ValueString() { + hasServiceParamChanges = true + } + } + } + if !hasServiceParamChanges { + if plan.JsonParameters.IsNull() != state.JsonParameters.IsNull() || plan.JsonParameters.IsUnknown() != state.JsonParameters.IsUnknown() { + hasServiceParamChanges = true + } else if !plan.JsonParameters.IsNull() && !plan.JsonParameters.IsUnknown() && !state.JsonParameters.IsNull() && !state.JsonParameters.IsUnknown() { + if plan.JsonParameters.ValueString() != state.JsonParameters.ValueString() { + hasServiceParamChanges = true + } + } + } + if !hasServiceParamChanges { + if plan.EnablePgPoolerMaster.IsNull() != state.EnablePgPoolerMaster.IsNull() || plan.EnablePgPoolerMaster.IsUnknown() != state.EnablePgPoolerMaster.IsUnknown() { + hasServiceParamChanges = true + } else if !plan.EnablePgPoolerMaster.IsNull() && !plan.EnablePgPoolerMaster.IsUnknown() && !state.EnablePgPoolerMaster.IsNull() && !state.EnablePgPoolerMaster.IsUnknown() { + if plan.EnablePgPoolerMaster.ValueBool() != state.EnablePgPoolerMaster.ValueBool() { + hasServiceParamChanges = true + } + } + } + if !hasServiceParamChanges { + if plan.EnablePgPoolerSlave.IsNull() != state.EnablePgPoolerSlave.IsNull() || plan.EnablePgPoolerSlave.IsUnknown() != state.EnablePgPoolerSlave.IsUnknown() { + hasServiceParamChanges = true + } else if !plan.EnablePgPoolerSlave.IsNull() && !plan.EnablePgPoolerSlave.IsUnknown() && !state.EnablePgPoolerSlave.IsNull() && !state.EnablePgPoolerSlave.IsUnknown() { + if plan.EnablePgPoolerSlave.ValueBool() != state.EnablePgPoolerSlave.ValueBool() { + hasServiceParamChanges = true + } + } + } + if !hasServiceParamChanges { + if plan.AllowNoSSL.IsNull() != state.AllowNoSSL.IsNull() || plan.AllowNoSSL.IsUnknown() != state.AllowNoSSL.IsUnknown() { + hasServiceParamChanges = true + } else if !plan.AllowNoSSL.IsNull() && !plan.AllowNoSSL.IsUnknown() && !state.AllowNoSSL.IsNull() && !state.AllowNoSSL.IsUnknown() { + if plan.AllowNoSSL.ValueBool() != state.AllowNoSSL.ValueBool() { + 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 plan.IpSpaceNameMaster.ValueString() != state.IpSpaceNameMaster.ValueString() { + hasServiceParamChanges = true + } + } + } + if !hasServiceParamChanges { + if plan.IpSpaceNameSlave.IsNull() != state.IpSpaceNameSlave.IsNull() || plan.IpSpaceNameSlave.IsUnknown() != state.IpSpaceNameSlave.IsUnknown() { + hasServiceParamChanges = true + } else if !plan.IpSpaceNameSlave.IsNull() && !plan.IpSpaceNameSlave.IsUnknown() && !state.IpSpaceNameSlave.IsNull() && !state.IpSpaceNameSlave.IsUnknown() { + if plan.IpSpaceNameSlave.ValueString() != state.IpSpaceNameSlave.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 + } + + params := map[int]string{ + 91: resources_core.FormatInt64(plan.ResourceInstances), + 92: resources_core.FormatInt64(plan.ResourceMemory), + 93: resources_core.FormatInt64(plan.ResourceCPU), + 94: resources_core.FormatString(plan.ResourceDisk), + 147: resources_core.FormatBool(plan.NeedExternalAddressMaster), + 148: resources_core.FormatBool(plan.NeedExternalAddressSlave), + 267: resources_core.FormatString(plan.ExtBACKUPSCHEDULE), + 268: resources_core.FormatInt64(plan.ExtBACKUPNUMTORETAIN), + 315: resources_core.FormatString(plan.AppVersion), + 316: resources_core.FormatString(plan.JsonParameters), + 317: resources_core.FormatBool(plan.EnablePgPoolerMaster), + 318: resources_core.FormatBool(plan.EnablePgPoolerSlave), + 319: resources_core.FormatBool(plan.AllowNoSSL), + 541: resources_core.FormatString(plan.IpSpaceNameMaster), + 542: resources_core.FormatString(plan.IpSpaceNameSlave), + } + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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: "allowNoSSL", Field: "AllowNoSSL", Type: "bool"}, + {Code: "appVersion", Field: "AppVersion", Type: "string"}, + {Code: "autoScale", Field: "AutoScale", Type: "bool"}, + {Code: "autoScalePercentage", Field: "AutoScalePercentage", Type: "int64"}, + {Code: "autoScaleQuotaGb", Field: "AutoScaleQuotaGb", Type: "string"}, + {Code: "autoScaleTechWindow", Field: "AutoScaleTechWindow", Type: "int64"}, + {Code: "enablePgPoolerMaster", Field: "EnablePgPoolerMaster", Type: "bool"}, + {Code: "enablePgPoolerSlave", Field: "EnablePgPoolerSlave", Type: "bool"}, + {Code: "ext_BACKUP_NUM_TO_RETAIN", Field: "ExtBACKUPNUMTORETAIN", Type: "int64"}, + {Code: "ext_BACKUP_SCHEDULE", Field: "ExtBACKUPSCHEDULE", Type: "string"}, + {Code: "ipSpaceNameMaster", Field: "IpSpaceNameMaster", Type: "string"}, + {Code: "ipSpaceNameSlave", Field: "IpSpaceNameSlave", Type: "string"}, + {Code: "jsonParameters", Field: "JsonParameters", Type: "string"}, + {Code: "needExternalAddressMaster", Field: "NeedExternalAddressMaster", Type: "bool"}, + {Code: "needExternalAddressSlave", Field: "NeedExternalAddressSlave", Type: "bool"}, + {Code: "resourceCPU", Field: "ResourceCPU", Type: "int64"}, + {Code: "resourceDisk", Field: "ResourceDisk", Type: "string"}, + {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 *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 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/universal_rebuild/internal/resources_gen/90_postgres_restart_action.go b/universal_rebuild/internal/resources_gen/90_postgres_restart_action.go new file mode 100644 index 0000000..1f6824c --- /dev/null +++ b/universal_rebuild/internal/resources_gen/90_postgres_restart_action.go @@ -0,0 +1,128 @@ +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/types" +) + +// Code generated by tools/gen_v2. DO NOT EDIT. +// Service: postgres +// Action: restart + +var _ resource.Resource = &PostgresRestartResource{} + +// PostgresRestartResource triggers a one-time action. +type PostgresRestartResource struct { + client *core.UniversalClient +} + +type PostgresRestartModel struct { + ID types.String `tfsdk:"id"` + PostgresID types.String `tfsdk:"postgres_id"` + RunID types.String `tfsdk:"run_id"` + OperationTimeout types.String `tfsdk:"operation_timeout"` +} + +func NewPostgresRestartResource() resource.Resource { + return &PostgresRestartResource{} +} + +func (r *PostgresRestartResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_postgres_restart" +} + +func (r *PostgresRestartResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + attrs := map[string]schema.Attribute{ + "id": schema.StringAttribute{Computed: true}, + "postgres_id": schema.StringAttribute{Required: true}, + "run_id": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + } + resp.Schema = schema.Schema{Attributes: attrs} +} + +func (r *PostgresRestartResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan PostgresRestartModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + instanceUID := strings.TrimSpace(plan.PostgresID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{} + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.ValueString() + } + if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "restart", params, operationTimeout); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "restart", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *PostgresRestartResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state PostgresRestartModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *PostgresRestartResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan PostgresRestartModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + instanceUID := strings.TrimSpace(plan.PostgresID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{} + + if err := resources_core.RunOperationByCode(ctx, r.client, instanceUID, "restart", params); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "restart", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *PostgresRestartResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + // No-op: removing the resource does not trigger a remote action. +} + +func (r *PostgresRestartResource) 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/universal_rebuild/internal/resources_gen/90_postgres_user_resource.go b/universal_rebuild/internal/resources_gen/90_postgres_user_resource.go new file mode 100644 index 0000000..e307576 --- /dev/null +++ b/universal_rebuild/internal/resources_gen/90_postgres_user_resource.go @@ -0,0 +1,334 @@ +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: 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"` + 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}, + "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(false)}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "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{ + "role": resources_core.FormatString(plan.Role), + "username": resources_core.FormatString(plan.Username), + } + identityCodes := []string{ + "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), + }) + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.ValueString() + } + if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_user", params, operationTimeout); err != nil { + if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(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 { + plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams)) + resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект подтверждён в state_out, выполняется усыновление") + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) + return + } + } + resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в 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("Нарушена консистентность", "Операция 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{ + "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 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{ + "role": resources_core.FormatString(state.Role), + "username": resources_core.FormatString(state.Username), + } + identityCodes := []string{ + "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 skipMissingOnDelete { + resp.Diagnostics.AddWarning("Подресурс не найден", "Объект отсутствует и будет пропущен: "+targetValue) + return + } + resp.Diagnostics.AddError("Подресурс не найден", "Объект отсутствует: "+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 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/universal_rebuild/internal/resources_gen/91_redis_resource.go b/universal_rebuild/internal/resources_gen/91_redis_resource.go new file mode 100644 index 0000000..b52f62e --- /dev/null +++ b/universal_rebuild/internal/resources_gen/91_redis_resource.go @@ -0,0 +1,436 @@ +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/int64default" + "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 +} + +type RedisModel struct { + ID types.String `tfsdk:"id"` + ResourceName types.String `tfsdk:"resource_name"` + OperationTimeout types.String `tfsdk:"operation_timeout"` + IpSpaceNameMaster types.String `tfsdk:"ip_space_name_master"` + IpSpaceNameSlave types.String `tfsdk:"ip_space_name_slave"` + NeedExternalAddressMaster types.Bool `tfsdk:"need_external_address_master"` + NeedExternalAddressSlave types.Bool `tfsdk:"need_external_address_slave"` + 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 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "ip_space_name_master": schema.StringAttribute{Optional: true, MarkdownDescription: "Имя ipSpace для публикации VIP master. Не может быть пустым, если включен needExternalAddressMaster Не изменяется после создания."}, + "ip_space_name_slave": schema.StringAttribute{Optional: true, MarkdownDescription: "Имя ipSpace для публикации VIP slave. Не может быть пустым, если включен needExternalAddressSlave Не изменяется после создания."}, + "need_external_address_master": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Выделяет внешний IP для доступа к master Не изменяется после создания."}, + "need_external_address_slave": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Выделяет внешний IP для доступа к slave. Будет работать если slave в целом есть Не изменяется после создания."}, + "resource_c_p_u": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(1000), MarkdownDescription: "Квота ядра пода (Указывается в mili) Не изменяется после создания."}, + "resource_disk": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(30), 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(1024), 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 *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 + } + } + if !plan.IpSpaceNameMaster.IsNull() && !plan.IpSpaceNameMaster.IsUnknown() && !state.IpSpaceNameMaster.IsNull() && !state.IpSpaceNameMaster.IsUnknown() { + if plan.IpSpaceNameMaster.ValueString() != state.IpSpaceNameMaster.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить ip_space_name_master", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.IpSpaceNameSlave.IsNull() && !plan.IpSpaceNameSlave.IsUnknown() && !state.IpSpaceNameSlave.IsNull() && !state.IpSpaceNameSlave.IsUnknown() { + if plan.IpSpaceNameSlave.ValueString() != state.IpSpaceNameSlave.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить ip_space_name_slave", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.NeedExternalAddressMaster.IsNull() && !plan.NeedExternalAddressMaster.IsUnknown() && !state.NeedExternalAddressMaster.IsNull() && !state.NeedExternalAddressMaster.IsUnknown() { + if plan.NeedExternalAddressMaster.ValueBool() != state.NeedExternalAddressMaster.ValueBool() { + resp.Diagnostics.AddError("Нельзя изменить need_external_address_master", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.NeedExternalAddressSlave.IsNull() && !plan.NeedExternalAddressSlave.IsUnknown() && !state.NeedExternalAddressSlave.IsNull() && !state.NeedExternalAddressSlave.IsUnknown() { + if plan.NeedExternalAddressSlave.ValueBool() != state.NeedExternalAddressSlave.ValueBool() { + resp.Diagnostics.AddError("Нельзя изменить need_external_address_slave", "Параметр задается при создании и не может быть изменен.") + 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() { + if plan.ResourceRealm.ValueString() != state.ResourceRealm.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.") + return + } + } + return + } + if config.ResourceRealm.IsNull() || config.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + 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{ + 112: resources_core.FormatInt64(config.ResourceCPU), + 113: resources_core.FormatInt64(config.ResourceMemory), + 114: resources_core.FormatInt64(config.ResourceDisk), + 181: resources_core.FormatInt64(config.ResourceInstances), + 182: resources_core.FormatString(config.ResourceRealm), + 183: resources_core.FormatBool(config.NeedExternalAddressMaster), + 184: resources_core.FormatBool(config.NeedExternalAddressSlave), + 548: resources_core.FormatString(config.IpSpaceNameMaster), + 549: resources_core.FormatString(config.IpSpaceNameSlave), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 91, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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 + } + if data.ResourceRealm.IsNull() || data.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + return + } + + resourceName := data.ResourceName.ValueString() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 91, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + params := map[int]string{ + 112: resources_core.FormatInt64(data.ResourceCPU), + 113: resources_core.FormatInt64(data.ResourceMemory), + 114: resources_core.FormatInt64(data.ResourceDisk), + 181: resources_core.FormatInt64(data.ResourceInstances), + 182: resources_core.FormatString(data.ResourceRealm), + 183: resources_core.FormatBool(data.NeedExternalAddressMaster), + 184: resources_core.FormatBool(data.NeedExternalAddressSlave), + 548: resources_core.FormatString(data.IpSpaceNameMaster), + 549: resources_core.FormatString(data.IpSpaceNameSlave), + } + + operationTimeout := "" + if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() { + operationTimeout = data.OperationTimeout.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: "ipSpaceNameMaster", Field: "IpSpaceNameMaster", Type: "string"}, + {Code: "ipSpaceNameSlave", Field: "IpSpaceNameSlave", Type: "string"}, + {Code: "needExternalAddressMaster", Field: "NeedExternalAddressMaster", Type: "bool"}, + {Code: "needExternalAddressSlave", Field: "NeedExternalAddressSlave", Type: "bool"}, + {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 *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: "ipSpaceNameMaster", Field: "IpSpaceNameMaster", Type: "string"}, + {Code: "ipSpaceNameSlave", Field: "IpSpaceNameSlave", Type: "string"}, + {Code: "needExternalAddressMaster", Field: "NeedExternalAddressMaster", Type: "bool"}, + {Code: "needExternalAddressSlave", Field: "NeedExternalAddressSlave", Type: "bool"}, + {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 *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 + } + + params := map[int]string{} + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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: "ipSpaceNameMaster", Field: "IpSpaceNameMaster", Type: "string"}, + {Code: "ipSpaceNameSlave", Field: "IpSpaceNameSlave", Type: "string"}, + {Code: "needExternalAddressMaster", Field: "NeedExternalAddressMaster", Type: "bool"}, + {Code: "needExternalAddressSlave", Field: "NeedExternalAddressSlave", Type: "bool"}, + {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 *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 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/universal_rebuild/internal/resources_gen/92_mongodb_resource.go b/universal_rebuild/internal/resources_gen/92_mongodb_resource.go new file mode 100644 index 0000000..4b7b992 --- /dev/null +++ b/universal_rebuild/internal/resources_gen/92_mongodb_resource.go @@ -0,0 +1,442 @@ +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/stringdefault" + "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 +} + +type MongodbModel struct { + ID types.String `tfsdk:"id"` + ResourceName types.String `tfsdk:"resource_name"` + OperationTimeout types.String `tfsdk:"operation_timeout"` + IpSpaceNameMaster types.String `tfsdk:"ip_space_name_master"` + NeedExternalAddressMaster types.String `tfsdk:"need_external_address_master"` + 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 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "ip_space_name_master": schema.StringAttribute{Optional: true, MarkdownDescription: "Если включен предыдущий параметр, то поле необходимо заполнить. Пример: `internet-no-antiddos-v1` Не изменяется после создания."}, + "need_external_address_master": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("false"), MarkdownDescription: "Флаг, определяющий, нужно ли выделять внешний IP для доступа к master-брокеру. Пример: `true` или `false` Не изменяется после создания."}, + "resource_c_p_u": schema.Int64Attribute{Required: true, MarkdownDescription: "Пример: `1000` Не изменяется после создания."}, + "resource_disk": schema.Int64Attribute{Required: true, MarkdownDescription: "Пример: `20` Не изменяется после создания."}, + "resource_instances": schema.Int64Attribute{Required: true, MarkdownDescription: "Пример: `2` Не изменяется после создания."}, + "resource_memory": schema.Int64Attribute{Required: true, 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 *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 + } + } + if !plan.IpSpaceNameMaster.IsNull() && !plan.IpSpaceNameMaster.IsUnknown() && !state.IpSpaceNameMaster.IsNull() && !state.IpSpaceNameMaster.IsUnknown() { + if plan.IpSpaceNameMaster.ValueString() != state.IpSpaceNameMaster.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить ip_space_name_master", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.NeedExternalAddressMaster.IsNull() && !plan.NeedExternalAddressMaster.IsUnknown() && !state.NeedExternalAddressMaster.IsNull() && !state.NeedExternalAddressMaster.IsUnknown() { + if plan.NeedExternalAddressMaster.ValueString() != state.NeedExternalAddressMaster.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить need_external_address_master", "Параметр задается при создании и не может быть изменен.") + 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() { + if plan.ResourceRealm.ValueString() != state.ResourceRealm.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.") + return + } + } + return + } + if config.ResourceCPU.IsNull() || config.ResourceCPU.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_c_p_u is required.") + return + } + if config.ResourceDisk.IsNull() || config.ResourceDisk.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_disk is required.") + return + } + if config.ResourceInstances.IsNull() || config.ResourceInstances.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_instances is required.") + return + } + if config.ResourceMemory.IsNull() || config.ResourceMemory.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_memory is required.") + return + } + if config.ResourceRealm.IsNull() || config.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + 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{ + 487: resources_core.FormatInt64(config.ResourceInstances), + 588: resources_core.FormatInt64(config.ResourceMemory), + 589: resources_core.FormatInt64(config.ResourceCPU), + 590: resources_core.FormatInt64(config.ResourceDisk), + 595: resources_core.FormatString(config.ResourceRealm), + 645: resources_core.FormatString(config.NeedExternalAddressMaster), + 646: resources_core.FormatString(config.IpSpaceNameMaster), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 92, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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 + } + if data.ResourceCPU.IsNull() || data.ResourceCPU.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_c_p_u is required.") + return + } + if data.ResourceDisk.IsNull() || data.ResourceDisk.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_disk is required.") + return + } + if data.ResourceInstances.IsNull() || data.ResourceInstances.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_instances is required.") + return + } + if data.ResourceMemory.IsNull() || data.ResourceMemory.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_memory 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() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 92, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + params := map[int]string{ + 487: resources_core.FormatInt64(data.ResourceInstances), + 588: resources_core.FormatInt64(data.ResourceMemory), + 589: resources_core.FormatInt64(data.ResourceCPU), + 590: resources_core.FormatInt64(data.ResourceDisk), + 595: resources_core.FormatString(data.ResourceRealm), + 645: resources_core.FormatString(data.NeedExternalAddressMaster), + 646: resources_core.FormatString(data.IpSpaceNameMaster), + } + + operationTimeout := "" + if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() { + operationTimeout = data.OperationTimeout.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: "ipSpaceNameMaster", Field: "IpSpaceNameMaster", Type: "string"}, + {Code: "needExternalAddressMaster", Field: "NeedExternalAddressMaster", 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 *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: "ipSpaceNameMaster", Field: "IpSpaceNameMaster", Type: "string"}, + {Code: "needExternalAddressMaster", Field: "NeedExternalAddressMaster", 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 *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 + } + + params := map[int]string{} + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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: "ipSpaceNameMaster", Field: "IpSpaceNameMaster", Type: "string"}, + {Code: "needExternalAddressMaster", Field: "NeedExternalAddressMaster", 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 *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 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/universal_rebuild/internal/resources_gen/92_mongodb_user_resource.go b/universal_rebuild/internal/resources_gen/92_mongodb_user_resource.go new file mode 100644 index 0000000..67a7b2c --- /dev/null +++ b/universal_rebuild/internal/resources_gen/92_mongodb_user_resource.go @@ -0,0 +1,340 @@ +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"` + 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}, + "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(false)}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "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 err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "create_user", params, operationTimeout); err != nil { + if adoptExistingOnCreate && resources_core.IsSubresourceAlreadyExistsError(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 { + plan.ID = types.StringValue(resources_core.BuildSubresourceID(instanceUID, "user", idParams)) + resp.Diagnostics.AddWarning("Подресурс уже существует", "Операция вернула duplicate/exist, объект подтверждён в state_out, выполняется усыновление") + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) + return + } + } + resp.Diagnostics.AddError("Нарушена консистентность", "Операция вернула duplicate/exist, но объект не найден в 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("Нарушена консистентность", "Операция 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 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 { + if skipMissingOnDelete { + resp.Diagnostics.AddWarning("Подресурс не найден", "Объект отсутствует и будет пропущен: "+targetValue) + return + } + resp.Diagnostics.AddError("Подресурс не найден", "Объект отсутствует: "+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 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/universal_rebuild/internal/resources_gen/93_rabbitmq_resource.go b/universal_rebuild/internal/resources_gen/93_rabbitmq_resource.go new file mode 100644 index 0000000..0e99b59 --- /dev/null +++ b/universal_rebuild/internal/resources_gen/93_rabbitmq_resource.go @@ -0,0 +1,465 @@ +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/int64default" + "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"` + IpSpaceNameMaster types.String `tfsdk:"ip_space_name_master"` + IpSpaceNameSlave types.String `tfsdk:"ip_space_name_slave"` + NeedExternalAddressMaster types.Bool `tfsdk:"need_external_address_master"` + NeedExternalAddressSlave types.Bool `tfsdk:"need_external_address_slave"` + 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "ip_space_name_master": schema.StringAttribute{Optional: true, MarkdownDescription: "Пример: `internet-no-antiddos-v1`"}, + "ip_space_name_slave": schema.StringAttribute{Optional: true, MarkdownDescription: "Пример: `internet-no-antiddos-v1`"}, + "need_external_address_master": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Флаг, определяющий, нужно ли выделять внешний IP для доступа к master. Пример: `true` или `false`"}, + "need_external_address_slave": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool(false), MarkdownDescription: "Выделяет внешний (белый) IP для доступа к slave"}, + "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() { + if plan.ResourceRealm.ValueString() != state.ResourceRealm.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.") + return + } + } + return + } + if config.ResourceRealm.IsNull() || config.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + 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.FormatBool(config.NeedExternalAddressMaster), + 543: resources_core.FormatString(config.IpSpaceNameMaster), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 93, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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.ResourceRealm.IsNull() || data.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + return + } + + resourceName := data.ResourceName.ValueString() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 93, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + 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.FormatBool(data.NeedExternalAddressMaster), + 543: resources_core.FormatString(data.IpSpaceNameMaster), + } + + operationTimeout := "" + if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() { + operationTimeout = data.OperationTimeout.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: "ipSpaceNameSlave", Field: "IpSpaceNameSlave", Type: "string"}, + {Code: "needExternalAddressMaster", Field: "NeedExternalAddressMaster", Type: "bool"}, + {Code: "needExternalAddressSlave", Field: "NeedExternalAddressSlave", Type: "bool"}, + {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: "ipSpaceNameSlave", Field: "IpSpaceNameSlave", Type: "string"}, + {Code: "needExternalAddressMaster", Field: "NeedExternalAddressMaster", Type: "bool"}, + {Code: "needExternalAddressSlave", Field: "NeedExternalAddressSlave", Type: "bool"}, + {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.NeedExternalAddressMaster.IsNull() != state.NeedExternalAddressMaster.IsNull() || plan.NeedExternalAddressMaster.IsUnknown() != state.NeedExternalAddressMaster.IsUnknown() { + hasServiceParamChanges = true + } else if !plan.NeedExternalAddressMaster.IsNull() && !plan.NeedExternalAddressMaster.IsUnknown() && !state.NeedExternalAddressMaster.IsNull() && !state.NeedExternalAddressMaster.IsUnknown() { + if plan.NeedExternalAddressMaster.ValueBool() != state.NeedExternalAddressMaster.ValueBool() { + hasServiceParamChanges = true + } + } + } + if !hasServiceParamChanges { + if plan.NeedExternalAddressSlave.IsNull() != state.NeedExternalAddressSlave.IsNull() || plan.NeedExternalAddressSlave.IsUnknown() != state.NeedExternalAddressSlave.IsUnknown() { + hasServiceParamChanges = true + } else if !plan.NeedExternalAddressSlave.IsNull() && !plan.NeedExternalAddressSlave.IsUnknown() && !state.NeedExternalAddressSlave.IsNull() && !state.NeedExternalAddressSlave.IsUnknown() { + if plan.NeedExternalAddressSlave.ValueBool() != state.NeedExternalAddressSlave.ValueBool() { + 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 plan.IpSpaceNameMaster.ValueString() != state.IpSpaceNameMaster.ValueString() { + hasServiceParamChanges = true + } + } + } + if !hasServiceParamChanges { + if plan.IpSpaceNameSlave.IsNull() != state.IpSpaceNameSlave.IsNull() || plan.IpSpaceNameSlave.IsUnknown() != state.IpSpaceNameSlave.IsUnknown() { + hasServiceParamChanges = true + } else if !plan.IpSpaceNameSlave.IsNull() && !plan.IpSpaceNameSlave.IsUnknown() && !state.IpSpaceNameSlave.IsNull() && !state.IpSpaceNameSlave.IsUnknown() { + if plan.IpSpaceNameSlave.ValueString() != state.IpSpaceNameSlave.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 + } + + 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.FormatBool(plan.NeedExternalAddressMaster), + 309: resources_core.FormatBool(plan.NeedExternalAddressSlave), + 545: resources_core.FormatString(plan.IpSpaceNameMaster), + 546: resources_core.FormatString(plan.IpSpaceNameSlave), + } + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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(), 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: "ipSpaceNameSlave", Field: "IpSpaceNameSlave", Type: "string"}, + {Code: "needExternalAddressMaster", Field: "NeedExternalAddressMaster", Type: "bool"}, + {Code: "needExternalAddressSlave", Field: "NeedExternalAddressSlave", Type: "bool"}, + {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 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/universal_rebuild/internal/resources_gen/94_lucee_redeploy_action.go b/universal_rebuild/internal/resources_gen/94_lucee_redeploy_action.go new file mode 100644 index 0000000..635a4da --- /dev/null +++ b/universal_rebuild/internal/resources_gen/94_lucee_redeploy_action.go @@ -0,0 +1,138 @@ +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/types" +) + +// Code generated by tools/gen_v2. DO NOT EDIT. +// Service: lucee +// Action: redeploy + +var _ resource.Resource = &LuceeRedeployResource{} + +// LuceeRedeployResource triggers a one-time action. +type LuceeRedeployResource struct { + client *core.UniversalClient +} + +type LuceeRedeployModel struct { + ID types.String `tfsdk:"id"` + LuceeID types.String `tfsdk:"lucee_id"` + RunID types.String `tfsdk:"run_id"` + OperationTimeout types.String `tfsdk:"operation_timeout"` + ResourceRealm types.String `tfsdk:"resource_realm"` +} + +func NewLuceeRedeployResource() resource.Resource { + return &LuceeRedeployResource{} +} + +func (r *LuceeRedeployResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_lucee_redeploy" +} + +func (r *LuceeRedeployResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + attrs := map[string]schema.Attribute{ + "id": schema.StringAttribute{Computed: true}, + "lucee_id": schema.StringAttribute{Required: true}, + "run_id": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Платформа для развертывания"}, + } + resp.Schema = schema.Schema{Attributes: attrs} +} + +func (r *LuceeRedeployResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan LuceeRedeployModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + if plan.ResourceRealm.IsNull() || plan.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + return + } + + instanceUID := strings.TrimSpace(plan.LuceeID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{ + "resourceRealm": resources_core.FormatString(plan.ResourceRealm), + } + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.ValueString() + } + if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "redeploy", params, operationTimeout); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "redeploy", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *LuceeRedeployResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state LuceeRedeployModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *LuceeRedeployResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan LuceeRedeployModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + instanceUID := strings.TrimSpace(plan.LuceeID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{ + "resourceRealm": resources_core.FormatString(plan.ResourceRealm), + } + + if err := resources_core.RunOperationByCode(ctx, r.client, instanceUID, "redeploy", params); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "redeploy", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *LuceeRedeployResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + // No-op: removing the resource does not trigger a remote action. +} + +func (r *LuceeRedeployResource) 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/universal_rebuild/internal/resources_gen/94_lucee_resource.go b/universal_rebuild/internal/resources_gen/94_lucee_resource.go new file mode 100644 index 0000000..09ccecc --- /dev/null +++ b/universal_rebuild/internal/resources_gen/94_lucee_resource.go @@ -0,0 +1,466 @@ +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/int64default" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "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 +} + +type LuceeModel struct { + ID types.String `tfsdk:"id"` + ResourceName types.String `tfsdk:"resource_name"` + OperationTimeout types.String `tfsdk:"operation_timeout"` + AppVersion types.String `tfsdk:"app_version"` + Domain types.String `tfsdk:"domain"` + GitPath types.String `tfsdk:"git_path"` + HealthPath types.String `tfsdk:"health_path"` + JsonEnv types.String `tfsdk:"json_env"` + 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 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "app_version": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("5.4"), MarkdownDescription: "Версия Lucee"}, + "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("web01"), MarkdownDescription: "Если будет указан FQDN, то происходят проверки DNS на валидность А-записи, или будет добавлено в зону resourceRealm Не изменяется после создания."}, + "git_path": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("https://github.com/xahys/testlucee"), MarkdownDescription: "Путь до Git, который будет webroot для сайта"}, + "health_path": schema.StringAttribute{Optional: true, MarkdownDescription: "Путь до healtcheck для запуска пода в Kubernetes, который отдаст 200 код"}, + "json_env": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("{ \"param\": \"value\" }"), MarkdownDescription: "Здесь вы можете задать переменные среды в формате KEY=VALUE. Они будут доступны внутри вашего приложения."}, + "resource_c_p_u": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(300), MarkdownDescription: "Квота ядра пода (milicores)"}, + "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(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 + } + } + if !plan.Domain.IsNull() && !plan.Domain.IsUnknown() && !state.Domain.IsNull() && !state.Domain.IsUnknown() { + if plan.Domain.ValueString() != state.Domain.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить domain", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() { + if plan.ResourceRealm.ValueString() != state.ResourceRealm.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.") + return + } + } + return + } + if config.ResourceRealm.IsNull() || config.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + 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{ + 103: resources_core.FormatString(config.Domain), + 104: resources_core.FormatString(config.GitPath), + 105: resources_core.FormatString(config.JsonEnv), + 106: resources_core.FormatInt64(config.ResourceCPU), + 107: resources_core.FormatInt64(config.ResourceMemory), + 108: resources_core.FormatString(config.ResourceRealm), + 132: resources_core.FormatString(config.HealthPath), + 139: resources_core.FormatInt64(config.ResourceInstances), + 263: resources_core.FormatString(config.AppVersion), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 94, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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 + } + if data.ResourceRealm.IsNull() || data.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + return + } + + resourceName := data.ResourceName.ValueString() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 94, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + params := map[int]string{ + 103: resources_core.FormatString(data.Domain), + 104: resources_core.FormatString(data.GitPath), + 105: resources_core.FormatString(data.JsonEnv), + 106: resources_core.FormatInt64(data.ResourceCPU), + 107: resources_core.FormatInt64(data.ResourceMemory), + 108: resources_core.FormatString(data.ResourceRealm), + 132: resources_core.FormatString(data.HealthPath), + 139: resources_core.FormatInt64(data.ResourceInstances), + 263: resources_core.FormatString(data.AppVersion), + } + + operationTimeout := "" + if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() { + operationTimeout = data.OperationTimeout.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: "appVersion", Field: "AppVersion", Type: "string"}, + {Code: "domain", Field: "Domain", Type: "string"}, + {Code: "gitPath", Field: "GitPath", Type: "string"}, + {Code: "healthPath", Field: "HealthPath", Type: "string"}, + {Code: "jsonEnv", Field: "JsonEnv", 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 *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: "appVersion", Field: "AppVersion", Type: "string"}, + {Code: "domain", Field: "Domain", Type: "string"}, + {Code: "gitPath", Field: "GitPath", Type: "string"}, + {Code: "healthPath", Field: "HealthPath", Type: "string"}, + {Code: "jsonEnv", Field: "JsonEnv", 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 *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.GitPath.IsNull() != state.GitPath.IsNull() || plan.GitPath.IsUnknown() != state.GitPath.IsUnknown() { + hasServiceParamChanges = true + } else if !plan.GitPath.IsNull() && !plan.GitPath.IsUnknown() && !state.GitPath.IsNull() && !state.GitPath.IsUnknown() { + if plan.GitPath.ValueString() != state.GitPath.ValueString() { + hasServiceParamChanges = true + } + } + } + if !hasServiceParamChanges { + if plan.HealthPath.IsNull() != state.HealthPath.IsNull() || plan.HealthPath.IsUnknown() != state.HealthPath.IsUnknown() { + hasServiceParamChanges = true + } else if !plan.HealthPath.IsNull() && !plan.HealthPath.IsUnknown() && !state.HealthPath.IsNull() && !state.HealthPath.IsUnknown() { + if plan.HealthPath.ValueString() != state.HealthPath.ValueString() { + hasServiceParamChanges = true + } + } + } + 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 plan.JsonEnv.ValueString() != state.JsonEnv.ValueString() { + 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.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.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 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 + } + + params := map[int]string{ + 133: resources_core.FormatString(plan.GitPath), + 134: resources_core.FormatString(plan.HealthPath), + 135: resources_core.FormatString(plan.JsonEnv), + 136: resources_core.FormatInt64(plan.ResourceCPU), + 137: resources_core.FormatInt64(plan.ResourceMemory), + 138: resources_core.FormatInt64(plan.ResourceInstances), + 264: resources_core.FormatString(plan.AppVersion), + } + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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(), 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: "appVersion", Field: "AppVersion", Type: "string"}, + {Code: "domain", Field: "Domain", Type: "string"}, + {Code: "gitPath", Field: "GitPath", Type: "string"}, + {Code: "healthPath", Field: "HealthPath", Type: "string"}, + {Code: "jsonEnv", Field: "JsonEnv", 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 *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 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/universal_rebuild/internal/resources_gen/94_lucee_restart_action.go b/universal_rebuild/internal/resources_gen/94_lucee_restart_action.go new file mode 100644 index 0000000..4432ff7 --- /dev/null +++ b/universal_rebuild/internal/resources_gen/94_lucee_restart_action.go @@ -0,0 +1,128 @@ +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/types" +) + +// Code generated by tools/gen_v2. DO NOT EDIT. +// Service: lucee +// Action: restart + +var _ resource.Resource = &LuceeRestartResource{} + +// LuceeRestartResource triggers a one-time action. +type LuceeRestartResource struct { + client *core.UniversalClient +} + +type LuceeRestartModel struct { + ID types.String `tfsdk:"id"` + LuceeID types.String `tfsdk:"lucee_id"` + RunID types.String `tfsdk:"run_id"` + OperationTimeout types.String `tfsdk:"operation_timeout"` +} + +func NewLuceeRestartResource() resource.Resource { + return &LuceeRestartResource{} +} + +func (r *LuceeRestartResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_lucee_restart" +} + +func (r *LuceeRestartResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + attrs := map[string]schema.Attribute{ + "id": schema.StringAttribute{Computed: true}, + "lucee_id": schema.StringAttribute{Required: true}, + "run_id": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + } + resp.Schema = schema.Schema{Attributes: attrs} +} + +func (r *LuceeRestartResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan LuceeRestartModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + instanceUID := strings.TrimSpace(plan.LuceeID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{} + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.ValueString() + } + if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "restart", params, operationTimeout); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "restart", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *LuceeRestartResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state LuceeRestartModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *LuceeRestartResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan LuceeRestartModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + instanceUID := strings.TrimSpace(plan.LuceeID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{} + + if err := resources_core.RunOperationByCode(ctx, r.client, instanceUID, "restart", params); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "restart", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *LuceeRestartResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + // No-op: removing the resource does not trigger a remote action. +} + +func (r *LuceeRestartResource) 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/universal_rebuild/internal/resources_gen/95_nodejs_redeploy_action.go b/universal_rebuild/internal/resources_gen/95_nodejs_redeploy_action.go new file mode 100644 index 0000000..11804bc --- /dev/null +++ b/universal_rebuild/internal/resources_gen/95_nodejs_redeploy_action.go @@ -0,0 +1,138 @@ +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/types" +) + +// Code generated by tools/gen_v2. DO NOT EDIT. +// Service: nodejs +// Action: redeploy + +var _ resource.Resource = &NodejsRedeployResource{} + +// NodejsRedeployResource triggers a one-time action. +type NodejsRedeployResource struct { + client *core.UniversalClient +} + +type NodejsRedeployModel struct { + ID types.String `tfsdk:"id"` + NodejsID types.String `tfsdk:"nodejs_id"` + RunID types.String `tfsdk:"run_id"` + OperationTimeout types.String `tfsdk:"operation_timeout"` + ResourceRealm types.String `tfsdk:"resource_realm"` +} + +func NewNodejsRedeployResource() resource.Resource { + return &NodejsRedeployResource{} +} + +func (r *NodejsRedeployResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_nodejs_redeploy" +} + +func (r *NodejsRedeployResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + attrs := map[string]schema.Attribute{ + "id": schema.StringAttribute{Computed: true}, + "nodejs_id": schema.StringAttribute{Required: true}, + "run_id": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Платформа для развертывания"}, + } + resp.Schema = schema.Schema{Attributes: attrs} +} + +func (r *NodejsRedeployResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan NodejsRedeployModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + if plan.ResourceRealm.IsNull() || plan.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + return + } + + instanceUID := strings.TrimSpace(plan.NodejsID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{ + "resourceRealm": resources_core.FormatString(plan.ResourceRealm), + } + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.ValueString() + } + if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "redeploy", params, operationTimeout); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "redeploy", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *NodejsRedeployResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state NodejsRedeployModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *NodejsRedeployResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan NodejsRedeployModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + instanceUID := strings.TrimSpace(plan.NodejsID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{ + "resourceRealm": resources_core.FormatString(plan.ResourceRealm), + } + + if err := resources_core.RunOperationByCode(ctx, r.client, instanceUID, "redeploy", params); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "redeploy", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *NodejsRedeployResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + // No-op: removing the resource does not trigger a remote action. +} + +func (r *NodejsRedeployResource) 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/universal_rebuild/internal/resources_gen/95_nodejs_resource.go b/universal_rebuild/internal/resources_gen/95_nodejs_resource.go new file mode 100644 index 0000000..a6be789 --- /dev/null +++ b/universal_rebuild/internal/resources_gen/95_nodejs_resource.go @@ -0,0 +1,466 @@ +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/int64default" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "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 +} + +type NodejsModel struct { + ID types.String `tfsdk:"id"` + ResourceName types.String `tfsdk:"resource_name"` + OperationTimeout types.String `tfsdk:"operation_timeout"` + AppVersion types.String `tfsdk:"app_version"` + Domain types.String `tfsdk:"domain"` + GitPath types.String `tfsdk:"git_path"` + HealthPath types.String `tfsdk:"health_path"` + JsonEnv types.String `tfsdk:"json_env"` + 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 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "app_version": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("23"), MarkdownDescription: "Версия приложения"}, + "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("web01"), MarkdownDescription: "Если будет указан FQDN, то происходят проверки DNS на валидность А-записи, или будет добавлено в зону resourceRealm Не изменяется после создания."}, + "git_path": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("https://github.com/xahys/testnode.git"), MarkdownDescription: "Путь до Git, который будет webroot для сайта"}, + "health_path": schema.StringAttribute{Optional: true, MarkdownDescription: "Путь до healtcheck для запуска пода в Kubernetes, который отдаст 200 код. Если оставить пустым, healtcheck'а не будет"}, + "json_env": schema.StringAttribute{Optional: true, MarkdownDescription: "Массив переменных, будут переданы в env приложения"}, + "resource_c_p_u": schema.Int64Attribute{Optional: true, Computed: true, Default: int64default.StaticInt64(500), MarkdownDescription: "Квота ядра пода (milicores). 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: "Квота памяти пода (MBytes)"}, + "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 *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 + } + } + if !plan.Domain.IsNull() && !plan.Domain.IsUnknown() && !state.Domain.IsNull() && !state.Domain.IsUnknown() { + if plan.Domain.ValueString() != state.Domain.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить domain", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() { + if plan.ResourceRealm.ValueString() != state.ResourceRealm.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.") + return + } + } + return + } + if config.ResourceRealm.IsNull() || config.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + 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{ + 149: resources_core.FormatString(config.Domain), + 150: resources_core.FormatString(config.GitPath), + 151: resources_core.FormatString(config.HealthPath), + 152: resources_core.FormatString(config.JsonEnv), + 153: resources_core.FormatInt64(config.ResourceCPU), + 154: resources_core.FormatInt64(config.ResourceMemory), + 155: resources_core.FormatInt64(config.ResourceInstances), + 156: resources_core.FormatString(config.ResourceRealm), + 270: resources_core.FormatString(config.AppVersion), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 95, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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 + } + if data.ResourceRealm.IsNull() || data.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + return + } + + resourceName := data.ResourceName.ValueString() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 95, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + params := map[int]string{ + 149: resources_core.FormatString(data.Domain), + 150: resources_core.FormatString(data.GitPath), + 151: resources_core.FormatString(data.HealthPath), + 152: resources_core.FormatString(data.JsonEnv), + 153: resources_core.FormatInt64(data.ResourceCPU), + 154: resources_core.FormatInt64(data.ResourceMemory), + 155: resources_core.FormatInt64(data.ResourceInstances), + 156: resources_core.FormatString(data.ResourceRealm), + 270: resources_core.FormatString(data.AppVersion), + } + + operationTimeout := "" + if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() { + operationTimeout = data.OperationTimeout.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: "appVersion", Field: "AppVersion", Type: "string"}, + {Code: "domain", Field: "Domain", Type: "string"}, + {Code: "gitPath", Field: "GitPath", Type: "string"}, + {Code: "healthPath", Field: "HealthPath", Type: "string"}, + {Code: "jsonEnv", Field: "JsonEnv", 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 *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: "appVersion", Field: "AppVersion", Type: "string"}, + {Code: "domain", Field: "Domain", Type: "string"}, + {Code: "gitPath", Field: "GitPath", Type: "string"}, + {Code: "healthPath", Field: "HealthPath", Type: "string"}, + {Code: "jsonEnv", Field: "JsonEnv", 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 *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.GitPath.IsNull() != state.GitPath.IsNull() || plan.GitPath.IsUnknown() != state.GitPath.IsUnknown() { + hasServiceParamChanges = true + } else if !plan.GitPath.IsNull() && !plan.GitPath.IsUnknown() && !state.GitPath.IsNull() && !state.GitPath.IsUnknown() { + if plan.GitPath.ValueString() != state.GitPath.ValueString() { + hasServiceParamChanges = true + } + } + } + if !hasServiceParamChanges { + if plan.HealthPath.IsNull() != state.HealthPath.IsNull() || plan.HealthPath.IsUnknown() != state.HealthPath.IsUnknown() { + hasServiceParamChanges = true + } else if !plan.HealthPath.IsNull() && !plan.HealthPath.IsUnknown() && !state.HealthPath.IsNull() && !state.HealthPath.IsUnknown() { + if plan.HealthPath.ValueString() != state.HealthPath.ValueString() { + hasServiceParamChanges = true + } + } + } + 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 plan.JsonEnv.ValueString() != state.JsonEnv.ValueString() { + 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.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.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 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 + } + + params := map[int]string{ + 157: resources_core.FormatString(plan.GitPath), + 158: resources_core.FormatString(plan.HealthPath), + 159: resources_core.FormatString(plan.JsonEnv), + 160: resources_core.FormatInt64(plan.ResourceCPU), + 161: resources_core.FormatInt64(plan.ResourceMemory), + 162: resources_core.FormatInt64(plan.ResourceInstances), + 271: resources_core.FormatString(plan.AppVersion), + } + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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(), 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: "appVersion", Field: "AppVersion", Type: "string"}, + {Code: "domain", Field: "Domain", Type: "string"}, + {Code: "gitPath", Field: "GitPath", Type: "string"}, + {Code: "healthPath", Field: "HealthPath", Type: "string"}, + {Code: "jsonEnv", Field: "JsonEnv", 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 *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 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/universal_rebuild/internal/resources_gen/96_pgadmin_redeploy_action.go b/universal_rebuild/internal/resources_gen/96_pgadmin_redeploy_action.go new file mode 100644 index 0000000..2ad2820 --- /dev/null +++ b/universal_rebuild/internal/resources_gen/96_pgadmin_redeploy_action.go @@ -0,0 +1,138 @@ +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/types" +) + +// Code generated by tools/gen_v2. DO NOT EDIT. +// Service: pgadmin +// Action: redeploy + +var _ resource.Resource = &PgadminRedeployResource{} + +// PgadminRedeployResource triggers a one-time action. +type PgadminRedeployResource struct { + client *core.UniversalClient +} + +type PgadminRedeployModel struct { + ID types.String `tfsdk:"id"` + PgadminID types.String `tfsdk:"pgadmin_id"` + RunID types.String `tfsdk:"run_id"` + OperationTimeout types.String `tfsdk:"operation_timeout"` + ResourceRealm types.String `tfsdk:"resource_realm"` +} + +func NewPgadminRedeployResource() resource.Resource { + return &PgadminRedeployResource{} +} + +func (r *PgadminRedeployResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_pgadmin_redeploy" +} + +func (r *PgadminRedeployResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + attrs := map[string]schema.Attribute{ + "id": schema.StringAttribute{Computed: true}, + "pgadmin_id": schema.StringAttribute{Required: true}, + "run_id": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Платформа для развертывания"}, + } + resp.Schema = schema.Schema{Attributes: attrs} +} + +func (r *PgadminRedeployResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan PgadminRedeployModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + if plan.ResourceRealm.IsNull() || plan.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + return + } + + instanceUID := strings.TrimSpace(plan.PgadminID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{ + "resourceRealm": resources_core.FormatString(plan.ResourceRealm), + } + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.ValueString() + } + if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "redeploy", params, operationTimeout); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "redeploy", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *PgadminRedeployResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state PgadminRedeployModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *PgadminRedeployResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan PgadminRedeployModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + instanceUID := strings.TrimSpace(plan.PgadminID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{ + "resourceRealm": resources_core.FormatString(plan.ResourceRealm), + } + + if err := resources_core.RunOperationByCode(ctx, r.client, instanceUID, "redeploy", params); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "redeploy", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *PgadminRedeployResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + // No-op: removing the resource does not trigger a remote action. +} + +func (r *PgadminRedeployResource) 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/universal_rebuild/internal/resources_gen/96_pgadmin_resource.go b/universal_rebuild/internal/resources_gen/96_pgadmin_resource.go new file mode 100644 index 0000000..f94e314 --- /dev/null +++ b/universal_rebuild/internal/resources_gen/96_pgadmin_resource.go @@ -0,0 +1,440 @@ +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/int64default" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "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"` + 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("web01"), 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(200), 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(256), MarkdownDescription: "Квота памяти пода (MBytes)"}, + "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 *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() { + if plan.Domain.ValueString() != state.Domain.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить domain", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.Login.IsNull() && !plan.Login.IsUnknown() && !state.Login.IsNull() && !state.Login.IsUnknown() { + if plan.Login.ValueString() != state.Login.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить login", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.Password.IsNull() && !plan.Password.IsUnknown() && !state.Password.IsNull() && !state.Password.IsUnknown() { + if plan.Password.ValueString() != state.Password.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить password", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.ResourceRealm.IsNull() && !plan.ResourceRealm.IsUnknown() && !state.ResourceRealm.IsNull() && !state.ResourceRealm.IsUnknown() { + if plan.ResourceRealm.ValueString() != state.ResourceRealm.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.") + return + } + } + return + } + if config.Login.IsNull() || config.Login.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "login is required.") + return + } + if config.Password.IsNull() || config.Password.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "password is required.") + return + } + if config.ResourceRealm.IsNull() || config.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + 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), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 96, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 96, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + 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() + } + 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 + } + } + } + + 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 + } + + params := map[int]string{ + 172: resources_core.FormatInt64(plan.ResourceCPU), + 173: resources_core.FormatInt64(plan.ResourceMemory), + 174: resources_core.FormatInt64(plan.ResourceDisk), + } + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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(), 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 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/universal_rebuild/internal/resources_gen/97_nodered_resource.go b/universal_rebuild/internal/resources_gen/97_nodered_resource.go new file mode 100644 index 0000000..6ce2414 --- /dev/null +++ b/universal_rebuild/internal/resources_gen/97_nodered_resource.go @@ -0,0 +1,405 @@ +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/int64default" + "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"` + 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "domain": schema.StringAttribute{Required: true, 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() { + if 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() { + if plan.ResourceRealm.ValueString() != state.ResourceRealm.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.") + return + } + } + return + } + if config.Domain.IsNull() || config.Domain.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "domain is required.") + return + } + if config.ResourceRealm.IsNull() || config.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + 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), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 97, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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.Domain.IsNull() || data.Domain.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "domain 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() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 97, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + 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() + } + 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 + } + + params := map[int]string{} + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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(), 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 := "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 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/universal_rebuild/internal/resources_gen/98_http_redeploy_action.go b/universal_rebuild/internal/resources_gen/98_http_redeploy_action.go new file mode 100644 index 0000000..a3f4ea0 --- /dev/null +++ b/universal_rebuild/internal/resources_gen/98_http_redeploy_action.go @@ -0,0 +1,138 @@ +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/types" +) + +// Code generated by tools/gen_v2. DO NOT EDIT. +// Service: http +// Action: redeploy + +var _ resource.Resource = &HttpRedeployResource{} + +// HttpRedeployResource triggers a one-time action. +type HttpRedeployResource struct { + client *core.UniversalClient +} + +type HttpRedeployModel struct { + ID types.String `tfsdk:"id"` + HttpID types.String `tfsdk:"http_id"` + RunID types.String `tfsdk:"run_id"` + OperationTimeout types.String `tfsdk:"operation_timeout"` + ResourceRealm types.String `tfsdk:"resource_realm"` +} + +func NewHttpRedeployResource() resource.Resource { + return &HttpRedeployResource{} +} + +func (r *HttpRedeployResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_http_redeploy" +} + +func (r *HttpRedeployResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + attrs := map[string]schema.Attribute{ + "id": schema.StringAttribute{Computed: true}, + "http_id": schema.StringAttribute{Required: true}, + "run_id": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "resource_realm": schema.StringAttribute{Required: true, MarkdownDescription: "Платформа для развертывания"}, + } + resp.Schema = schema.Schema{Attributes: attrs} +} + +func (r *HttpRedeployResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan HttpRedeployModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + if plan.ResourceRealm.IsNull() || plan.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + return + } + + instanceUID := strings.TrimSpace(plan.HttpID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{ + "resourceRealm": resources_core.FormatString(plan.ResourceRealm), + } + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.ValueString() + } + if err := resources_core.RunOperationByCodeWithTimeout(ctx, r.client, instanceUID, "redeploy", params, operationTimeout); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "redeploy", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *HttpRedeployResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state HttpRedeployModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *HttpRedeployResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan HttpRedeployModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + instanceUID := strings.TrimSpace(plan.HttpID.ValueString()) + runID := strings.TrimSpace(plan.RunID.ValueString()) + if instanceUID == "" || runID == "" { + resp.Diagnostics.AddError("Ошибка клиента", "отсутствует идентификатор экземпляра или run_id") + return + } + + params := map[string]string{ + "resourceRealm": resources_core.FormatString(plan.ResourceRealm), + } + + if err := resources_core.RunOperationByCode(ctx, r.client, instanceUID, "redeploy", params); err != nil { + resp.Diagnostics.AddError("Ошибка клиента", err.Error()) + return + } + + plan.ID = types.StringValue(resources_core.BuildActionID(instanceUID, "redeploy", runID)) + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *HttpRedeployResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + // No-op: removing the resource does not trigger a remote action. +} + +func (r *HttpRedeployResource) 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/universal_rebuild/internal/resources_gen/98_http_resource.go b/universal_rebuild/internal/resources_gen/98_http_resource.go new file mode 100644 index 0000000..63dbf17 --- /dev/null +++ b/universal_rebuild/internal/resources_gen/98_http_resource.go @@ -0,0 +1,424 @@ +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/int64default" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "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"` + Domain types.String `tfsdk:"domain"` + 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("web01"), MarkdownDescription: "Если будет указан FQDN, то происходят проверки DNS на валидность А-записи, или будет добавлено в зону resourceRealm Не изменяется после создания."}, + "json_env": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("{"param": "value"}"), 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: "Платформа для развертывания Не изменяется после создания."}, + "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() { + if plan.Domain.ValueString() != state.Domain.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить domain", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.JsonEnv.IsNull() && !plan.JsonEnv.IsUnknown() && !state.JsonEnv.IsNull() && !state.JsonEnv.IsUnknown() { + if 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() { + if 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() { + if plan.ResourceRealm.ValueString() != state.ResourceRealm.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить resource_realm", "Параметр задается при создании и не может быть изменен.") + return + } + } + return + } + if config.ResourceRealm.IsNull() || config.ResourceRealm.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "resource_realm is required.") + 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), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 98, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 98, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + 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), + } + + operationTimeout := "" + if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() { + operationTimeout = data.OperationTimeout.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: "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: "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 + } + } + } + + 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 + } + + params := map[int]string{ + 218: resources_core.FormatInt64(plan.ResourceCPU), + 219: resources_core.FormatInt64(plan.ResourceMemory), + 220: resources_core.FormatInt64(plan.ResourceInstances), + } + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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(), 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: "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 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/universal_rebuild/internal/resources_gen/99_gitea_resource.go b/universal_rebuild/internal/resources_gen/99_gitea_resource.go new file mode 100644 index 0000000..b2a90ac --- /dev/null +++ b/universal_rebuild/internal/resources_gen/99_gitea_resource.go @@ -0,0 +1,473 @@ +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/int64default" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "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"` + Domain types.String `tfsdk:"domain"` + 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}, + "resource_name": schema.StringAttribute{Required: true}, + "operation_timeout": schema.StringAttribute{Optional: true}, + "domain": schema.StringAttribute{Optional: true, Computed: true, Default: stringdefault.StaticString("web01"), MarkdownDescription: "Если будет указан FQDN, то происходят проверки DNS на валидность А-записи, или будет добавлено в зону resourceRealm Не изменяется после создания."}, + "psql_uid": schema.StringAttribute{Required: 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 + } + planChanged := false + if !plan.PsqlUid.IsNull() && !plan.PsqlUid.IsUnknown() { + resolvedPsqlUid, err := r.client.ResolveRefSvcParamValue(ctx, 90, plan.PsqlUid.ValueString()) + if err != nil { + resp.Diagnostics.AddWarning("Failed to resolve psql_uid", err.Error()) + } else if resolvedPsqlUid != "" && resolvedPsqlUid != plan.PsqlUid.ValueString() { + plan.PsqlUid = types.StringValue(resolvedPsqlUid) + planChanged = true + } + } + if planChanged { + resp.Diagnostics.Append(resp.Plan.Set(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() { + if plan.Domain.ValueString() != state.Domain.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить domain", "Параметр задается при создании и не может быть изменен.") + return + } + } + if !plan.PsqlUid.IsNull() && !plan.PsqlUid.IsUnknown() && !state.PsqlUid.IsNull() && !state.PsqlUid.IsUnknown() { + if plan.PsqlUid.ValueString() != state.PsqlUid.ValueString() { + resp.Diagnostics.AddError("Нельзя изменить psql_uid", "Параметр задается при создании и не может быть изменен.") + return + } + } + return + } + if config.PsqlUid.IsNull() || config.PsqlUid.IsUnknown() { + resp.Diagnostics.AddError("Missing required attribute", "psql_uid is required.") + 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), + } + + resp.Diagnostics.Append(resources_core.PlanExistingResourceDiagnosticsWithParams(ctx, r.client, 99, config.ResourceName.ValueString(), adoptExistingOnCreate, params)...) +} + +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 + } + 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() + resp.Diagnostics.Append(resources_core.CreateExistingResourceDiagnostics(ctx, r.client, 99, resourceName, data.AdoptExistingOnCreate.ValueBool())...) + + 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), + } + + operationTimeout := "" + if !data.OperationTimeout.IsNull() && !data.OperationTimeout.IsUnknown() { + operationTimeout = data.OperationTimeout.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: "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) + } + } + + 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: "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) + } + } + + 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 { + 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 + } + + 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), + } + + operationTimeout := "" + if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() { + operationTimeout = plan.OperationTimeout.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(), 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: "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) + } + } + + 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 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/universal_rebuild/internal/resources_gen/registry.go b/universal_rebuild/internal/resources_gen/registry.go new file mode 100644 index 0000000..183b8c8 --- /dev/null +++ b/universal_rebuild/internal/resources_gen/registry.go @@ -0,0 +1,76 @@ +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, + NewGiteaComplexResource, + NewHarborResource, + NewHttpResource, + NewK8sSthutrvalClusterResource, + NewK8sZitiControllerResource, + NewKafkaResource, + NewLuceeResource, + NewMariadbResource, + NewMongodbResource, + NewNextcloudResource, + NewNifiResource, + NewNodejsResource, + NewNoderedResource, + NewOpenwhiskResource, + NewPgadminResource, + NewPostgresResource, + NewRabbitmqResource, + NewRedisResource, + NewS3Resource, + NewS3bucketResource, + NewSupersetResource, + NewTemplateResource, + NewTenantResource, + NewValoTenantResource, + NewVappResource, + NewVcComplexResource, + NewVcNsxtResource, + NewVcOrgResource, + NewVcOrgSaasResource, + NewVcVdcResource, + NewVcVdcGroupResource, + NewVcVmResource, + NewVcVmV2Resource, + NewVcVmV3Resource, + NewVcexternalipResource, + NewVmpostgreResource, + NewClickhouseDatabaseResource, + NewClickhouseUserResource, + NewKafkaTopicResource, + NewKafkaUserResource, + NewMongodbUserResource, + NewS3SubUserResource, + NewDummyRedeployResource, + NewHttpRedeployResource, + NewK8sSthutrvalClusterReconcileResource, + NewK8sSthutrvalClusterUpdateSecretsResource, + NewLuceeRedeployResource, + NewLuceeRestartResource, + NewNextcloudRestartResource, + NewNodejsRedeployResource, + NewPgadminRedeployResource, + NewPostgresRecoveryResource, + NewPostgresRestartResource, + NewVcNsxtReconcileResource, + NewVcOrgReconcileResource, + NewVcVdcReconcileResource, + NewVcVdcGroupAddVdcResource, + NewVcVdcGroupReconcileResource, + NewVcVdcGroupRemoveVdcResource, + NewVcVmV3RedeployResource, + } +}