2021-09-22 17:55:20 +00:00
|
|
|
// Copyright 2016-2021, Pulumi Corporation.
|
2020-09-30 20:41:52 +00:00
|
|
|
//
|
|
|
|
// 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 test
|
|
|
|
|
|
|
|
import (
|
2021-08-23 20:46:09 +00:00
|
|
|
"bytes"
|
2020-09-30 20:41:52 +00:00
|
|
|
"encoding/json"
|
2021-09-22 17:55:20 +00:00
|
|
|
"fmt"
|
2021-08-23 20:46:09 +00:00
|
|
|
"io"
|
2021-04-29 20:08:22 +00:00
|
|
|
"os"
|
2020-09-30 20:41:52 +00:00
|
|
|
"path/filepath"
|
2021-09-22 17:55:20 +00:00
|
|
|
"sort"
|
2020-09-30 20:41:52 +00:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
2021-07-06 22:40:53 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2021-07-13 23:41:40 +00:00
|
|
|
"gopkg.in/yaml.v3"
|
|
|
|
|
|
|
|
"github.com/pulumi/pulumi/pkg/v3/codegen/schema"
|
2022-10-21 23:13:44 +00:00
|
|
|
"github.com/pulumi/pulumi/pkg/v3/codegen/testing/utils"
|
2021-09-23 17:42:20 +00:00
|
|
|
"github.com/pulumi/pulumi/pkg/v3/testing/integration"
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/util/executable"
|
2020-09-30 20:41:52 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// GenPkgSignature corresponds to the shape of the codegen GeneratePackage functions.
|
|
|
|
type GenPkgSignature func(string, *schema.Package, map[string][]byte) (map[string][]byte, error)
|
|
|
|
|
|
|
|
// GeneratePackageFilesFromSchema loads a schema and generates files using the provided GeneratePackage function.
|
|
|
|
func GeneratePackageFilesFromSchema(schemaPath string, genPackageFunc GenPkgSignature) (map[string][]byte, error) {
|
|
|
|
// Read in, decode, and import the schema.
|
2023-01-06 22:39:16 +00:00
|
|
|
schemaBytes, err := os.ReadFile(schemaPath)
|
2020-09-30 20:41:52 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-07-13 23:41:40 +00:00
|
|
|
ext := filepath.Ext(schemaPath)
|
|
|
|
|
2020-09-30 20:41:52 +00:00
|
|
|
var pkgSpec schema.PackageSpec
|
2021-07-13 23:41:40 +00:00
|
|
|
if ext == ".yaml" || ext == ".yml" {
|
|
|
|
err = yaml.Unmarshal(schemaBytes, &pkgSpec)
|
|
|
|
} else {
|
|
|
|
err = json.Unmarshal(schemaBytes, &pkgSpec)
|
|
|
|
}
|
2020-09-30 20:41:52 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-10-21 23:13:44 +00:00
|
|
|
loader := schema.NewPluginLoader(utils.NewHost(testdataPath))
|
|
|
|
pkg, diags, err := schema.BindSpec(pkgSpec, loader)
|
2020-09-30 20:41:52 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2022-10-21 23:13:44 +00:00
|
|
|
} else if diags.HasErrors() {
|
|
|
|
return nil, diags
|
2020-09-30 20:41:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return genPackageFunc("test", pkg, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// LoadFiles loads the provided list of files from a directory.
|
2020-10-10 20:47:23 +00:00
|
|
|
func LoadFiles(dir, lang string, files []string) (map[string][]byte, error) {
|
2020-09-30 20:41:52 +00:00
|
|
|
result := map[string][]byte{}
|
|
|
|
for _, file := range files {
|
2023-01-06 22:39:16 +00:00
|
|
|
fileBytes, err := os.ReadFile(filepath.Join(dir, lang, file))
|
2020-09-30 20:41:52 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
result[file] = fileBytes
|
|
|
|
}
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
2021-09-22 17:55:20 +00:00
|
|
|
func PathExists(path string) (bool, error) {
|
|
|
|
_, err := os.Stat(path)
|
|
|
|
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// `LoadBaseline` loads the contents of the given baseline directory,
|
|
|
|
// by inspecting its `codegen-manifest.json`.
|
|
|
|
func LoadBaseline(dir, lang string) (map[string][]byte, error) {
|
|
|
|
cm := &codegenManifest{}
|
|
|
|
err := cm.load(filepath.Join(dir, lang))
|
2021-07-06 22:40:53 +00:00
|
|
|
if err != nil {
|
2021-09-22 17:55:20 +00:00
|
|
|
return nil, fmt.Errorf("Failed to load codegen-manifest.json: %w", err)
|
2021-07-06 22:40:53 +00:00
|
|
|
}
|
|
|
|
|
2021-09-22 17:55:20 +00:00
|
|
|
files := make(map[string][]byte)
|
2021-07-06 22:40:53 +00:00
|
|
|
|
2021-09-22 17:55:20 +00:00
|
|
|
for _, f := range cm.EmittedFiles {
|
2023-01-06 22:39:16 +00:00
|
|
|
bytes, err := os.ReadFile(filepath.Join(dir, lang, f))
|
2021-09-22 17:55:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("Failed to load file %s referenced in codegen-manifest.json: %w", f, err)
|
2021-07-06 22:40:53 +00:00
|
|
|
}
|
2021-09-22 17:55:20 +00:00
|
|
|
files[f] = bytes
|
2021-07-06 22:40:53 +00:00
|
|
|
}
|
|
|
|
|
2021-09-22 17:55:20 +00:00
|
|
|
return files, nil
|
2021-07-06 22:40:53 +00:00
|
|
|
}
|
|
|
|
|
2021-09-22 17:55:20 +00:00
|
|
|
type codegenManifest struct {
|
|
|
|
EmittedFiles []string `json:"emittedFiles"`
|
|
|
|
}
|
2021-07-06 22:40:53 +00:00
|
|
|
|
2021-09-22 17:55:20 +00:00
|
|
|
func (cm *codegenManifest) load(dir string) error {
|
2023-01-06 22:39:16 +00:00
|
|
|
bytes, err := os.ReadFile(filepath.Join(dir, "codegen-manifest.json"))
|
2021-09-22 17:55:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return json.Unmarshal(bytes, cm)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cm *codegenManifest) save(dir string) error {
|
|
|
|
sort.Strings(cm.EmittedFiles)
|
|
|
|
buf := &bytes.Buffer{}
|
|
|
|
enc := json.NewEncoder(buf)
|
2022-08-19 12:27:34 +00:00
|
|
|
enc.SetEscapeHTML(false)
|
2021-09-22 17:55:20 +00:00
|
|
|
enc.SetIndent("", " ")
|
|
|
|
err := enc.Encode(cm)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2021-07-06 22:40:53 +00:00
|
|
|
}
|
2021-09-22 17:55:20 +00:00
|
|
|
data := buf.Bytes()
|
2023-03-03 16:36:39 +00:00
|
|
|
return os.WriteFile(filepath.Join(dir, "codegen-manifest.json"), data, 0o600)
|
2021-07-06 22:40:53 +00:00
|
|
|
}
|
|
|
|
|
2020-09-30 20:41:52 +00:00
|
|
|
// ValidateFileEquality compares maps of files for equality.
|
2021-07-27 02:23:17 +00:00
|
|
|
func ValidateFileEquality(t *testing.T, actual, expected map[string][]byte) bool {
|
|
|
|
ok := true
|
2020-09-30 20:41:52 +00:00
|
|
|
for name, file := range expected {
|
2021-09-22 17:55:20 +00:00
|
|
|
_, inActual := actual[name]
|
|
|
|
if inActual {
|
|
|
|
if !assert.Equal(t, string(file), string(actual[name]), name) {
|
|
|
|
t.Logf("%s did not agree", name)
|
|
|
|
ok = false
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
t.Logf("File %s was expected but is missing from the actual fileset", name)
|
2021-07-27 02:23:17 +00:00
|
|
|
ok = false
|
|
|
|
}
|
2020-09-30 20:41:52 +00:00
|
|
|
}
|
2021-06-24 16:17:55 +00:00
|
|
|
for name := range actual {
|
2021-09-22 17:55:20 +00:00
|
|
|
if _, inExpected := expected[name]; !inExpected {
|
|
|
|
t.Logf("File %s from the actual fileset was not expected", name)
|
2021-07-27 02:23:17 +00:00
|
|
|
ok = false
|
2021-06-24 16:17:55 +00:00
|
|
|
}
|
|
|
|
}
|
2021-07-27 02:23:17 +00:00
|
|
|
return ok
|
2020-09-30 20:41:52 +00:00
|
|
|
}
|
2021-01-15 18:09:09 +00:00
|
|
|
|
2021-07-06 22:40:53 +00:00
|
|
|
// If PULUMI_ACCEPT is set, writes out actual output to the expected
|
2021-04-29 20:08:22 +00:00
|
|
|
// file set, so we can continue enjoying golden tests without manually
|
|
|
|
// modifying the expected output.
|
2021-07-06 22:40:53 +00:00
|
|
|
func RewriteFilesWhenPulumiAccept(t *testing.T, dir, lang string, actual map[string][]byte) bool {
|
|
|
|
if os.Getenv("PULUMI_ACCEPT") == "" {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2021-09-22 17:55:20 +00:00
|
|
|
cm := &codegenManifest{}
|
|
|
|
|
2021-07-06 22:40:53 +00:00
|
|
|
baseline := filepath.Join(dir, lang)
|
|
|
|
|
|
|
|
// Remove the baseline directory's current contents.
|
2021-09-22 17:55:20 +00:00
|
|
|
_, err := os.ReadDir(baseline)
|
2021-07-06 22:40:53 +00:00
|
|
|
switch {
|
|
|
|
case err == nil:
|
2021-09-22 17:55:20 +00:00
|
|
|
err = os.RemoveAll(baseline)
|
|
|
|
require.NoError(t, err)
|
2021-07-06 22:40:53 +00:00
|
|
|
case os.IsNotExist(err):
|
|
|
|
// OK
|
|
|
|
default:
|
|
|
|
require.NoError(t, err)
|
2021-04-29 20:08:22 +00:00
|
|
|
}
|
2021-07-06 22:40:53 +00:00
|
|
|
|
2021-09-22 17:55:20 +00:00
|
|
|
for file, bytes := range actual {
|
|
|
|
relPath := filepath.FromSlash(file)
|
|
|
|
path := filepath.Join(dir, lang, relPath)
|
|
|
|
cm.EmittedFiles = append(cm.EmittedFiles, relPath)
|
|
|
|
err := writeFileEnsuringDir(path, bytes)
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = cm.save(filepath.Join(dir, lang))
|
|
|
|
require.NoError(t, err)
|
2021-09-15 16:49:36 +00:00
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2021-09-22 17:55:20 +00:00
|
|
|
// Useful for populating code-generated destination
|
|
|
|
// `codeDir=$dir/$lang` with extra manually written files such as the
|
|
|
|
// unit test files. These files are copied from `$dir/$lang-extras`
|
|
|
|
// folder if present.
|
|
|
|
func CopyExtraFiles(t *testing.T, dir, lang string) {
|
|
|
|
codeDir := filepath.Join(dir, lang)
|
2023-12-12 12:19:42 +00:00
|
|
|
extrasDir := filepath.Join(dir, lang+"-extras")
|
2021-09-22 17:55:20 +00:00
|
|
|
gotExtras, err := PathExists(extrasDir)
|
2021-07-06 22:40:53 +00:00
|
|
|
|
2021-09-22 17:55:20 +00:00
|
|
|
if !gotExtras {
|
|
|
|
return
|
|
|
|
}
|
2021-07-06 22:40:53 +00:00
|
|
|
|
2021-09-22 17:55:20 +00:00
|
|
|
if err != nil {
|
2021-07-06 22:40:53 +00:00
|
|
|
require.NoError(t, err)
|
2021-09-22 17:55:20 +00:00
|
|
|
return
|
2021-07-06 22:40:53 +00:00
|
|
|
}
|
2021-09-22 17:55:20 +00:00
|
|
|
|
|
|
|
err = filepath.Walk(extrasDir, func(path string, info os.FileInfo, err error) error {
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if info.IsDir() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
relPath, err := filepath.Rel(extrasDir, path)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
destPath := filepath.Join(codeDir, relPath)
|
|
|
|
|
2023-01-06 22:39:16 +00:00
|
|
|
bytes, err := os.ReadFile(path)
|
2021-09-22 17:55:20 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
err = writeFileEnsuringDir(destPath, bytes)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
t.Logf("Copied %s to %s", path, destPath)
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func writeFileEnsuringDir(path string, bytes []byte) error {
|
2023-03-03 16:36:39 +00:00
|
|
|
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil && !os.IsExist(err) {
|
2021-09-22 17:55:20 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-03-03 16:36:39 +00:00
|
|
|
return os.WriteFile(path, bytes, 0o600)
|
2021-04-29 20:08:22 +00:00
|
|
|
}
|
|
|
|
|
2021-01-15 18:09:09 +00:00
|
|
|
// CheckAllFilesGenerated ensures that the set of expected and actual files generated
|
|
|
|
// are exactly equivalent.
|
|
|
|
func CheckAllFilesGenerated(t *testing.T, actual, expected map[string][]byte) {
|
|
|
|
seen := map[string]bool{}
|
|
|
|
for x := range expected {
|
|
|
|
seen[x] = true
|
|
|
|
}
|
|
|
|
for a := range actual {
|
|
|
|
assert.Contains(t, seen, a, "Unexpected file generated: %s", a)
|
|
|
|
if seen[a] {
|
|
|
|
delete(seen, a)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for s := range seen {
|
|
|
|
assert.Fail(t, "No content generated for expected file %s", s)
|
|
|
|
}
|
|
|
|
}
|
2021-08-23 20:46:09 +00:00
|
|
|
|
|
|
|
// Validates a transformer on a single file.
|
|
|
|
func ValidateFileTransformer(
|
|
|
|
t *testing.T,
|
|
|
|
inputFile string,
|
|
|
|
expectedOutputFile string,
|
2023-03-03 16:36:39 +00:00
|
|
|
transformer func(reader io.Reader, writer io.Writer) error,
|
|
|
|
) {
|
2021-08-23 20:46:09 +00:00
|
|
|
reader, err := os.Open(inputFile)
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
|
|
|
err = transformer(reader, &buf)
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
actualBytes := buf.Bytes()
|
|
|
|
|
|
|
|
if os.Getenv("PULUMI_ACCEPT") != "" {
|
2023-03-03 16:36:39 +00:00
|
|
|
err := os.WriteFile(expectedOutputFile, actualBytes, 0o600)
|
2021-08-23 20:46:09 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
actual := map[string][]byte{expectedOutputFile: actualBytes}
|
|
|
|
|
2023-01-06 22:39:16 +00:00
|
|
|
expectedBytes, err := os.ReadFile(expectedOutputFile)
|
2021-08-23 20:46:09 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
expected := map[string][]byte{expectedOutputFile: expectedBytes}
|
|
|
|
|
|
|
|
ValidateFileEquality(t, actual, expected)
|
|
|
|
}
|
2021-09-23 17:42:20 +00:00
|
|
|
|
|
|
|
func RunCommand(t *testing.T, name string, cwd string, exec string, args ...string) {
|
2021-10-07 19:39:19 +00:00
|
|
|
RunCommandWithOptions(t, &integration.ProgramTestOptions{}, name, cwd, exec, args...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func RunCommandWithOptions(
|
|
|
|
t *testing.T,
|
|
|
|
opts *integration.ProgramTestOptions,
|
2023-03-03 16:36:39 +00:00
|
|
|
name string, cwd string, exec string, args ...string,
|
|
|
|
) {
|
2021-09-23 17:42:20 +00:00
|
|
|
exec, err := executable.FindExecutable(exec)
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
t.FailNow()
|
|
|
|
}
|
|
|
|
wd, err := filepath.Abs(cwd)
|
|
|
|
require.NoError(t, err)
|
|
|
|
var stdout, stderr bytes.Buffer
|
2021-10-07 19:39:19 +00:00
|
|
|
opts.Stdout = &stdout
|
|
|
|
opts.Stderr = &stderr
|
|
|
|
opts.Verbose = true
|
2021-09-23 17:42:20 +00:00
|
|
|
err = integration.RunCommand(t,
|
|
|
|
name,
|
|
|
|
append([]string{exec}, args...),
|
|
|
|
wd,
|
2021-10-07 19:39:19 +00:00
|
|
|
opts)
|
2021-09-24 19:25:30 +00:00
|
|
|
if !assert.NoError(t, err) {
|
2021-09-23 17:42:20 +00:00
|
|
|
stdout := stdout.String()
|
|
|
|
stderr := stderr.String()
|
|
|
|
if len(stdout) > 0 {
|
|
|
|
t.Logf("stdout: %s", stdout)
|
|
|
|
}
|
|
|
|
if len(stderr) > 0 {
|
|
|
|
t.Logf("stderr: %s", stderr)
|
|
|
|
}
|
|
|
|
t.FailNow()
|
|
|
|
}
|
|
|
|
}
|
2021-09-29 18:33:57 +00:00
|
|
|
|
|
|
|
type SchemaVersion = string
|
|
|
|
|
2022-03-18 18:48:39 +00:00
|
|
|
// Schemas are downloaded in the makefile, and the versions specified here
|
|
|
|
// should be in sync with the makefile.
|
2021-09-29 18:33:57 +00:00
|
|
|
const (
|
2024-03-10 17:23:15 +00:00
|
|
|
AwsSchema SchemaVersion = "4.26.0"
|
|
|
|
AzureNativeSchema SchemaVersion = "1.29.0"
|
|
|
|
AzureSchema SchemaVersion = "4.18.0"
|
|
|
|
KubernetesSchema SchemaVersion = "3.7.2"
|
|
|
|
RandomSchema SchemaVersion = "4.11.2"
|
|
|
|
EksSchema SchemaVersion = "0.37.1"
|
|
|
|
AwsStaticWebsiteSchema SchemaVersion = "0.4.0"
|
2024-03-24 00:06:57 +00:00
|
|
|
AwsNativeSchema SchemaVersion = "0.99.0"
|
2021-09-29 18:33:57 +00:00
|
|
|
)
|
[program-gen] Emit Output-returning JSON serialization methods without rewriting applies (#15371)
### Description
A while ago we started implementing [specialized JSON serialization
methods](https://github.com/pulumi/pulumi/issues/12519) for Pulumi
programs which can accept nested outputs without having to rewrite and
combine applies.
- `Output.SerializeJson` in .NET
- `pulumi.jsonStringify` in nodejs
- `pulumi.Output.json_dumps` in Python
This PR extends program-gen for TypeScript, C# and Python to start
emitting these JSON serialization functions (when necessary). The PR
special-cases the `toJSON` PCL function when rewriting applies so that
nested outputs aren't rewritted.
Example PCL program and generated results:
> Also check out the downstream codegen tests to see improved generated
examples
```
resource vpc "aws:ec2:Vpc" {
cidrBlock = "10.100.0.0/16"
instanceTenancy = "default"
}
resource policy "aws:iam/policy:Policy" {
description = "test"
policy = toJSON({
"Version" = "2012-10-17"
"Interpolated" = "arn:${vpc.arn}:value"
"Value" = vpc.id
})
}
```
### Generated TypeScript Before
```typescript
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const vpc = new aws.ec2.Vpc("vpc", {
cidrBlock: "10.100.0.0/16",
instanceTenancy: "default",
});
const policy = new aws.iam.Policy("policy", {
description: "test",
policy: pulumi.all([vpc.arn, vpc.id]).apply(([arn, id]) => JSON.stringify({
Version: "2012-10-17",
Interpolated: `arn:${arn}:value`,
Value: id,
})),
});
```
### Generated TypeScript After
```typescript
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const vpc = new aws.ec2.Vpc("vpc", {
cidrBlock: "10.100.0.0/16",
instanceTenancy: "default",
});
const policy = new aws.iam.Policy("policy", {
description: "test",
policy: pulumi.jsonStringify({
Version: "2012-10-17",
Interpolated: pulumi.interpolate`arn:${vpc.arn}:value`,
Value: vpc.id,
}),
});
```
### Generated Python Before
```python
import pulumi
import json
import pulumi_aws as aws
vpc = aws.ec2.Vpc("vpc",
cidr_block="10.100.0.0/16",
instance_tenancy="default")
policy = aws.iam.Policy("policy",
description="test",
policy=pulumi.Output.all(vpc.arn, vpc.id).apply(lambda arn, id: json.dumps({
"Version": "2012-10-17",
"Interpolated": f"arn:{arn}:value",
"Value": id,
})))
```
### Generated Python After
```python
import pulumi
import json
import pulumi_aws as aws
vpc = aws.ec2.Vpc("vpc",
cidr_block="10.100.0.0/16",
instance_tenancy="default")
policy = aws.iam.Policy("policy",
description="test",
policy=pulumi.Output.json_dumps({
"Version": "2012-10-17",
"Interpolated": vpc.arn.apply(lambda arn: f"arn:{arn}:value"),
"Value": vpc.id,
}))
```
### Generated C# Before
```csharp
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var vpc = new Aws.Ec2.Vpc("vpc", new()
{
CidrBlock = "10.100.0.0/16",
InstanceTenancy = "default",
});
var policy = new Aws.Iam.Policy("policy", new()
{
Description = "test",
PolicyDocument = Output.Tuple(vpc.Arn, vpc.Id).Apply(values =>
{
var arn = values.Item1;
var id = values.Item2;
return JsonSerializer.Serialize(new Dictionary<string, object?>
{
["Version"] = "2012-10-17",
["Interpolated"] = $"arn:{arn}:value",
["Value"] = id,
});
}),
});
});
```
### Generated C# After
```csharp
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var vpc = new Aws.Ec2.Vpc("vpc", new()
{
CidrBlock = "10.100.0.0/16",
InstanceTenancy = "default",
});
var policy = new Aws.Iam.Policy("policy", new()
{
Description = "test",
PolicyDocument = Output.JsonSerialize(Output.Create(new Dictionary<string, object?>
{
["Version"] = "2012-10-17",
["Interpolated"] = vpc.Arn.Apply(arn => $"arn:{arn}:value"),
["Value"] = vpc.Id,
})),
});
});
```
## Checklist
- [ ] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [x] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [x] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2024-02-20 15:48:46 +00:00
|
|
|
|
|
|
|
// PulumiDotnetSDKVersion is the version of the Pulumi .NET SDK to use in program-gen tests
|
2024-08-21 16:19:35 +00:00
|
|
|
const PulumiDotnetSDKVersion = "3.66.2"
|