feat: provider v0.1.9 — namespace removed from resources, moved to provider block

This commit is contained in:
“Naeel”
2026-03-09 15:12:07 +04:00
parent 0aaeb47b3b
commit 17d32fcb39
23 changed files with 138 additions and 141 deletions
+3 -1
View File
@@ -23,14 +23,16 @@ type Client struct {
httpClient *http.Client
endpoint string
token string
Namespace string // берётся из provider {}, пользователь не касается
}
// New создаёт клиент. endpoint — базовый URL оператора (без trailing slash).
func New(endpoint, token string) *Client {
func New(endpoint, token, namespace string) *Client {
return &Client{
httpClient: &http.Client{Timeout: 30 * time.Second},
endpoint: endpoint,
token: token,
Namespace: namespace,
}
}
@@ -28,8 +28,9 @@ type SlessProvider struct {
// SlessProviderModel — конфигурация блока provider {} в .tf файле.
type SlessProviderModel struct {
Endpoint types.String `tfsdk:"endpoint"`
Token types.String `tfsdk:"token"`
Endpoint types.String `tfsdk:"endpoint"`
Token types.String `tfsdk:"token"`
Namespace types.String `tfsdk:"namespace"`
}
// New возвращает фабрику провайдера — точная копия паттерна nubes.
@@ -56,6 +57,12 @@ func (p *SlessProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp
Optional: true,
Sensitive: true,
},
// namespace — окружение/проект в кластере. Задаётся один раз здесь.
// В ресурсах (sless_function, sless_trigger, sless_job) namespace НЕ указывается.
"namespace": schema.StringAttribute{
MarkdownDescription: "Пространство имён (окружение). Задаётся один раз для всех ресурсов.",
Required: true,
},
},
}
}
@@ -87,7 +94,9 @@ func (p *SlessProvider) Configure(ctx context.Context, req provider.ConfigureReq
}
}
c := client.New(endpoint, token)
namespace := config.Namespace.ValueString()
c := client.New(endpoint, token, namespace)
resp.ResourceData = c
resp.DataSourceData = c
}
@@ -51,7 +51,6 @@ func NewFunctionResource() resource.Resource {
// FunctionModel — модель состояния terraform для sless_function.
type FunctionModel struct {
Namespace types.String `tfsdk:"namespace"`
Name types.String `tfsdk:"name"`
Runtime types.String `tfsdk:"runtime"`
Entrypoint types.String `tfsdk:"entrypoint"`
@@ -75,13 +74,7 @@ func (r *FunctionResource) Metadata(_ context.Context, req resource.MetadataRequ
func (r *FunctionResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
// namespace + name — immutable, смена требует пересоздания ресурса
"namespace": schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
// name — immutable, смена требует пересоздания ресурса
"name": schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{
@@ -175,7 +168,7 @@ func (r *FunctionResource) Create(ctx context.Context, req resource.CreateReques
return
}
ns := plan.Namespace.ValueString()
ns := r.client.Namespace
envVars, d := mapToStringMap(ctx, plan.EnvVars)
resp.Diagnostics.Append(d...)
if resp.Diagnostics.HasError() {
@@ -221,7 +214,7 @@ func (r *FunctionResource) Read(ctx context.Context, req resource.ReadRequest, r
return
}
fn, err := r.client.GetFunction(ctx, state.Namespace.ValueString(), state.Name.ValueString())
fn, err := r.client.GetFunction(ctx, r.client.Namespace, state.Name.ValueString())
if err != nil {
resp.Diagnostics.AddError("read function", err.Error())
return
@@ -243,7 +236,7 @@ func (r *FunctionResource) Update(ctx context.Context, req resource.UpdateReques
return
}
ns := plan.Namespace.ValueString()
ns := r.client.Namespace
name := plan.Name.ValueString()
envVars, d := mapToStringMap(ctx, plan.EnvVars)
@@ -293,7 +286,7 @@ func (r *FunctionResource) Delete(ctx context.Context, req resource.DeleteReques
return
}
if err := r.client.DeleteFunction(ctx, state.Namespace.ValueString(), state.Name.ValueString()); err != nil {
if err := r.client.DeleteFunction(ctx, r.client.Namespace, state.Name.ValueString()); err != nil {
resp.Diagnostics.AddError("delete function", err.Error())
}
}
@@ -307,7 +300,6 @@ func fnToModel(plan FunctionModel, fn *client.FunctionResponse) FunctionModel {
buildTimeoutSec = types.Int64Value(defaultBuildTimeoutSec)
}
return FunctionModel{
Namespace: types.StringValue(fn.Namespace),
Name: types.StringValue(fn.Name),
Runtime: types.StringValue(fn.Runtime),
Entrypoint: types.StringValue(fn.Entrypoint),
@@ -49,7 +49,6 @@ func NewJobResource() resource.Resource {
// JobModel — модель состояния terraform для sless_job.
type JobModel struct {
Namespace types.String `tfsdk:"namespace"`
Name types.String `tfsdk:"name"`
Function types.String `tfsdk:"function"`
EventJSON types.String `tfsdk:"event_json"`
@@ -73,12 +72,7 @@ func (r *JobResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *
MarkdownDescription: "Одноразовый запуск serverless функции. terraform apply блокируется до завершения джоба.",
Attributes: map[string]schema.Attribute{
// Все input-поля immutable — джоб нельзя "изменить", только пересоздать.
"namespace": schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"name": schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{
@@ -160,7 +154,7 @@ func (r *JobResource) Create(ctx context.Context, req resource.CreateRequest, re
return
}
ns := plan.Namespace.ValueString()
ns := r.client.Namespace
eventJSON := plan.EventJSON.ValueString()
if eventJSON == "" {
eventJSON = "{}"
@@ -188,7 +182,6 @@ func (r *JobResource) Create(ctx context.Context, req resource.CreateRequest, re
waitTimeoutSec = types.Int64Value(defaultWaitTimeoutSec)
}
resp.Diagnostics.Append(resp.State.Set(ctx, JobModel{
Namespace: types.StringValue(plan.Namespace.ValueString()),
Name: types.StringValue(plan.Name.ValueString()),
Function: types.StringValue(plan.Function.ValueString()),
EventJSON: plan.EventJSON,
@@ -223,7 +216,7 @@ func (r *JobResource) Read(ctx context.Context, req resource.ReadRequest, resp *
return
}
j, err := r.client.GetJob(ctx, state.Namespace.ValueString(), state.Name.ValueString())
j, err := r.client.GetJob(ctx, r.client.Namespace, state.Name.ValueString())
if err != nil {
resp.Diagnostics.AddError("read job", err.Error())
return
@@ -250,7 +243,7 @@ func (r *JobResource) Delete(ctx context.Context, req resource.DeleteRequest, re
return
}
if err := r.client.DeleteJob(ctx, state.Namespace.ValueString(), state.Name.ValueString()); err != nil {
if err := r.client.DeleteJob(ctx, r.client.Namespace, state.Name.ValueString()); err != nil {
resp.Diagnostics.AddError("delete job", err.Error())
}
}
@@ -262,7 +255,6 @@ func jobToModel(plan JobModel, j *client.JobResponse) JobModel {
waitTimeoutSec = types.Int64Value(defaultWaitTimeoutSec)
}
return JobModel{
Namespace: types.StringValue(j.Namespace),
Name: types.StringValue(j.Name),
Function: types.StringValue(j.FunctionRef),
EventJSON: plan.EventJSON,
@@ -35,7 +35,6 @@ func NewTriggerResource() resource.Resource {
// TriggerModel — модель состояния terraform для sless_trigger.
type TriggerModel struct {
Namespace types.String `tfsdk:"namespace"`
Name types.String `tfsdk:"name"`
Type types.String `tfsdk:"type"`
FunctionRef types.String `tfsdk:"function"`
@@ -54,12 +53,6 @@ func (r *TriggerResource) Metadata(_ context.Context, req resource.MetadataReque
func (r *TriggerResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"namespace": schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"name": schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{
@@ -136,7 +129,7 @@ func (r *TriggerResource) Create(ctx context.Context, req resource.CreateRequest
return
}
tr, err := r.client.CreateTrigger(ctx, plan.Namespace.ValueString(), client.TriggerRequest{
tr, err := r.client.CreateTrigger(ctx, r.client.Namespace, client.TriggerRequest{
Name: plan.Name.ValueString(),
Type: plan.Type.ValueString(),
FunctionRef: plan.FunctionRef.ValueString(),
@@ -151,7 +144,7 @@ func (r *TriggerResource) Create(ctx context.Context, req resource.CreateRequest
// Контроллер заполняет status.URL асинхронно — ждём до 30 секунд.
// Без этого URL остаётся пустым в state и требует ручного terraform refresh.
if tr.URL == "" && plan.Type.ValueString() == "http" {
ns := plan.Namespace.ValueString()
ns := r.client.Namespace
name := plan.Name.ValueString()
deadline := time.Now().Add(30 * time.Second)
for time.Now().Before(deadline) {
@@ -174,7 +167,7 @@ func (r *TriggerResource) Read(ctx context.Context, req resource.ReadRequest, re
return
}
tr, err := r.client.GetTrigger(ctx, state.Namespace.ValueString(), state.Name.ValueString())
tr, err := r.client.GetTrigger(ctx, r.client.Namespace, state.Name.ValueString())
if err != nil {
resp.Diagnostics.AddError("read trigger", err.Error())
return
@@ -198,7 +191,7 @@ func (r *TriggerResource) Update(ctx context.Context, req resource.UpdateRequest
}
enabled := plan.Enabled.ValueBool()
tr, err := r.client.UpdateTrigger(ctx, plan.Namespace.ValueString(), plan.Name.ValueString(), client.TriggerUpdateRequest{
tr, err := r.client.UpdateTrigger(ctx, r.client.Namespace, plan.Name.ValueString(), client.TriggerUpdateRequest{
Enabled: &enabled,
})
if err != nil {
@@ -216,7 +209,7 @@ func (r *TriggerResource) Delete(ctx context.Context, req resource.DeleteRequest
return
}
if err := r.client.DeleteTrigger(ctx, state.Namespace.ValueString(), state.Name.ValueString()); err != nil {
if err := r.client.DeleteTrigger(ctx, r.client.Namespace, state.Name.ValueString()); err != nil {
resp.Diagnostics.AddError("delete trigger", err.Error())
}
}
@@ -230,7 +223,6 @@ func trToModel(tr *client.TriggerResponse) TriggerModel {
schedule = types.StringValue(tr.Schedule)
}
return TriggerModel{
Namespace: types.StringValue(tr.Namespace),
Name: types.StringValue(tr.Name),
Type: types.StringValue(tr.Type),
FunctionRef: types.StringValue(tr.FunctionRef),