Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fraser/paramprovider #16152

Draft
wants to merge 33 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
57d8f6a
Add paramaterized providers
Frassle Nov 6, 2023
7d284e7
Add to PackageSpec
Frassle Nov 7, 2023
c24d640
Fix PackageSpec
Frassle Nov 7, 2023
de5ace4
Fix marshaling
Frassle Nov 7, 2023
f703b7c
Bind extensions
Frassle Nov 7, 2023
1cd9ffe
Start binding node
Frassle Nov 7, 2023
a048557
Bind parameter
Frassle Nov 7, 2023
856d2c9
Progress on codegen
Frassle Nov 7, 2023
b9c9b3a
Add Map
Frassle Nov 7, 2023
94aaf94
NodeJS codegen
Frassle Nov 7, 2023
f174d73
Don't emit plugin json
Frassle Nov 7, 2023
2e28ce8
Fix package
Frassle Nov 8, 2023
47bbf1c
Remove pulumi entry fully
Frassle Nov 8, 2023
cedc218
Rebuild parameter interface
Frassle Nov 8, 2023
3bf2b41
Validate keys
Frassle Nov 8, 2023
c1f1286
Send base package, parmater key is in type token
Frassle Nov 8, 2023
b980edd
Fix tests
Frassle Nov 8, 2023
04e2cdc
Plumbing in version
Frassle Nov 8, 2023
b64ee11
Plumbing in version
Frassle Nov 8, 2023
05deb1f
Fix bind
Frassle Nov 8, 2023
c18ad28
split param and ext
Frassle Nov 8, 2023
6c2836f
Fix schema get
Frassle Nov 8, 2023
f8804f4
Fixing version
Frassle Nov 8, 2023
f3c57ab
Fixing version
Frassle Nov 8, 2023
54a3b9c
fixing versions
Frassle Nov 8, 2023
6ca11cf
Nicer param in OptsDefaults
Frassle Nov 8, 2023
a13e58e
Move paramater into extension
Frassle Nov 8, 2023
7212060
Start moving into extension block
Frassle Nov 9, 2023
5a9123f
Finish moving into ext
Frassle Nov 9, 2023
2729610
Plumb into nodejs SDK
Frassle Nov 9, 2023
9299e26
Fix nodejs protobufs
Frassle Nov 10, 2023
4445ab8
Merge remote-tracking branch 'origin/master' into paramprovider
Frassle Nov 27, 2023
c81ecf8
Merge remote-tracking branch 'origin/master' into paramprovider
Frassle May 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/backend/display/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func stateForJSONOutput(s *resource.State, opts Options) *resource.State {
return resource.NewState(s.Type, s.URN, s.Custom, s.Delete, s.ID, inputs,
outputs, s.Parent, s.Protect, s.External, s.Dependencies, s.InitErrors, s.Provider,
s.PropertyDependencies, s.PendingReplacement, s.AdditionalSecretOutputs, s.Aliases, &s.CustomTimeouts,
s.ImportID, s.RetainOnDelete, s.DeletedWith, s.Created, s.Modified, s.SourcePosition)
s.ImportID, s.RetainOnDelete, s.DeletedWith, s.Created, s.Modified, s.SourcePosition, s.Parameter)
}

