fix+docs: FunctionJob label bugfix, job ErrAlreadyExists, python str→text/plain, operator.yaml v0.1.33, progress.md
- controllers/functionjob_controller.go: - PodTemplate labels: functionjob=, function= (k8s 1.27+ удалил job-name=) - getJobPodOutput принимает labelSelector вместо jobName - захват stderr при Failed job; truncateForStatus() helper - terraform/provider/internal/client/client.go: ErrJobAlreadyExists (409 Conflict) - terraform/provider/internal/resources/job_resource.go: при конфликте создания — читаем существующий job - runtimes/python3.11/server.py: str return → text/plain - internal/builder/context.go: python runtime base image → v0.1.3 - deployments/k8s/operator.yaml: image → v0.1.33 - doc/progress.md: добавлены секции FunctionJob bugfix, str→text/plain, web-console v0.2.0
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// 2026-03-11
|
||||
// 2026-03-17 12:20
|
||||
// client.go — HTTP-клиент для REST API sless оператора.
|
||||
// Изолирован от terraform-plugin-framework — зависит только от stdlib и net/http.
|
||||
// Все методы принимают ctx для правильной работы с таймаутами terraform.
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
@@ -44,6 +45,9 @@ type Client struct {
|
||||
Namespace string
|
||||
}
|
||||
|
||||
// ErrJobAlreadyExists возвращается при попытке создать FunctionJob с уже существующим именем.
|
||||
var ErrJobAlreadyExists = errors.New("job already exists")
|
||||
|
||||
// New создаёт клиент.
|
||||
// - endpoint — базовый URL оператора (без trailing slash), например "https://sless-api.kube5s.ru"
|
||||
// - token — Bearer JWT-токен облака
|
||||
@@ -456,6 +460,9 @@ func (c *Client) CreateJob(ctx context.Context, ns string, req JobRequest) (*Job
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
if resp.StatusCode == http.StatusConflict {
|
||||
return nil, fmt.Errorf("%w: %s", ErrJobAlreadyExists, strings.TrimSpace(string(body)))
|
||||
}
|
||||
return nil, fmt.Errorf("create job: status %d: %s", resp.StatusCode, body)
|
||||
}
|
||||
var j JobResponse
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// 2026-03-08
|
||||
// 2026-03-17 12:20
|
||||
// job_resource.go — Terraform ресурс sless_job.
|
||||
//
|
||||
// Lifecycle:
|
||||
@@ -17,6 +17,7 @@ package resources
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@@ -163,15 +164,28 @@ func (r *JobResource) Create(ctx context.Context, req resource.CreateRequest, re
|
||||
// run_id=0: создаём FunctionJob в k8s, но оператор не запустит k8s Job.
|
||||
// Пользователь может поменять run_id > 0 позже чтобы запустить.
|
||||
runID := plan.RunID.ValueInt64()
|
||||
_, err := r.client.CreateJob(ctx, ns, client.JobRequest{
|
||||
createdJob, err := r.client.CreateJob(ctx, ns, client.JobRequest{
|
||||
Name: plan.Name.ValueString(),
|
||||
FunctionRef: plan.Function.ValueString(),
|
||||
EventJSON: eventJSON,
|
||||
RunID: runID,
|
||||
})
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError("create job", err.Error())
|
||||
return
|
||||
if errors.Is(err, client.ErrJobAlreadyExists) {
|
||||
existingJob, getErr := r.client.GetJob(ctx, ns, plan.Name.ValueString())
|
||||
if getErr != nil {
|
||||
resp.Diagnostics.AddError("create job", fmt.Sprintf("job already exists and get existing failed: %s", getErr.Error()))
|
||||
return
|
||||
}
|
||||
if existingJob == nil {
|
||||
resp.Diagnostics.AddError("create job", "job already exists but cannot be read right after conflict")
|
||||
return
|
||||
}
|
||||
createdJob = existingJob
|
||||
} else {
|
||||
resp.Diagnostics.AddError("create job", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Если RunID=0 — не ждём завершения, пишем state сразу
|
||||
@@ -187,10 +201,10 @@ func (r *JobResource) Create(ctx context.Context, req resource.CreateRequest, re
|
||||
EventJSON: plan.EventJSON,
|
||||
RunID: types.Int64Value(0),
|
||||
WaitTimeoutSec: waitTimeoutSec,
|
||||
Phase: types.StringValue("Skipped"),
|
||||
StartTime: types.StringValue(""),
|
||||
CompletionTime: types.StringValue(""),
|
||||
Message: types.StringValue("run_id=0: set run_id>0 to execute"),
|
||||
Phase: types.StringValue(createdJob.Phase),
|
||||
StartTime: types.StringValue(createdJob.StartTime),
|
||||
CompletionTime: types.StringValue(createdJob.CompletionTime),
|
||||
Message: types.StringValue(createdJob.Message),
|
||||
})...)
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user