Skip to content

Commit

Permalink
Fix azure loader issues (#1682)
Browse files Browse the repository at this point in the history
Fixes #1681

For providers such as Azure Classic that have a discrepancy between
"azure" and "azurerm", PULUMI_CONVERT=1 conversion no longer attempts to
resolve and download the "azurerm" plugin from GitHub.
  • Loading branch information
t0yv0 authored Feb 9, 2024
1 parent 85f5520 commit 7eef4a3
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 12 deletions.
14 changes: 12 additions & 2 deletions pkg/tfgen/convert_cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
hcl2nodejs "github.com/pulumi/pulumi/pkg/v3/codegen/nodejs"
"github.com/pulumi/pulumi/pkg/v3/codegen/pcl"
hcl2python "github.com/pulumi/pulumi/pkg/v3/codegen/python"
"github.com/pulumi/pulumi/pkg/v3/codegen/schema"
pschema "github.com/pulumi/pulumi/pkg/v3/codegen/schema"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource/plugin"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/cmdutil"
Expand Down Expand Up @@ -76,6 +77,8 @@ type cliConverter struct {
) string
}

loader schema.Loader

convertExamplesList []struct {
docs string
path examplePath
Expand Down Expand Up @@ -107,6 +110,12 @@ func (g *Generator) cliConverter() *cliConverter {
pluginHost: g.pluginHost,
pcls: map[string]translatedExample{},
}
if g.pluginHost != nil {
l := newLoader(g.pluginHost)
// Ensure azurerm resolves to azure for example:
l.aliasPackage(g.info.Name, string(g.pkg))
g.cliConverterState.loader = l
}
return g.cliConverterState
}

