Skip to content

Commit

Permalink
Test invoke using new mapping interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
Frassle committed Dec 1, 2022
1 parent 52ef9a8 commit 2e6fdbe
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 7 deletions.
10 changes: 6 additions & 4 deletions pkg/tf2pulumi/convert/eject.go
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/spf13/afero"

"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tf2pulumi/il"
"github.com/pulumi/pulumi/pkg/v3/codegen/convert"
"github.com/pulumi/pulumi/pkg/v3/codegen/hcl2/syntax"
"github.com/pulumi/pulumi/pkg/v3/codegen/pcl"
"github.com/pulumi/pulumi/pkg/v3/codegen/schema"
Expand Down Expand Up @@ -82,14 +83,15 @@ func (o EjectOptions) logf(format string, arguments ...interface{}) {
}

// Eject converts a Terraform module at the provided location into a Pulumi module.
func Eject(dir string, loader schema.ReferenceLoader) (*workspace.Project, *pcl.Program, error) {
func Eject(dir string, loader schema.ReferenceLoader, mapper convert.Mapper) (*workspace.Project, *pcl.Program, error) {
if loader == nil {
panic("must provide a non-nil loader")
}

opts := EjectOptions{
Root: afero.NewBasePathFs(afero.NewOsFs(), dir),
Loader: loader,
Root: afero.NewBasePathFs(afero.NewOsFs(), dir),
Loader: loader,
ProviderInfoSource: il.NewMapperProviderInfoSource(mapper),
}

tfFiles, program, diags, err := internalEject(opts)
Expand All @@ -102,7 +104,7 @@ func Eject(dir string, loader schema.ReferenceLoader) (*workspace.Project, *pcl.
return nil, nil, err
}
}
if err != nil {
if err != nil || diags.HasErrors() {
return nil, nil, fmt.Errorf("failed to load Terraform configuration, %v", err)
}

Expand Down
23 changes: 21 additions & 2 deletions pkg/tf2pulumi/convert/eject_test.go
Expand Up @@ -75,6 +75,24 @@ func (l *testLoader) LoadPackageReference(pkg string, version *semver.Version) (
return schemaPackage.Reference(), nil
}

type testMapper struct {
path string
}

func (l *testMapper) GetMapping(provider string) ([]byte, error) {
mappingPath := filepath.Join(l.path, provider) + ".json"

mappingBytes, err := os.ReadFile(mappingPath)
if err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, err
}

return mappingBytes, nil
}

func TestEject(t *testing.T) {
// Test framework for eject
// Each folder in testdata has a pcl folder, we check that if we convert the hcl we get the expected pcl
Expand All @@ -89,7 +107,7 @@ func TestEject(t *testing.T) {
}, 0)
for _, info := range infos {
// Skip the "schemas" directory, that's for test schemas not for tests themselves
if info.IsDir() && info.Name() != "schemas" {
if info.IsDir() && info.Name() != "schemas" && info.Name() != "mappings" {
tests = append(tests, struct {
name string
path string
Expand All @@ -101,6 +119,7 @@ func TestEject(t *testing.T) {
}

loader := &testLoader{path: filepath.Join(testDir, "schemas")}
mapper := &testMapper{path: filepath.Join(testDir, "mappings")}

for _, tt := range tests {
tt := tt // avoid capturing loop variable in the closure
Expand All @@ -111,7 +130,7 @@ func TestEject(t *testing.T) {
hclPath := tt.path
pclPath := filepath.Join(tt.path, "pcl")

project, program, err := Eject(hclPath, loader)
project, program, err := Eject(hclPath, loader, mapper)
if !assert.NoError(t, err) {
return
}
Expand Down
38 changes: 38 additions & 0 deletions pkg/tf2pulumi/convert/testdata/mappings/simpledata.json
@@ -0,0 +1,38 @@
{
"name": "simpledata",
"provider": {
"dataSources": {
"simpledata_source": {
"input_one": {
"type": 4
},
"input_two": {
"type": 2
},
"result": {
"type": 4,
"computed": true
}
}
}
},
"dataSources": {
"simpledata_source": {
"tok": "simpledata::source",
"fields": {
"input_one": {
"name": "input_one",
"type": "string"
},
"input_two": {
"name": "input_two",
"type": "integer"
},
"result": {
"name": "result",
"type": "string"
}
}
}
}
}
27 changes: 27 additions & 0 deletions pkg/tf2pulumi/convert/testdata/schemas/simpledata.json
@@ -0,0 +1,27 @@
{
"version": "0.0.1",
"name": "simpledata",
"functions":{
"simpledata::source": {
"inputs": {
"type": "object",
"properties": {
"input_one": {
"type": "string"
},
"input_two": {
"type": "integer"
}
}
},
"outputs": {
"properties": {
"result": {
"type": "string"
}
},
"type": "object"
}
}
}
}
8 changes: 8 additions & 0 deletions pkg/tf2pulumi/convert/testdata/simple_invoke/main.tf
@@ -0,0 +1,8 @@
data "simpledata_source" "a_data_source" {
input_one = "hello"
input_two = true
}

output "some_output" {
value = data.simpledata_source.a_data_source.result
}
7 changes: 7 additions & 0 deletions pkg/tf2pulumi/convert/testdata/simple_invoke/pcl/main.pp
@@ -0,0 +1,7 @@
aDataSource = invoke("simpledata::source", {
input_one = "hello",
input_two = true
})
output someOutput {
value = aDataSource.result
}
33 changes: 33 additions & 0 deletions pkg/tf2pulumi/il/plugin_info.go
Expand Up @@ -15,6 +15,7 @@
package il

import (
"encoding/json"
"fmt"
"net/http"
"net/url"
Expand All @@ -23,6 +24,7 @@ import (

jsoniter "github.com/json-iterator/go"
"github.com/pkg/errors"
"github.com/pulumi/pulumi/pkg/v3/codegen/convert"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
"github.com/pulumi/pulumi/sdk/v3/go/common/workspace"

Expand All @@ -36,6 +38,37 @@ type ProviderInfoSource interface {
GetProviderInfo(registry, namespace, name, version string) (*tfbridge.ProviderInfo, error)
}

// mapperProviderInfoSource wraps a convert.Mapper to return tfbridge.ProviderInfo
type mapperProviderInfoSource struct {
mapper convert.Mapper
}

func NewMapperProviderInfoSource(mapper convert.Mapper) ProviderInfoSource {
return &mapperProviderInfoSource{mapper: mapper}
}

func (mapper *mapperProviderInfoSource) GetProviderInfo(
registryName, namespace, name, version string) (*tfbridge.ProviderInfo, error) {

data, err := mapper.mapper.GetMapping(name)
if err != nil {
return nil, err
}
// Might be nil or []
if len(data) == 0 {
message := fmt.Sprintf("could not find mapping information for provider %s", name)
message += "; try installing a pulumi plugin that supports this terraform provider"
return nil, fmt.Errorf(message)
}

var info *tfbridge.MarshallableProviderInfo
err = json.Unmarshal(data, &info)
if err != nil {
return nil, fmt.Errorf("could not decode schema information for provider %s: %w", name, err)
}
return info.Unmarshal(), nil
}

// CachingProviderInfoSource wraps a ProviderInfoSource in a cache for faster access.
type CachingProviderInfoSource struct {
m sync.RWMutex
Expand Down
2 changes: 1 addition & 1 deletion pkg/tfbridge/info.go
Expand Up @@ -397,7 +397,7 @@ type PreConfigureCallbackWithLogger func(
) error

// The types below are marshallable versions of the schema descriptions associated with a provider. These are used when
// marshalling a provider info as JSON; Note that these types only represent a subset of the informatino associated
// marshalling a provider info as JSON; Note that these types only represent a subset of the information associated
// with a ProviderInfo; thus, a ProviderInfo cannot be round-tripped through JSON.

// MarshallableSchema is the JSON-marshallable form of a Terraform schema.
Expand Down

0 comments on commit 2e6fdbe

Please sign in to comment.