package resources import ( "context" "fmt" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" "terraform-provider-fission/internal/client" ) var _ resource.Resource = &MQTriggerResource{} // MQTriggerResource управляет MQ-триггером через K8s Deployment+Secret (sqs-consumer). type MQTriggerResource struct { client *client.Client } type mqTriggerResourceModel struct { ID types.String `tfsdk:"id"` Name types.String `tfsdk:"name"` Namespace types.String `tfsdk:"namespace"` Function types.String `tfsdk:"function"` Queue types.String `tfsdk:"queue"` AccessKey types.String `tfsdk:"access_key"` SecretKey types.String `tfsdk:"secret_key"` SQSEndpoint types.String `tfsdk:"sqs_endpoint"` } func NewMQTriggerResource() resource.Resource { return &MQTriggerResource{} } func (r *MQTriggerResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_mq_trigger" } func (r *MQTriggerResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ Description: "MQ-триггер через K8s Deployment (sqs-consumer) + Secret с SQS credentials.", Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ Computed: true, Description: "Идентификатор ресурса (namespace/name).", }, "name": schema.StringAttribute{ Required: true, Description: "Имя MQ trigger.", PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, "namespace": schema.StringAttribute{ Optional: true, Computed: true, Description: "Kubernetes namespace.", PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, "function": schema.StringAttribute{ Required: true, Description: "Имя Fission Function, к которой направляются сообщения из очереди.", }, "queue": schema.StringAttribute{ Required: true, Description: "Имя SQS очереди.", }, "access_key": schema.StringAttribute{ Required: true, Sensitive: true, Description: "SQS Access Key.", }, "secret_key": schema.StringAttribute{ Required: true, Sensitive: true, Description: "SQS Secret Key.", }, "sqs_endpoint": schema.StringAttribute{ Optional: true, Computed: true, Default: stringdefault.StaticString("http://shared-sqs.shared-sqs.svc.cluster.local:4100"), Description: "SQS endpoint URL. По умолчанию — внутренний shared-sqs.", }, }, } } func (r *MQTriggerResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { if req.ProviderData == nil { return } c, ok := req.ProviderData.(*client.Client) if !ok { resp.Diagnostics.AddError("Неверный тип провайдера", fmt.Sprintf("ожидался *client.Client, получен %T", req.ProviderData)) return } r.client = c } func (r *MQTriggerResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var plan mqTriggerResourceModel resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) if resp.Diagnostics.HasError() { return } ns := plan.Namespace.ValueString() if ns == "" { ns = r.client.Namespace } info, err := r.client.CreateMQTrigger( ctx, plan.Name.ValueString(), ns, plan.Function.ValueString(), plan.Queue.ValueString(), plan.SQSEndpoint.ValueString(), plan.AccessKey.ValueString(), plan.SecretKey.ValueString(), ) if err != nil { resp.Diagnostics.AddError("Ошибка создания MQ trigger", err.Error()) return } plan.ID = types.StringValue(ns + "/" + plan.Name.ValueString()) plan.Namespace = types.StringValue(ns) plan.SQSEndpoint = types.StringValue(info.SQSEndpoint) resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) } func (r *MQTriggerResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var state mqTriggerResourceModel resp.Diagnostics.Append(req.State.Get(ctx, &state)...) if resp.Diagnostics.HasError() { return } ns := state.Namespace.ValueString() info, err := r.client.GetMQTrigger(ctx, ns, state.Name.ValueString()) if err != nil { if client.IsNotFound(err) { resp.State.RemoveResource(ctx) return } resp.Diagnostics.AddError("Ошибка чтения MQ trigger", err.Error()) return } state.Function = types.StringValue(info.Function) state.Queue = types.StringValue(info.Queue) state.SQSEndpoint = types.StringValue(info.SQSEndpoint) resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) } func (r *MQTriggerResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { var plan mqTriggerResourceModel resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) if resp.Diagnostics.HasError() { return } ns := plan.Namespace.ValueString() name := plan.Name.ValueString() // Удаляем старый и создаём заново с новыми параметрами. if err := r.client.DeleteMQTrigger(ctx, ns, name); err != nil { resp.Diagnostics.AddError("Ошибка удаления MQ trigger при обновлении", err.Error()) return } info, err := r.client.CreateMQTrigger( ctx, name, ns, plan.Function.ValueString(), plan.Queue.ValueString(), plan.SQSEndpoint.ValueString(), plan.AccessKey.ValueString(), plan.SecretKey.ValueString(), ) if err != nil { resp.Diagnostics.AddError("Ошибка создания MQ trigger при обновлении", err.Error()) return } plan.SQSEndpoint = types.StringValue(info.SQSEndpoint) resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) } func (r *MQTriggerResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { var state mqTriggerResourceModel resp.Diagnostics.Append(req.State.Get(ctx, &state)...) if resp.Diagnostics.HasError() { return } if err := r.client.DeleteMQTrigger(ctx, state.Namespace.ValueString(), state.Name.ValueString()); err != nil { resp.Diagnostics.AddError("Ошибка удаления MQ trigger", err.Error()) } }