customize resources

This commit is contained in:
2025-04-24 15:46:06 -04:00
parent b649164b63
commit b9ca51af01
10 changed files with 206 additions and 66 deletions

View File

@@ -12,6 +12,7 @@ require (
github.com/lxc/terraform-provider-incus/shim v0.0.0-00010101000000-000000000000
github.com/pulumi/pulumi-terraform-bridge/v3 v3.106.0
github.com/pulumi/pulumi/pkg/v3 v3.160.0
github.com/pulumi/pulumi/sdk/v3 v3.160.0
)
@@ -143,7 +144,6 @@ require (
github.com/pulumi/inflector v0.1.1 // indirect
github.com/pulumi/pulumi-java/pkg v1.8.0 // indirect
github.com/pulumi/pulumi-yaml v1.15.1 // indirect
github.com/pulumi/pulumi/sdk/v3 v3.160.0 // indirect
github.com/pulumi/schema-tools v0.1.2 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect

View File

@@ -15,7 +15,10 @@
package incus
import (
"context"
"fmt"
"path"
"strings"
// Allow embedding bridge-metadata.json in the provider.
_ "embed"
@@ -23,8 +26,10 @@ import (
incus "github.com/lxc/terraform-provider-incus/shim" // Import the upstream provider
pfbridge "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/pf/tfbridge"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge/info"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge/tokens"
"github.com/pulumi/pulumi/pkg/v3/codegen/schema"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
"github.com/brandonkal/pulumi-incus/provider/pkg/version"
)
@@ -38,9 +43,7 @@ const (
mainMod = "index" // the incus module
)
// Temporarily comment out the bridge-metadata.json embedding
// //go:embed cmd/pulumi-resource-incus/bridge-metadata.json
// var metadata []byte
//go:embed cmd/pulumi-resource-incus/bridge-metadata.json
var metadata []byte
// Provider returns additional overlaid schema and metadata associated with the provider.
@@ -131,37 +134,40 @@ func Provider() tfbridge.ProviderInfo {
// category/cloud tag helps with categorizing the package in the Pulumi Registry.
// For all available categories, see `Keywords` in
// https://www.pulumi.com/docs/guides/pulumi-packages/schema/#package.
Keywords: []string{"incus", "category/cloud"},
Keywords: []string{"incus", "category/cloud", "containers", "nimbus"},
License: "Apache-2.0",
Homepage: "https://linuxcontainers.org",
Repository: "https://github.com/brandonkal/pulumi-incus",
Repository: "https://git.kalinow.ski/nimbus/pulumi-incus",
// The GitHub Org for the provider - defaults to `terraform-providers`. Note that this should
// match the TF provider module's require directive, not any replace directives.
GitHubOrg: "lxc",
// Temporarily comment out the MetadataInfo
MetadataInfo: tfbridge.NewProviderMetadata(metadata),
Config: map[string]*tfbridge.SchemaInfo{
Config: map[string]*tfbridge.SchemaInfo{
// Add any required configuration here, or remove the example below if
// no additional points are required.
"region": {
Type: "incus:region/region:Region",
},
// "region": {
// Type: "incus:region/region:Region",
// },
},
// If extra types are needed for configuration, they can be added here.
ExtraTypes: map[string]schema.ComplexTypeSpec{
"incus:region/region:Region": {
ObjectTypeSpec: schema.ObjectTypeSpec{
Type: "string",
},
Enum: []schema.EnumValueSpec{
{Name: "here", Value: "HERE"},
{Name: "overThere", Value: "OVER_THERE"},
},
},
// "incus:region/region:Region": {
// ObjectTypeSpec: schema.ObjectTypeSpec{
// Type: "string",
// },
// Enum: []schema.EnumValueSpec{
// {Name: "here", Value: "HERE"},
// {Name: "overThere", Value: "OVER_THERE"},
// },
// },
},
JavaScript: &tfbridge.JavaScriptInfo{
// RespectSchemaVersion ensures the SDK is generated linking to the correct version of the provider.
RespectSchemaVersion: true,
RespectSchemaVersion: true,
PackageName: "@kiterun/incus",
TypeScriptVersion: "^5.8.3",
UseTypeOnlyReferences: true,
},
Python: &tfbridge.PythonInfo{
// RespectSchemaVersion ensures the SDK is generated linking to the correct version of the provider.
@@ -199,11 +205,155 @@ func Provider() tfbridge.ProviderInfo {
//
// You shouldn't need to override anything, but if you do, use the [tfbridge.ProviderInfo.Resources]
// and [tfbridge.ProviderInfo.DataSources].
prov.MustComputeTokens(tokens.SingleModule("incus_", mainMod,
tokens.MakeStandard(mainPkg)))
prov.MustComputeTokens(tokens.SingleModule("incus_", mainMod, tokens.MakeStandard(mainPkg)))
// Add special ID handling for the incus_instance resource
// Docs here https://registry.terraform.io/providers/lxc/incus/latest/docs/resources/certificate
defaultProjectField := map[string]*info.Schema{
"project": {
Default: &info.Default{
Value: "default",
},
},
}
prov.Resources["incus_certificate"] = &tfbridge.ResourceInfo{
Tok: tfbridge.MakeResource(mainPkg, mainMod, "Certificate"),
ComputeID: tfbridge.DelegateIDField("name", prov.Name, prov.Repository),
}
prov.Resources["incus_cluster_group"] = &tfbridge.ResourceInfo{
Tok: tfbridge.MakeResource(mainPkg, mainMod, "ClusterGroup"),
ComputeID: tfbridge.DelegateIDField("name", prov.Name, prov.Repository),
}
prov.Resources["incus_image"] = &tfbridge.ResourceInfo{
Tok: tfbridge.MakeResource(mainPkg, mainMod, "Image"),
// Does this work if source image is used?
ComputeID: delegateIDFields([]resource.PropertyKey{"project", "fingerprint"}, prov.Name, prov.Repository),
// DREAM: default project
// Fields: defaultProjectField,
}
prov.Resources["incus_instance"] = &tfbridge.ResourceInfo{
Tok: tfbridge.MakeResource(mainPkg, mainMod, "Instance"),
ComputeID: delegateIDFields([]resource.PropertyKey{"project", "name"}, prov.Name, prov.Repository),
Fields: defaultProjectField,
DeleteBeforeReplace: true,
}
prov.Resources["incus_instance_snapshot"] = &tfbridge.ResourceInfo{
Tok: tfbridge.MakeResource(mainPkg, mainMod, "InstanceSnapshot"),
ComputeID: delegateIDFields([]resource.PropertyKey{"project", "name"}, prov.Name, prov.Repository),
Fields: defaultProjectField,
}
prov.Resources["incus_network"] = &tfbridge.ResourceInfo{
Tok: tfbridge.MakeResource(mainPkg, mainMod, "Network"),
ComputeID: delegateIDFields([]resource.PropertyKey{"project", "name"}, prov.Name, prov.Repository),
Fields: defaultProjectField,
}
prov.Resources["incus_network_acl"] = &tfbridge.ResourceInfo{
Tok: tfbridge.MakeResource(mainPkg, mainMod, "NetworkAcl"),
ComputeID: delegateIDFields([]resource.PropertyKey{"project", "name"}, prov.Name, prov.Repository),
Fields: defaultProjectField,
}
prov.Resources["incus_network_forward"] = &tfbridge.ResourceInfo{
Tok: tfbridge.MakeResource(mainPkg, mainMod, "NetworkForward"),
ComputeID: delegateIDFields([]resource.PropertyKey{"project", "network", "listen_address"}, prov.Name, prov.Repository),
// DREAM: project
// Fields: defaultProjectField,
}
prov.Resources["incus_network_integration"] = &tfbridge.ResourceInfo{
Tok: tfbridge.MakeResource(mainPkg, mainMod, "NetworkIntegration"),
ComputeID: delegateIDFields([]resource.PropertyKey{"project", "name", "type"}, prov.Name, prov.Repository),
Fields: defaultProjectField,
}
prov.Resources["incus_network_lb"] = &tfbridge.ResourceInfo{
Tok: tfbridge.MakeResource(mainPkg, mainMod, "NetworkLoadBalancer"),
ComputeID: delegateIDFields([]resource.PropertyKey{"project", "network", "listen_address"}, prov.Name, prov.Repository),
// Fields: defaultProjectField,
}
prov.Resources["incus_network_peer"] = &tfbridge.ResourceInfo{
Tok: tfbridge.MakeResource(mainPkg, mainMod, "NetworkPeer"),
ComputeID: delegateIDFields([]resource.PropertyKey{"project", "name", "network"}, prov.Name, prov.Repository),
Fields: defaultProjectField,
}
prov.Resources["incus_network_zone"] = &tfbridge.ResourceInfo{
Tok: tfbridge.MakeResource(mainPkg, mainMod, "NetworkZone"),
ComputeID: delegateIDFields([]resource.PropertyKey{"project", "name"}, prov.Name, prov.Repository),
Fields: defaultProjectField,
}
prov.Resources["incus_network_zone_record"] = &tfbridge.ResourceInfo{
Tok: tfbridge.MakeResource(mainPkg, mainMod, "NetworkZoneRecord"),
ComputeID: delegateIDFields([]resource.PropertyKey{"project", "zone", "name"}, prov.Name, prov.Repository),
Fields: defaultProjectField,
}
prov.Resources["incus_profile"] = &tfbridge.ResourceInfo{
Tok: tfbridge.MakeResource(mainPkg, mainMod, "Profile"),
ComputeID: delegateIDFields([]resource.PropertyKey{"project", "name"}, prov.Name, prov.Repository),
Fields: defaultProjectField,
}
prov.Resources["incus_project"] = &tfbridge.ResourceInfo{
Tok: tfbridge.MakeResource(mainPkg, mainMod, "Project"),
ComputeID: tfbridge.DelegateIDField("name", prov.Name, prov.Repository),
}
prov.Resources["incus_storage_bucket"] = &tfbridge.ResourceInfo{
Tok: tfbridge.MakeResource(mainPkg, mainMod, "StorageBucket"),
ComputeID: delegateIDFields([]resource.PropertyKey{"project", "pool", "name"}, prov.Name, prov.Repository),
Fields: defaultProjectField,
}
prov.Resources["incus_storage_bucket_key"] = &tfbridge.ResourceInfo{
Tok: tfbridge.MakeResource(mainPkg, mainMod, "StorageBucketKey"),
ComputeID: delegateIDFields([]resource.PropertyKey{"project", "pool", "name"}, prov.Name, prov.Repository),
Fields: defaultProjectField,
}
prov.Resources["incus_storage_pool"] = &tfbridge.ResourceInfo{
Tok: tfbridge.MakeResource(mainPkg, mainMod, "StoragePool"),
ComputeID: delegateIDFields([]resource.PropertyKey{"project", "name"}, prov.Name, prov.Repository),
Fields: defaultProjectField,
}
prov.Resources["incus_storage_volume"] = &tfbridge.ResourceInfo{
Tok: tfbridge.MakeResource(mainPkg, mainMod, "StorageVolume"),
ComputeID: delegateIDFields([]resource.PropertyKey{"project", "pool", "name"}, prov.Name, prov.Repository),
Fields: defaultProjectField,
}
prov.MustApplyAutoAliases()
prov.SetAutonaming(255, "-")
return prov
}
func delegateIDFields(fields []resource.PropertyKey, providerName, repoURL string) tfbridge.ComputeID {
return func(ctx context.Context, state resource.PropertyMap) (resource.ID, error) {
if len(fields) == 0 {
return "", fmt.Errorf("no fields provided for ID computation")
}
var idParts []string
for _, field := range fields {
id, err := tfbridge.DelegateIDProperty(resource.PropertyPath{string(field)}, providerName, repoURL)(ctx, state)
if err != nil {
return "", err
}
idParts = append(idParts, string(id))
}
return resource.ID(strings.Join(idParts, "/")), nil
}
}