feat: configurable timeouts for sless_function and sless_job
- sless_function: build_timeout_sec (optional, default 300s = 5 min) - sless_job: wait_timeout_sec (optional, default 600s = 10 min) - provider v0.1.3 published to terra.k8c.ru
This commit is contained in:
@@ -32,8 +32,9 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
)
|
||||
|
||||
// buildTimeout — максимальное время ожидания kaniko-сборки образа.
|
||||
const buildTimeout = 5 * time.Minute
|
||||
// defaultBuildTimeoutSec — дефолтный таймаут ожидания kaniko-сборки (300 сек = 5 мин).
|
||||
// Пользователь может переопределить через build_timeout_sec.
|
||||
const defaultBuildTimeoutSec = 300
|
||||
|
||||
var _ resource.Resource = &FunctionResource{}
|
||||
|
||||
@@ -58,6 +59,8 @@ type FunctionModel struct {
|
||||
// code_hash — sha256/md5 zip-файла, пользователь задаёт через filemd5().
|
||||
// Изменение hash → провайдер перезагружает код и запускает пересборку.
|
||||
CodeHash types.String `tfsdk:"code_hash"`
|
||||
// build_timeout_sec — максимальное ожидание kaniko-сборки. Дефолт 300 сек.
|
||||
BuildTimeoutSec types.Int64 `tfsdk:"build_timeout_sec"`
|
||||
Phase types.String `tfsdk:"phase"`
|
||||
ImageRef types.String `tfsdk:"image_ref"`
|
||||
}
|
||||
@@ -114,6 +117,13 @@ func (r *FunctionResource) Schema(_ context.Context, _ resource.SchemaRequest, r
|
||||
"code_hash": schema.StringAttribute{
|
||||
Optional: true,
|
||||
},
|
||||
// build_timeout_sec — таймаут ожидания kaniko-сборки. Дефолт 300 сек (5 мин).
|
||||
// Увеличь если функция с тяжёлыми зависимостями (например torch).
|
||||
"build_timeout_sec": schema.Int64Attribute{
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
MarkdownDescription: "Таймаут ожидания сборки образа в секундах. По умолчанию 300 (5 мин).",
|
||||
},
|
||||
// phase, image_ref — только для чтения, вычисляются оператором
|
||||
"phase": schema.StringAttribute{
|
||||
Computed: true,
|
||||
@@ -178,7 +188,11 @@ func (r *FunctionResource) Create(ctx context.Context, req resource.CreateReques
|
||||
resp.Diagnostics.AddError("upload code", err.Error())
|
||||
return
|
||||
}
|
||||
fn, err = r.client.WaitReady(ctx, ns, fn.Name, buildTimeout)
|
||||
buildSec := plan.BuildTimeoutSec.ValueInt64()
|
||||
if buildSec <= 0 {
|
||||
buildSec = defaultBuildTimeoutSec
|
||||
}
|
||||
fn, err = r.client.WaitReady(ctx, ns, fn.Name, time.Duration(buildSec)*time.Second)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("waiting for function ready", err.Error())
|
||||
return
|
||||
@@ -246,7 +260,11 @@ func (r *FunctionResource) Update(ctx context.Context, req resource.UpdateReques
|
||||
resp.Diagnostics.AddError("upload code", err.Error())
|
||||
return
|
||||
}
|
||||
fn, err = r.client.WaitReady(ctx, ns, name, buildTimeout)
|
||||
buildSec := plan.BuildTimeoutSec.ValueInt64()
|
||||
if buildSec <= 0 {
|
||||
buildSec = defaultBuildTimeoutSec
|
||||
}
|
||||
fn, err = r.client.WaitReady(ctx, ns, name, time.Duration(buildSec)*time.Second)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("waiting for function ready", err.Error())
|
||||
return
|
||||
@@ -269,8 +287,13 @@ func (r *FunctionResource) Delete(ctx context.Context, req resource.DeleteReques
|
||||
}
|
||||
|
||||
// fnToModel конвертирует API-ответ + plan (для локальных полей) → state модель.
|
||||
// plan используется для code_path и code_hash — API их не хранит.
|
||||
// plan используется для code_path, code_hash, build_timeout_sec — API их не хранит.
|
||||
func fnToModel(plan FunctionModel, fn *client.FunctionResponse) FunctionModel {
|
||||
buildTimeoutSec := plan.BuildTimeoutSec
|
||||
// Если не задан пользователем — записываем дефолт чтобы не было null в state
|
||||
if buildTimeoutSec.IsNull() || buildTimeoutSec.IsUnknown() || buildTimeoutSec.ValueInt64() <= 0 {
|
||||
buildTimeoutSec = types.Int64Value(defaultBuildTimeoutSec)
|
||||
}
|
||||
return FunctionModel{
|
||||
Namespace: types.StringValue(fn.Namespace),
|
||||
Name: types.StringValue(fn.Name),
|
||||
@@ -281,6 +304,7 @@ func fnToModel(plan FunctionModel, fn *client.FunctionResponse) FunctionModel {
|
||||
EnvVars: plan.EnvVars, // API возвращает null для пустого map — берём из plan
|
||||
CodePath: plan.CodePath,
|
||||
CodeHash: plan.CodeHash,
|
||||
BuildTimeoutSec: buildTimeoutSec,
|
||||
Phase: types.StringValue(fn.Phase),
|
||||
ImageRef: types.StringValue(fn.ImageRef),
|
||||
}
|
||||
|
||||
@@ -28,8 +28,9 @@ import (
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
)
|
||||
|
||||
// jobTimeout — максимальное время ожидания завершения джоба.
|
||||
const jobTimeout = 10 * time.Minute
|
||||
// defaultWaitTimeoutSec — дефолтный таймаут ожидания завершения джоба (600 сек = 10 мин).
|
||||
// Пользователь может переопределить через wait_timeout_sec.
|
||||
const defaultWaitTimeoutSec = 600
|
||||
|
||||
var _ resource.Resource = &JobResource{}
|
||||
|
||||
@@ -47,6 +48,8 @@ type JobModel struct {
|
||||
Name types.String `tfsdk:"name"`
|
||||
Function types.String `tfsdk:"function"`
|
||||
EventJSON types.String `tfsdk:"event_json"`
|
||||
// wait_timeout_sec — максимальное ожидание завершения джоба. Дефолт 600 сек.
|
||||
WaitTimeoutSec types.Int64 `tfsdk:"wait_timeout_sec"`
|
||||
Phase types.String `tfsdk:"phase"`
|
||||
StartTime types.String `tfsdk:"start_time"`
|
||||
CompletionTime types.String `tfsdk:"completion_time"`
|
||||
@@ -88,6 +91,12 @@ func (r *JobResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *
|
||||
stringplanmodifier.RequiresReplace(),
|
||||
},
|
||||
},
|
||||
// wait_timeout_sec — сколько ждать завершения джоба. Увеличь если код долго работает (например миграция БД).
|
||||
"wait_timeout_sec": schema.Int64Attribute{
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
MarkdownDescription: "Таймаут ожидания завершения джоба в секундах. По умолчанию 600 (10 мин).",
|
||||
},
|
||||
// Computed — заполняются после завершения джоба
|
||||
"phase": schema.StringAttribute{
|
||||
Computed: true,
|
||||
@@ -148,7 +157,11 @@ func (r *JobResource) Create(ctx context.Context, req resource.CreateRequest, re
|
||||
}
|
||||
|
||||
// Блокируем apply до завершения джоба (Succeeded или Failed)
|
||||
j, err := r.client.WaitJobDone(ctx, ns, plan.Name.ValueString(), jobTimeout)
|
||||
waitSec := plan.WaitTimeoutSec.ValueInt64()
|
||||
if waitSec <= 0 {
|
||||
waitSec = defaultWaitTimeoutSec
|
||||
}
|
||||
j, err := r.client.WaitJobDone(ctx, ns, plan.Name.ValueString(), time.Duration(waitSec)*time.Second)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("waiting for job to complete", err.Error())
|
||||
return
|
||||
@@ -198,11 +211,16 @@ func (r *JobResource) Delete(ctx context.Context, req resource.DeleteRequest, re
|
||||
|
||||
// jobToModel конвертирует API-ответ → state модель.
|
||||
func jobToModel(plan JobModel, j *client.JobResponse) JobModel {
|
||||
waitTimeoutSec := plan.WaitTimeoutSec
|
||||
if waitTimeoutSec.IsNull() || waitTimeoutSec.IsUnknown() || waitTimeoutSec.ValueInt64() <= 0 {
|
||||
waitTimeoutSec = types.Int64Value(defaultWaitTimeoutSec)
|
||||
}
|
||||
return JobModel{
|
||||
Namespace: types.StringValue(j.Namespace),
|
||||
Name: types.StringValue(j.Name),
|
||||
Function: types.StringValue(j.FunctionRef),
|
||||
EventJSON: plan.EventJSON, // API отдаёт event_json но берём из plan для консистентности
|
||||
EventJSON: plan.EventJSON,
|
||||
WaitTimeoutSec: waitTimeoutSec,
|
||||
Phase: types.StringValue(j.Phase),
|
||||
StartTime: types.StringValue(j.StartTime),
|
||||
CompletionTime: types.StringValue(j.CompletionTime),
|
||||
|
||||
Reference in New Issue
Block a user