// ShowJSONEvents renders incremental engine events to stdout.
Expand Down
71 changes: 46 additions & 25 deletions pkg/cmd/pulumi/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ Subcommands of this command are useful to package authors during development.`,
// optional version:
//
// FILE.[json|y[a]ml] | PLUGIN[@VERSION] | PATH_TO_PLUGIN
func schemaFromSchemaSource(packageSource string) (*schema.Package, error) {
func schemaFromSchemaSource(packageSource string, args []string) (*schema.Package, error) {
var spec schema.PackageSpec
bind := func(spec schema.PackageSpec) (*schema.Package, error) {
pkg, diags, err := schema.BindSpec(spec, nil)
Expand All @@ -76,6 +76,9 @@ func schemaFromSchemaSource(packageSource string) (*schema.Package, error) {
return pkg, nil
}
if ext := filepath.Ext(packageSource); ext == ".yaml" || ext == ".yml" {
if len(args) > 0 {
return nil, errors.New("cannot specify parameters for a YAML schema")
}
f, err := os.ReadFile(packageSource)
if err != nil {
return nil, err
Expand All @@ -86,6 +89,9 @@ func schemaFromSchemaSource(packageSource string) (*schema.Package, error) {
}
return bind(spec)
} else if ext == ".json" {
if len(args) > 0 {
return nil, errors.New("cannot specify parameters for a JSON schema")
}
f, err := os.ReadFile(packageSource)
if err != nil {
return nil, err
Expand All @@ -97,12 +103,18 @@ func schemaFromSchemaSource(packageSource string) (*schema.Package, error) {
return bind(spec)
}

p, err := providerFromSource(packageSource)
p, err := providerFromSource(packageSource, args)
if err != nil {
return nil, err
}
defer p.Close()
bytes, err := p.GetSchema(0)

var bytes []byte
if len(args) > 0 {
bytes, err = p.GetSchema(1, args[0])
} else {
bytes, err = p.GetSchema(0, "")
}
if err != nil {
return nil, err
}
Expand All @@ -116,7 +128,7 @@ func schemaFromSchemaSource(packageSource string) (*schema.Package, error) {
// providerFromSource takes a plugin name or path.
//
// PLUGIN[@VERSION] | PATH_TO_PLUGIN
func providerFromSource(packageSource string) (plugin.Provider, error) {
func providerFromSource(packageSource string, args []string) (plugin.Provider, error) {
wd, err := os.Getwd()
if err != nil {
return nil, err
Expand Down Expand Up @@ -148,13 +160,14 @@ func providerFromSource(packageSource string) (plugin.Provider, error) {

// No file separators, so we try to look up the schema
// On unix, these checks are identical. On windows, filepath.Separator is '\\'
var provider plugin.Provider
if !strings.ContainsRune(pkg, filepath.Separator) && !strings.ContainsRune(pkg, '/') {
host, err := plugin.NewDefaultHost(pCtx, nil, false, nil, nil)
if err != nil {
return nil, err
}
// We assume this was a plugin and not a path, so load the plugin.
provider, err := host.Provider(tokens.Package(pkg), version)
provider, err = host.Provider(tokens.Package(pkg), version)
if err != nil {
// There is an executable with the same name, so suggest that
if info, statErr := os.Stat(pkg); statErr == nil && isExecutable(info) {
Expand Down Expand Up @@ -192,30 +205,38 @@ func providerFromSource(packageSource string) (plugin.Provider, error) {
}
return nil, err
}
return provider, nil
}
} else {

// We were given a path to a binary, so invoke that.
info, err := os.Stat(pkg)
if os.IsNotExist(err) {
return nil, fmt.Errorf("could not find file %s", pkg)
} else if err != nil {
return nil, err
} else if !isExecutable(info) {
if p, err := filepath.Abs(pkg); err == nil {
pkg = p
// We were given a path to a binary, so invoke that.
info, err := os.Stat(pkg)
if os.IsNotExist(err) {
return nil, fmt.Errorf("could not find file %s", pkg)
} else if err != nil {
return nil, err
} else if !info.IsDir() && !isExecutable(info) {
if p, err := filepath.Abs(pkg); err == nil {
pkg = p
}
return nil, fmt.Errorf("plugin at path %q not executable", pkg)
}
return nil, fmt.Errorf("plugin at path %q not executable", pkg)
}

host, err := plugin.NewDefaultHost(pCtx, nil, false, nil, nil)
if err != nil {
return nil, err
host, err := plugin.NewDefaultHost(pCtx, nil, false, nil, nil)
if err != nil {
return nil, err
}

provider, err = plugin.NewProviderFromPath(host, pCtx, pkg)
if err != nil {
return nil, err
}
}

p, err := plugin.NewProviderFromPath(host, pCtx, pkg)
if err != nil {
return nil, err
// If we have args call parameterize
if len(args) > 0 {
err := provider.Parameterize(tokens.Package(args[0]), args[1:], nil, nil)
if err != nil {
return nil, fmt.Errorf("parameterize provider: %w", err)
}
}
return p, nil
return provider, nil
}
13 changes: 6 additions & 7 deletions pkg/cmd/pulumi/package_extract_mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,20 @@ import (

func newExtractMappingCommand() *cobra.Command {
var out string
var provider string

cmd := &cobra.Command{
Use: "get-mapping <key> <schema_source> [<provider key>]",
Args: cobra.RangeArgs(2, 3),
Use: "get-mapping <key> <schema_source>",
Args: cobra.MinimumNArgs(2),
Short: "Get the mapping information for a given key from a package",
Long: `Get the mapping information for a given key from a package.