Expand Down Expand Up @@ -389,8 +398,9 @@ func (cc *cliConverter) convertPCL(
opts = append(opts, pcl.SkipResourceTypechecking)
if cc.pluginHost != nil {
opts = append(opts, pcl.PluginHost(cc.pluginHost))
loader := newLoader(cc.pluginHost)
opts = append(opts, pcl.Loader(loader))
}
if cc.loader != nil {
opts = append(opts, pcl.Loader(cc.loader))
}
if cc.packageCache != nil {
opts = append(opts, pcl.Cache(cc.packageCache))
Expand Down
131 changes: 125 additions & 6 deletions pkg/tfgen/convert_cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,34 @@
package tfgen

import (
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"
"runtime"
"strings"
"testing"

"encoding/json"

"github.com/blang/semver"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hexops/autogold/v2"
"github.com/spf13/afero"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
bridgetesting "github.com/pulumi/pulumi-terraform-bridge/v3/internal/testing"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
sdkv2 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/sdk-v2"
pschema "github.com/pulumi/pulumi/pkg/v3/codegen/schema"
"github.com/pulumi/pulumi/sdk/v3/go/common/diag"
"github.com/pulumi/pulumi/sdk/v3/go/common/diag/colors"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource/plugin"
"github.com/pulumi/pulumi/sdk/v3/go/common/tokens"
"github.com/pulumi/pulumi/sdk/v3/go/common/workspace"

bridgetesting "github.com/pulumi/pulumi-terraform-bridge/v3/internal/testing"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
sdkv2 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/sdk-v2"
shimv2 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/sdk-v2"
)

func TestConvertViaPulumiCLI(t *testing.T) {
Expand Down Expand Up @@ -164,6 +171,7 @@ output "someOutput" {
Package: info.Name,
Version: info.Version,
Language: Schema,
PluginHost: &testPluginHost{},
ProviderInfo: info,
Root: fs,
Sink: diag.DefaultSink(io.Discard, io.Discard, diag.FormatOptions{
Expand Down Expand Up @@ -213,4 +221,115 @@ Converted 100.00% of yaml examples (1/1)
withPrefix := tfbridge.ProviderInfo{Name: "p", ResourcePrefix: "prov"}
assert.Equal(t, filepath.Join(".", "prov.json"), c.mappingsFile(".", withPrefix))
})

// Taken from https://github.com/pulumi/pulumi-azure/issues/1698
//
// Emulate a case where pulumi name does not match the TF provider prefix, and one of the
// examples is referencing an unknown resource.
//
// Before the fix this would panic reaching out to PluginHost.ResolvePlugin.
t.Run("unknownResource", func(t *testing.T) {
md := []byte(strings.ReplaceAll(`
# azurerm_web_pubsub_custom_certificate
Manages an Azure Web PubSub Custom Certificate.
## Example Usage
%%%hcl
resource "azurerm_web_pubsub_service" "example" {
name = "example-webpubsub"
}
resource "azurerm_web_pubsub_custom_certificate" "test" {
name = "example-cert"
}
%%%`, "%%%", "```"))
p := &schema.Provider{
ResourcesMap: map[string]*schema.Resource{
"azurerm_web_pubsub_custom_certificate": {
Schema: map[string]*schema.Schema{"name": {
Type: schema.TypeString,
Optional: true,
}},
},
},
}
pi := tfbridge.ProviderInfo{
P: shimv2.NewProvider(p),
Name: "azurerm",
Version: "0.0.1",
Resources: map[string]*tfbridge.ResourceInfo{
"azurerm_web_pubsub_custom_certificate": {
Tok: "azure:webpubsub/customCertificate:CustomCertificate",
Docs: &tfbridge.DocInfo{Markdown: md},
},
},
}
g, err := NewGenerator(GeneratorOptions{
Package: "azure",
Version: "0.0.1",
PluginHost: &testPluginHost{},
Language: Schema,
ProviderInfo: pi,
Root: afero.NewBasePathFs(afero.NewOsFs(), t.TempDir()),
Sink: diag.DefaultSink(io.Discard, io.Discard, diag.FormatOptions{
Color: colors.Never,
}),
})
require.NoError(t, err)

err = g.Generate()
require.NoError(t, err)
})
}

type testPluginHost struct{}

func (*testPluginHost) ServerAddr() string { panic("Unexpected call") }

func (*testPluginHost) Log(diag.Severity, resource.URN, string, int32) {
panic("Unexpected call")
}

func (*testPluginHost) LogStatus(diag.Severity, resource.URN, string, int32) {
panic("Unexpected call")
}

func (*testPluginHost) Analyzer(tokens.QName) (plugin.Analyzer, error) { panic("Unexpected call") }

func (*testPluginHost) PolicyAnalyzer(
tokens.QName, string, *plugin.PolicyAnalyzerOptions,
) (plugin.Analyzer, error) {
panic("Unexpected call")
}

func (*testPluginHost) ListAnalyzers() []plugin.Analyzer { panic("Unexpected call") }

func (*testPluginHost) Provider(tokens.Package, *semver.Version) (plugin.Provider, error) {
panic("Unexpected call")
}

func (*testPluginHost) CloseProvider(plugin.Provider) error { panic("Unexpected call") }

func (*testPluginHost) LanguageRuntime(string, plugin.ProgramInfo) (plugin.LanguageRuntime, error) {
panic("Unexpected call")
}

func (*testPluginHost) EnsurePlugins([]workspace.PluginSpec, plugin.Flags) error {
panic("Unexpected call")
}

func (*testPluginHost) ResolvePlugin(
workspace.PluginKind, string, *semver.Version,
) (*workspace.PluginInfo, error) {
panic("Unexpected call")
}

func (*testPluginHost) GetProjectPlugins() []workspace.ProjectPlugin { panic("Unexpected call") }
func (*testPluginHost) SignalCancellation() error { panic("Unexpected call") }
func (*testPluginHost) Close() error { return nil }

var _ plugin.Host = (*testPluginHost)(nil)
1 change: 0 additions & 1 deletion pkg/tfgen/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -871,7 +871,6 @@ type GenerateOptions struct {

// Generate creates Pulumi packages from the information it was initialized with.
func (g *Generator) Generate() error {

// First gather up the entire package contents. This structure is complete and sufficient to hand off to the
// language-specific generators to create the full output.
pack, err := g.gatherPackage()
Expand Down
17 changes: 14 additions & 3 deletions pkg/tfgen/loaders.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,30 @@ package tfgen

import (
"github.com/blang/semver"

"github.com/pulumi/pulumi/pkg/v3/codegen/schema"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource/plugin"
)

type loader struct {
innerLoader schema.Loader
emptyPackages map[string]bool
innerLoader schema.Loader
emptyPackages map[string]bool
aliasedPackages map[string]string
}

var _ schema.Loader = &loader{}

func (l *loader) aliasPackage(alias string, canonicalName string) {
if l.aliasedPackages == nil {
l.aliasedPackages = map[string]string{}
}
l.aliasedPackages[alias] = canonicalName
}

func (l *loader) LoadPackage(name string, ver *semver.Version) (*schema.Package, error) {
if renamed, ok := l.aliasedPackages[name]; ok {
name = renamed
}

if l.emptyPackages[name] {
return &schema.Package{
Name: name,
Expand Down

0 comments on commit 7eef4a3

Please sign in to comment.