Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pkg/convert/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ type Encoding interface {
NewResourceEncoder(resource string, resourceType tftypes.Object) (Encoder, error)
NewDataSourceDecoder(dataSource string, dataSourceType tftypes.Object) (Decoder, error)
NewDataSourceEncoder(dataSource string, dataSourceType tftypes.Object) (Encoder, error)
NewEphemeralResourceDecoder(ephemeralResource string, resourceType tftypes.Object) (Decoder, error)
NewEphemeralResourceEncoder(ephemeralResource string, resourceType tftypes.Object) (Encoder, error)
}

// Like PropertyNames but specialized to either a type by token or config property.
Expand Down
18 changes: 18 additions & 0 deletions pkg/convert/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,24 @@ func (e *encoding) NewDataSourceDecoder(
return dec, nil
}

func (e *encoding) NewEphemeralResourceEncoder(resource string, objectType tftypes.Object) (Encoder, error) {
mctx := newEphemeralResourceSchemaMapContext(resource, e.SchemaOnlyProvider, e.ProviderInfo)
enc, err := NewObjectEncoder(ObjectSchema{mctx.schemaMap, mctx.schemaInfos, &objectType})
if err != nil {
return nil, fmt.Errorf("cannot derive an encoder for resource %q: %w", resource, err)
}
return enc, nil
}

func (e *encoding) NewEphemeralResourceDecoder(resource string, objectType tftypes.Object) (Decoder, error) {
mctx := newEphemeralResourceSchemaMapContext(resource, e.SchemaOnlyProvider, e.ProviderInfo)
dec, err := NewObjectDecoder(ObjectSchema{mctx.schemaMap, mctx.schemaInfos, &objectType})
if err != nil {
return nil, fmt.Errorf("cannot derive a decoder for resource %q: %w", resource, err)
}
return dec, nil
}

func buildPropertyEncoders(
mctx *schemaMapContext, objectType tftypes.Object,
) (map[terraformPropertyName]Encoder, error) {
Expand Down
17 changes: 16 additions & 1 deletion pkg/convert/schema_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"

"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/walk"
)

Expand Down Expand Up @@ -73,6 +73,21 @@ func newDataSourceSchemaMapContext(
return newSchemaMapContext(sm, fields)
}

func newEphemeralResourceSchemaMapContext(
resource string,
schemaOnlyProvider shim.Provider,
providerInfo *tfbridge.ProviderInfo,
) *schemaMapContext {
r := schemaOnlyProvider.EphemeralResourcesMap().Get(resource)
contract.Assertf(r != nil, "no ephemeral resource %q found in ResourceMap", resource)
sm := r.Schema()
var fields map[string]*tfbridge.SchemaInfo
if providerInfo != nil {
fields = providerInfo.EphemeralResources[resource].GetFields()
}
return newSchemaMapContext(sm, fields)
}

func (sc *schemaMapContext) PropertyKey(tfname terraformPropertyName, _ tftypes.Type) resource.PropertyKey {
return sc.ToPropertyKey(tfname)
}
Expand Down
5 changes: 5 additions & 0 deletions pkg/pf/internal/pfutils/attr.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

"github.com/hashicorp/terraform-plugin-framework/attr"
dschema "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
eschema "github.com/hashicorp/terraform-plugin-framework/ephemeral/schema"
prschema "github.com/hashicorp/terraform-plugin-framework/provider/schema"
rschema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-go/tftypes"
Expand Down Expand Up @@ -65,6 +66,10 @@ func FromResourceAttribute(x rschema.Attribute) Attr {
return FromAttrLike(x)
}

func FromEphemeralResourceAttribute(x eschema.Attribute) Attr {
return FromAttrLike(x)
}

func FromAttrLike(attrLike AttrLike) Attr {
nested, nestingMode := extractNestedAttributes(attrLike)
hasDefault := hasDefault(attrLike)
Expand Down
74 changes: 74 additions & 0 deletions pkg/pf/internal/pfutils/ephemeral_resources.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright 2016-2022, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package pfutils

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-framework/ephemeral"
"github.com/hashicorp/terraform-plugin-framework/provider"

"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/pf/internal/runtypes"
shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
)