<schema_source> can be a package name or the path to a plugin binary.`,
Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error {
key := args[0]
source := args[1]
var provider string
if len(args) > 2 {
provider = args[2]
}

p, err := providerFromSource(source)
p, err := providerFromSource(source, args[2:])
if err != nil {
return fmt.Errorf("load provider: %w", err)
}
Expand Down Expand Up @@ -70,5 +67,7 @@ func newExtractMappingCommand() *cobra.Command {
cmd.Flags().StringVarP(&out, "out", "o", "", "The file to write the mapping data to")
contract.AssertNoErrorf(cmd.MarkFlagRequired("out"), `Could not mark "out" as required`)

cmd.Flags().StringVarP(&provider, "key", "", "", "The provider key to request for mapping")

return cmd
}
4 changes: 2 additions & 2 deletions pkg/cmd/pulumi/package_extract_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ import (
func newExtractSchemaCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "get-schema <schema_source>",
Args: cobra.ExactArgs(1),
Args: cobra.MinimumNArgs(1),
Short: "Get the schema.json from a package",
Long: `Get the schema.json from a package.

<schema_source> can be a package name or the path to a plugin binary.`,
Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error {
source := args[0]

pkg, err := schemaFromSchemaSource(source)
pkg, err := schemaFromSchemaSource(source, args[1:])
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/cmd/pulumi/package_gen_sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func newGenSdkCommand() *cobra.Command {
var version string
cmd := &cobra.Command{
Use: "gen-sdk <schema_source>",
Args: cobra.ExactArgs(1),
Args: cobra.MinimumNArgs(1),
Short: "Generate SDK(s) from a package or schema",
Long: `Generate SDK(s) from a package or schema.

