feat: scaffold terraform provider for fission via kubernetes CRD

This commit is contained in:
Naeel
2026-04-14 21:55:50 +03:00
parent 2e775e73a4
commit a8c28c751e
11 changed files with 659 additions and 0 deletions
@@ -0,0 +1,61 @@
package client
import (
"fmt"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)
// Client хранит клиентов Kubernetes API для работы с CRD Fission.
type Client struct {
DynClient dynamic.Interface
K8sClient kubernetes.Interface
Namespace string
}
// New создает Kubernetes clients из kubeconfig/context.
func New(kubeconfigPath, kubeContext, namespace string) (*Client, error) {
cfg, err := buildConfig(kubeconfigPath, kubeContext)
if err != nil {
return nil, err
}
dynClient, err := dynamic.NewForConfig(cfg)
if err != nil {
return nil, fmt.Errorf("create dynamic client: %w", err)
}
k8sClient, err := kubernetes.NewForConfig(cfg)
if err != nil {
return nil, fmt.Errorf("create kubernetes client: %w", err)
}
return &Client{
DynClient: dynClient,
K8sClient: k8sClient,
Namespace: namespace,
}, nil
}
func buildConfig(kubeconfigPath, kubeContext string) (*rest.Config, error) {
loadingRules := &clientcmd.ClientConfigLoadingRules{}
if kubeconfigPath != "" {
loadingRules.ExplicitPath = kubeconfigPath
}
overrides := &clientcmd.ConfigOverrides{}
if kubeContext != "" {
overrides.CurrentContext = kubeContext
}
clientCfg := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides)
cfg, err := clientCfg.ClientConfig()
if err != nil {
return nil, fmt.Errorf("build kube config: %w", err)
}
return cfg, nil
}
@@ -0,0 +1,126 @@
package provider
import (
"context"
"os"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types"
"terraform-provider-fission/internal/client"
"terraform-provider-fission/internal/resources"
)
var _ provider.Provider = &FissionProvider{}
type FissionProvider struct {
version string
}
type FissionProviderModel struct {
KubeconfigPath types.String `tfsdk:"kubeconfig_path"`
KubeContext types.String `tfsdk:"kube_context"`
Namespace types.String `tfsdk:"namespace"`
}
func New(version string) func() provider.Provider {
return func() provider.Provider {
return &FissionProvider{version: version}
}
}
func (p *FissionProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "fission"
resp.Version = p.version
}
func (p *FissionProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"kubeconfig_path": schema.StringAttribute{
Optional: true,
Description: "Путь к kubeconfig файлу.",
},
"kube_context": schema.StringAttribute{
Optional: true,
Description: "Имя kubernetes context.",
},
"namespace": schema.StringAttribute{
Optional: true,
Description: "Namespace для ресурсов Fission.",
},
},
}
}
func (p *FissionProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
var data FissionProviderModel
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
kubeconfigPath := data.KubeconfigPath.ValueString()
if kubeconfigPath == "" {
kubeconfigPath = os.Getenv("KUBECONFIG")
}
kubeContext := data.KubeContext.ValueString()
if kubeContext == "" {
kubeContext = os.Getenv("KUBE_CONTEXT")
}
namespace := data.Namespace.ValueString()
if namespace == "" {
namespace = os.Getenv("FISSION_NAMESPACE")
}
if namespace == "" {
namespace = "default"
}
fissionClient, err := client.New(kubeconfigPath, kubeContext, namespace)
if err != nil {
resp.Diagnostics.AddError("Ошибка инициализации Kubernetes клиента", err.Error())
return
}
resp.DataSourceData = fissionClient
resp.ResourceData = fissionClient
}
func (p *FissionProvider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{
resources.NewEnvironmentResource,
resources.NewPackageResource,
resources.NewFunctionResource,
resources.NewHTTPTriggerResource,
}
}
func (p *FissionProvider) DataSources(_ context.Context) []func() datasource.DataSource {
return nil
}
func (p *FissionProvider) ValidateConfig(ctx context.Context, req provider.ValidateConfigRequest, resp *provider.ValidateConfigResponse) {
var data FissionProviderModel
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
if data.Namespace.IsNull() || data.Namespace.IsUnknown() {
return
}
if data.Namespace.ValueString() == "" {
resp.Diagnostics.AddAttributeError(
path.Root("namespace"),
"Некорректный namespace",
"Значение namespace не может быть пустой строкой.",
)
}
}
@@ -0,0 +1,30 @@
package resources
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
)
var _ resource.Resource = &EnvironmentResource{}
type EnvironmentResource struct{}
func NewEnvironmentResource() resource.Resource {
return &EnvironmentResource{}
}
func (r *EnvironmentResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_environment"
}
func (r *EnvironmentResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{}
}
func (r *EnvironmentResource) Configure(_ context.Context, _ resource.ConfigureRequest, _ *resource.ConfigureResponse) {}
func (r *EnvironmentResource) Create(_ context.Context, _ resource.CreateRequest, _ *resource.CreateResponse) {}
func (r *EnvironmentResource) Read(_ context.Context, _ resource.ReadRequest, _ *resource.ReadResponse) {}
func (r *EnvironmentResource) Update(_ context.Context, _ resource.UpdateRequest, _ *resource.UpdateResponse) {}
func (r *EnvironmentResource) Delete(_ context.Context, _ resource.DeleteRequest, _ *resource.DeleteResponse) {}
@@ -0,0 +1,30 @@
package resources
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
)
var _ resource.Resource = &FunctionResource{}
type FunctionResource struct{}
func NewFunctionResource() resource.Resource {
return &FunctionResource{}
}
func (r *FunctionResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_function"
}
func (r *FunctionResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{}
}
func (r *FunctionResource) Configure(_ context.Context, _ resource.ConfigureRequest, _ *resource.ConfigureResponse) {}
func (r *FunctionResource) Create(_ context.Context, _ resource.CreateRequest, _ *resource.CreateResponse) {}
func (r *FunctionResource) Read(_ context.Context, _ resource.ReadRequest, _ *resource.ReadResponse) {}
func (r *FunctionResource) Update(_ context.Context, _ resource.UpdateRequest, _ *resource.UpdateResponse) {}
func (r *FunctionResource) Delete(_ context.Context, _ resource.DeleteRequest, _ *resource.DeleteResponse) {}
@@ -0,0 +1,30 @@
package resources
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
)
var _ resource.Resource = &HTTPTriggerResource{}
type HTTPTriggerResource struct{}
func NewHTTPTriggerResource() resource.Resource {
return &HTTPTriggerResource{}
}
func (r *HTTPTriggerResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_http_trigger"
}
func (r *HTTPTriggerResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{}
}
func (r *HTTPTriggerResource) Configure(_ context.Context, _ resource.ConfigureRequest, _ *resource.ConfigureResponse) {}
func (r *HTTPTriggerResource) Create(_ context.Context, _ resource.CreateRequest, _ *resource.CreateResponse) {}
func (r *HTTPTriggerResource) Read(_ context.Context, _ resource.ReadRequest, _ *resource.ReadResponse) {}
func (r *HTTPTriggerResource) Update(_ context.Context, _ resource.UpdateRequest, _ *resource.UpdateResponse) {}
func (r *HTTPTriggerResource) Delete(_ context.Context, _ resource.DeleteRequest, _ *resource.DeleteResponse) {}
@@ -0,0 +1,30 @@
package resources
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
)
var _ resource.Resource = &PackageResource{}
type PackageResource struct{}
func NewPackageResource() resource.Resource {
return &PackageResource{}
}
func (r *PackageResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_package"
}
func (r *PackageResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{}
}
func (r *PackageResource) Configure(_ context.Context, _ resource.ConfigureRequest, _ *resource.ConfigureResponse) {}
func (r *PackageResource) Create(_ context.Context, _ resource.CreateRequest, _ *resource.CreateResponse) {}
func (r *PackageResource) Read(_ context.Context, _ resource.ReadRequest, _ *resource.ReadResponse) {}
func (r *PackageResource) Update(_ context.Context, _ resource.UpdateRequest, _ *resource.UpdateResponse) {}
func (r *PackageResource) Delete(_ context.Context, _ resource.DeleteRequest, _ *resource.DeleteResponse) {}