func GatherEphemeralResources[F func(Schema) shim.SchemaMap](
ctx context.Context, prov provider.Provider, f F,
) (runtypes.EphemeralResources, error) {
provMetadata := queryProviderMetadata(ctx, prov)
es := make(collection[func() ephemeral.EphemeralResource])

eprov, ok := prov.(provider.ProviderWithEphemeralResources)
if ok {
for _, makeEphemeralResource := range eprov.EphemeralResources(ctx) {
ephemeralResource := makeEphemeralResource()

meta := ephemeral.MetadataResponse{}
ephemeralResource.Metadata(ctx, ephemeral.MetadataRequest{
ProviderTypeName: provMetadata.TypeName,
}, &meta)

schemaResponse := &ephemeral.SchemaResponse{}
ephemeralResource.Schema(ctx, ephemeral.SchemaRequest{}, schemaResponse)

ephemeralResourceSchema := schemaResponse.Schema
diag := schemaResponse.Diagnostics
if err := checkDiagsForErrors(diag); err != nil {
return nil, fmt.Errorf("Resource %s GetSchema() error: %w", meta.TypeName, err)
}

es[runtypes.TypeOrRenamedEntityName(meta.TypeName)] = entry[func() ephemeral.EphemeralResource]{
t: makeEphemeralResource,
schema: FromEphemeralResourceSchema(ephemeralResourceSchema),
tfName: runtypes.TypeName(meta.TypeName),
}
}
}

return &ephemeralResources{collection: es, convert: f}, nil
}

type ephemeralResources struct {
collection[func() ephemeral.EphemeralResource]
convert func(Schema) shim.SchemaMap
}

func (r ephemeralResources) Schema(t runtypes.TypeOrRenamedEntityName) runtypes.Schema {
entry := r.collection[t]
return runtypesSchemaAdapter{entry.schema, r.convert, entry.tfName}
}

func (ephemeralResources) IsEphemeralResources() {}
6 changes: 6 additions & 0 deletions pkg/pf/internal/pfutils/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

"github.com/hashicorp/terraform-plugin-framework/attr"
dschema "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
eschema "github.com/hashicorp/terraform-plugin-framework/ephemeral/schema"
prschema "github.com/hashicorp/terraform-plugin-framework/provider/schema"
rschema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
Expand Down Expand Up @@ -66,6 +67,11 @@ func FromResourceSchema(x rschema.Schema) Schema {
return newSchemaAdapter(x, x.Type(), x.DeprecationMessage, attrs, blocks, &x)
}

func FromEphemeralResourceSchema(x eschema.Schema) Schema {
attrs := convertMap(FromEphemeralResourceAttribute, x.Attributes)
return newSchemaAdapter(x, x.Type(), x.DeprecationMessage, attrs, nil, nil)
}