Expand All @@ -50,7 +50,7 @@ func newGenSdkCommand() *cobra.Command {
source := args[0]

d := diag.DefaultSink(os.Stdout, os.Stderr, diag.FormatOptions{Color: cmdutil.GetGlobalColorization()})
pkg, err := schemaFromSchemaSource(source)
pkg, err := schemaFromSchemaSource(source, args[1:])
if err != nil {
return err
}
Expand Down
86 changes: 65 additions & 21 deletions pkg/codegen/nodejs/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -2265,7 +2265,8 @@ func (mod *modContext) genResourceModule(w io.Writer) {
fmt.Fprintf(w, " },\n")
fmt.Fprintf(w, "};\n")
for _, name := range registrations.SortedValues() {
fmt.Fprintf(w, "pulumi.runtime.registerResourceModule(\"%v\", \"%v\", _module)\n", mod.pkg.Name(), name)
pkgName := mod.pkg.PackageName()
fmt.Fprintf(w, "pulumi.runtime.registerResourceModule(\"%v\", \"%v\", _module)\n", pkgName, name)
}
}

Expand Down Expand Up @@ -2362,19 +2363,19 @@ func genPackageMetadata(pkg *schema.Package, info NodePackageInfo, fs codegen.Fs
}

type npmPackage struct {
Name string `json:"name"`
Version string `json:"version"`
Description string `json:"description,omitempty"`
Keywords []string `json:"keywords,omitempty"`
Homepage string `json:"homepage,omitempty"`
Repository string `json:"repository,omitempty"`
License string `json:"license,omitempty"`
Scripts map[string]string `json:"scripts,omitempty"`
Dependencies map[string]string `json:"dependencies,omitempty"`
DevDependencies map[string]string `json:"devDependencies,omitempty"`
PeerDependencies map[string]string `json:"peerDependencies,omitempty"`
Resolutions map[string]string `json:"resolutions,omitempty"`
Pulumi plugin.PulumiPluginJSON `json:"pulumi,omitempty"`
Name string `json:"name"`
Version string `json:"version"`
Description string `json:"description,omitempty"`
Keywords []string `json:"keywords,omitempty"`
Homepage string `json:"homepage,omitempty"`
Repository string `json:"repository,omitempty"`
License string `json:"license,omitempty"`
Scripts map[string]string `json:"scripts,omitempty"`
Dependencies map[string]string `json:"dependencies,omitempty"`
DevDependencies map[string]string `json:"devDependencies,omitempty"`
PeerDependencies map[string]string `json:"peerDependencies,omitempty"`
Resolutions map[string]string `json:"resolutions,omitempty"`
Pulumi *plugin.PulumiPluginJSON `json:"pulumi,omitempty"`
}

func genNPMPackageMetadata(pkg *schema.Package, info NodePackageInfo, localDependencies map[string]string) (string, error) {
Expand Down Expand Up @@ -2405,6 +2406,18 @@ func genNPMPackageMetadata(pkg *schema.Package, info NodePackageInfo, localDepen
version = pluginVersion
}

// If this is an extension library than it is _not_ a plugin library itself, it will depend on the library that
// documents the plugin version.
var pulumiJSON *plugin.PulumiPluginJSON
if pkg.Extension == nil {
pulumiJSON = &plugin.PulumiPluginJSON{
Resource: true,
Server: pkg.PluginDownloadURL,
Name: pkg.Name,
Version: pluginVersion,
}
}

// Create info that will get serialized into an NPM package.json.
npminfo := npmPackage{
Name: packageName,
Expand All @@ -2418,12 +2431,7 @@ func genNPMPackageMetadata(pkg *schema.Package, info NodePackageInfo, localDepen
"build": "tsc",
},
DevDependencies: devDependencies,
Pulumi: plugin.PulumiPluginJSON{
Resource: true,
Server: pkg.PluginDownloadURL,
Name: pkg.Name,
Version: pluginVersion,
},
Pulumi: pulumiJSON,
}

// Copy the overlay dependencies, if any.
Expand All @@ -2437,6 +2445,19 @@ func genNPMPackageMetadata(pkg *schema.Package, info NodePackageInfo, localDepen
npminfo.Dependencies[depk] = depv
}
}
// Add the extension dependency, if any.
if pkg.Extension != nil {
var version string
if pkg.Extension.Version != nil {
version = pkg.Extension.Version.String()
}
if npminfo.Dependencies == nil {
npminfo.Dependencies = make(map[string]string)
}
// TODO: Hardcoded assumption that extensions are pulumi packages.
npminfo.Dependencies["@pulumi/"+pkg.Extension.Name] = version
}

for depk, depv := range info.DevDependencies {
if npminfo.DevDependencies == nil {
npminfo.DevDependencies = make(map[string]string)
Expand Down Expand Up @@ -2600,7 +2621,9 @@ func generateModuleContextMap(tool string, pkg *schema.Package, extraFiles map[s
}
}

scanResource(pkg.Provider)
if pkg.Provider != nil {
scanResource(pkg.Provider)
}
for _, r := range pkg.Resources {
scanResource(r)
}
Expand Down Expand Up @@ -2786,6 +2809,27 @@ func (mod *modContext) genUtilitiesFile(w io.Writer) error {
} else {
code = strings.ReplaceAll(code, "/*pluginDownloadURL*/", "")
}
var parameter, extension string
if def.Extension != nil {
if def.Extension.Parameter != nil {
json, err := json.Marshal(def.Extension.Parameter)
if err != nil {
return fmt.Errorf("marshal parameter: %w", err)
}
// It's an extension if it doesn't have it's own provider
isExtension := "false"
if def.Provider == nil {
isExtension = "true"
}
parameter = fmt.Sprintf(",\n parameterValue: %s,\n parameterExtension: %s", json, isExtension)
}
extension = fmt.Sprintf(", extensionPackage: %q", def.Extension.Name)
if def.Extension.Version != nil {
extension = fmt.Sprintf("%s , extensionVersion: %q", extension, def.Extension.Version.String())
}
}
code = strings.ReplaceAll(code, "/*parameter*/", parameter)
code = strings.ReplaceAll(code, "/*extension*/", extension)

_, err = fmt.Fprintf(w, "%s", code)
return err
Expand Down
2 changes: 1 addition & 1 deletion pkg/codegen/nodejs/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export function getVersion(): string {

/** @internal */
export function resourceOptsDefaults(): any {
return { version: getVersion()/*pluginDownloadURL*/ };
return { version: getVersion()/*pluginDownloadURL*//*parameter*//*extension*/ };
}

/** @internal */
Expand Down