type schemaAdapter struct {
tftypes.AttributePathStepper
attrType attr.Type
Expand Down
6 changes: 6 additions & 0 deletions pkg/pf/internal/runtypes/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,9 @@ type DataSources interface {
collection
IsDataSources()
}

// Represents all provider's ephemeral resources pre-indexed by TypeOrRenamedEntityName.
type EphemeralResources interface {
collection
IsEphemeralResources()
}
90 changes: 90 additions & 0 deletions pkg/pf/internal/schemashim/ephemeral_resource_map.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright 2016-2022, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package schemashim

import (
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"

"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/internal/internalinter"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/pf/internal/runtypes"
shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
)

// Resource map needs to support Set (mutability) for RenameResourceWithAlias.
func newSchemaOnlyEphemeralResourceMap(resources runtypes.EphemeralResources) schemaOnlyEphemeralResourceMap {
m := schemaOnlyEphemeralResourceMap{Map: make(map[string]*schemaOnlyResource)}
for _, name := range resources.All() {
key := string(name)
v := resources.Schema(name)
m.Map[key] = newSchemaOnlyResource(v)
}
return m
}

type schemaOnlyEphemeralResourceMap struct {
internalinter.Internal
Map map[string]*schemaOnlyResource
}

var (
_ shim.ResourceMap = schemaOnlyEphemeralResourceMap{}
_ runtypes.EphemeralResources = schemaOnlyEphemeralResourceMap{}
)

func (m schemaOnlyEphemeralResourceMap) Len() int {
return len(m.Map)
}

func (m schemaOnlyEphemeralResourceMap) Get(key string) shim.Resource {
return m.Map[key]
}

func (m schemaOnlyEphemeralResourceMap) GetOk(key string) (shim.Resource, bool) {
v, ok := m.Map[key]
return v, ok
}

func (m schemaOnlyEphemeralResourceMap) Range(each func(key string, value shim.Resource) bool) {
for k, v := range m.Map {
if !each(k, v) {
return
}
}
}

func (m schemaOnlyEphemeralResourceMap) Set(key string, value shim.Resource) {
v, ok := value.(*schemaOnlyResource)
contract.Assertf(ok, "Set must be a %T, found a %T", v, value)
m.Map[key] = v
}

func (m schemaOnlyEphemeralResourceMap) All() []runtypes.TypeOrRenamedEntityName {
arr := make([]runtypes.TypeOrRenamedEntityName, 0, len(m.Map))
for k := range m.Map {
arr = append(arr, runtypes.TypeOrRenamedEntityName(k))
}
return arr
}

func (m schemaOnlyEphemeralResourceMap) Has(key runtypes.TypeOrRenamedEntityName) bool {
_, ok := m.Map[string(key)]
return ok
}

func (m schemaOnlyEphemeralResourceMap) Schema(key runtypes.TypeOrRenamedEntityName) runtypes.Schema {
return m.Map[string(key)].tf
}

func (m schemaOnlyEphemeralResourceMap) IsEphemeralResources() {}
17 changes: 13 additions & 4 deletions pkg/pf/internal/schemashim/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ import (
var _ = pf.ShimProvider(&SchemaOnlyProvider{})

type SchemaOnlyProvider struct {
ctx context.Context
tf pfprovider.Provider
resourceMap schemaOnlyResourceMap
dataSourceMap schemaOnlyDataSourceMap
ctx context.Context
tf pfprovider.Provider
resourceMap schemaOnlyResourceMap
dataSourceMap schemaOnlyDataSourceMap
ephemeralResourceMap schemaOnlyEphemeralResourceMap
internalinter.Internal
}

Expand All @@ -62,6 +63,10 @@ func (p *SchemaOnlyProvider) DataSources(ctx context.Context) (runtypes.DataSour
return p.dataSourceMap, nil
}

func (p *SchemaOnlyProvider) EphemeralResources(ctx context.Context) (runtypes.EphemeralResources, error) {
return p.ephemeralResourceMap, nil
}

func (p *SchemaOnlyProvider) Config(ctx context.Context) (tftypes.Object, error) {
schemaResponse := &pfprovider.SchemaResponse{}
p.tf.Schema(ctx, pfprovider.SchemaRequest{}, schemaResponse)
Expand Down Expand Up @@ -93,6 +98,10 @@ func (p *SchemaOnlyProvider) DataSourcesMap() shim.ResourceMap {
return p.dataSourceMap
}

func (p *SchemaOnlyProvider) EphemeralResourcesMap() shim.ResourceMap {
return p.ephemeralResourceMap
}

func (p *SchemaOnlyProvider) InternalValidate() error {
return nil
}
Expand Down
14 changes: 10 additions & 4 deletions pkg/pf/internal/schemashim/schemashim.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,18 @@ func ShimSchemaOnlyProvider(ctx context.Context, provider pfprovider.Provider) s
if err != nil {
panic(err)
}
ephemeralResources, err := pfutils.GatherEphemeralResources(ctx, provider, NewSchemaMap)
if err != nil {
panic(err)
}
resourceMap := newSchemaOnlyResourceMap(resources)
dataSourceMap := newSchemaOnlyDataSourceMap(dataSources)
ephemeralResourceMap := newSchemaOnlyEphemeralResourceMap(ephemeralResources)
return &SchemaOnlyProvider{
ctx: ctx,
tf: provider,
resourceMap: resourceMap,
dataSourceMap: dataSourceMap,
ctx: ctx,
tf: provider,
resourceMap: resourceMap,
dataSourceMap: dataSourceMap,
ephemeralResourceMap: ephemeralResourceMap,
}
}
9 changes: 9 additions & 0 deletions pkg/pf/proto/protov6.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,12 @@ func (p Provider) DataSourcesMap() shim.ResourceMap {
}
return resourceMap(v.DataSourceSchemas)
}

func (p Provider) EphemeralResourcesMap() shim.ResourceMap {
v, err := p.getSchema()
if err != nil {
tfbridge.GetLogger(p.ctx).Error(err.Error())
return nil
}
return resourceMap(v.EphemeralResourceSchemas)
}
14 changes: 14 additions & 0 deletions pkg/pf/proto/runtypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ func (p Provider) DataSources(context.Context) (runtypes.DataSources, error) {
return datasources{collection(v.DataSourceSchemas)}, nil
}

func (p Provider) EphemeralResources(context.Context) (runtypes.EphemeralResources, error) {
v, err := p.getSchema()
if err != nil {
return nil, err
}
return ephemeralResources{collection(v.EphemeralResourceSchemas)}, nil
}

type schema struct {
s *tfprotov6.Schema
tfName runtypes.TypeName
Expand Down Expand Up @@ -85,6 +93,12 @@ var _ runtypes.DataSources = datasources{}

func (datasources) IsDataSources() {}

var _ runtypes.EphemeralResources = ephemeralResources{}

type ephemeralResources struct{ collection }

func (ephemeralResources) IsEphemeralResources() {}

type collection map[string]*tfprotov6.Schema

func (c collection) All() []runtypes.TypeOrRenamedEntityName {
Expand Down
1 change: 1 addition & 0 deletions pkg/pf/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@ type ShimProvider interface {
Server(context.Context) (tfprotov6.ProviderServer, error)
Resources(context.Context) (runtypes.Resources, error)
DataSources(context.Context) (runtypes.DataSources, error)
EphemeralResources(context.Context) (runtypes.EphemeralResources, error)
Config(context.Context) (tftypes.Object, error)
}
Loading
Loading