diff --git a/CHANGELOG.md b/CHANGELOG.md index d9a46c25bc..3577fd5633 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## HEAD (Unreleased) +### Improvements + +- Add YAML support to Go SDK. (https://github.com/pulumi/pulumi-kubernetes/pull/1093). + ### Bug Fixes - fix(customresources): use a 3-way merge patch instead of strategic merge. (https://github.com/pulumi/pulumi-kubernetes/pull/1095) diff --git a/provider/cmd/pulumi-gen-kubernetes/main.go b/provider/cmd/pulumi-gen-kubernetes/main.go index 7c54891c20..9cce689b5a 100644 --- a/provider/cmd/pulumi-gen-kubernetes/main.go +++ b/provider/cmd/pulumi-gen-kubernetes/main.go @@ -15,21 +15,25 @@ package main import ( + "bytes" "encoding/json" "fmt" + "go/format" "io/ioutil" "log" "os" "path" "path/filepath" + "sort" + "text/template" "github.com/pkg/errors" + "github.com/pulumi/pulumi-kubernetes/provider/v2/pkg/gen" + "github.com/pulumi/pulumi/pkg/v2/codegen" gogen "github.com/pulumi/pulumi/pkg/v2/codegen/go" "github.com/pulumi/pulumi/pkg/v2/codegen/schema" "github.com/pulumi/pulumi/sdk/v2/go/common/tools" "github.com/pulumi/pulumi/sdk/v2/go/common/util/contract" - - "github.com/pulumi/pulumi-kubernetes/provider/v2/pkg/gen" ) // This is the URL for the v1.17.0 swagger spec. This is the last version of the spec containing the following @@ -79,7 +83,7 @@ func main() { case "dotnet": writeDotnetClient(data, outdir, templateDir) case "go": - writeGoClient(data, outdir) + writeGoClient(data, outdir, templateDir) case "schema": if err := writePulumiSchema(data, outdir); err != nil { panic(err) @@ -322,12 +326,41 @@ func writeDotnetClient(data map[string]interface{}, outdir, templateDir string) } } -func writeGoClient(data map[string]interface{}, outdir string) { +func writeGoClient(data map[string]interface{}, outdir string, templateDir string) { pkg := genPulumiSchemaPackage(data) files, err := gogen.GeneratePackage("pulumigen", pkg) if err != nil { panic(err) } + + resources, err := gogen.LanguageResources("pulumigen", pkg) + if err != nil { + panic(err) + } + + templateResources := gen.TemplateResources{} + imports := codegen.StringSet{} + for _, resource := range resources { + r := gen.TemplateResource{ + Alias: resource.Alias, + Name: resource.Name, + Package: resource.Package, + Token: resource.Token, + } + templateResources.Resources = append(templateResources.Resources, r) + importPath := fmt.Sprintf(`%s "%s"`, resource.Alias, resource.Package) + imports.Add(importPath) + } + templateResources.Imports = imports.SortedValues() + sort.Slice(templateResources.Resources, func(i, j int) bool { + return templateResources.Resources[i].Token < templateResources.Resources[j].Token + }) + + files["kubernetes/yaml/configFile.go"] = mustRenderTemplate(filepath.Join(templateDir, "yaml", "configFile.tmpl"), templateResources) + files["kubernetes/yaml/configGroup.go"] = mustRenderTemplate(filepath.Join(templateDir, "yaml", "configGroup.tmpl"), templateResources) + files["kubernetes/yaml/transformation.go"] = mustRenderTemplate(filepath.Join(templateDir, "yaml", "transformation.tmpl"), templateResources) + files["kubernetes/yaml/yaml.go"] = mustRenderTemplate(filepath.Join(templateDir, "yaml", "yaml.tmpl"), templateResources) + for filename, contents := range files { path := filepath.Join(outdir, filename) @@ -341,6 +374,31 @@ func writeGoClient(data map[string]interface{}, outdir string) { } } +func mustLoadFile(path string) []byte { + b, err := ioutil.ReadFile(path) + if err != nil { + panic(err) + } + return b +} + +func mustRenderTemplate(path string, resources gen.TemplateResources) []byte { + b := mustLoadFile(path) + t := template.Must(template.New("resources").Parse(string(b))) + + var buf bytes.Buffer + err := t.Execute(&buf, resources) + if err != nil { + panic(err) + } + formattedSource, err := format.Source(buf.Bytes()) + if err != nil { + panic(err) + } + + return formattedSource +} + func genPulumiSchemaPackage(data map[string]interface{}) *schema.Package { pkgSpec := gen.PulumiSchema(data) pkg, err := schema.ImportSpec(pkgSpec, nil) diff --git a/provider/go.mod b/provider/go.mod index 491fd89135..3460a32699 100644 --- a/provider/go.mod +++ b/provider/go.mod @@ -11,8 +11,8 @@ require ( github.com/imdario/mergo v0.3.8 github.com/mitchellh/go-wordwrap v1.0.0 github.com/pkg/errors v0.9.1 - github.com/pulumi/pulumi/pkg/v2 v2.1.0 - github.com/pulumi/pulumi/sdk/v2 v2.1.0 + github.com/pulumi/pulumi/pkg/v2 v2.1.1-0.20200506045153-0e512aa0ef84 + github.com/pulumi/pulumi/sdk/v2 v2.1.1-0.20200506045153-0e512aa0ef84 github.com/stretchr/testify v1.5.1 google.golang.org/grpc v1.28.0 k8s.io/api v0.17.0 diff --git a/provider/go.sum b/provider/go.sum index c3a2103eea..aa7d1fafb8 100644 --- a/provider/go.sum +++ b/provider/go.sum @@ -215,6 +215,8 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -437,12 +439,12 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/pulumi/pulumi/pkg/v2 v2.1.0 h1:L/gaZ4XQGLODxzXu1SVfIHUHWCR8ENO4mYQnpv6u+Go= -github.com/pulumi/pulumi/pkg/v2 v2.1.0/go.mod h1:NadTQy17wc69lQt/xTl5b6/fbl/tBiOPYMIZ+M/KtBI= +github.com/pulumi/pulumi/pkg/v2 v2.1.1-0.20200506045153-0e512aa0ef84 h1:IuN+CUhkLj7CwthEnWhifL25N4KRykiQEfKJXTI//mQ= +github.com/pulumi/pulumi/pkg/v2 v2.1.1-0.20200506045153-0e512aa0ef84/go.mod h1:hXaFYjGEnsQ7qGRJbCDhjuGh7sip3TsaOGNkU3ADt9s= github.com/pulumi/pulumi/sdk/v2 v2.0.0 h1:3VMXbEo3bqeaU+YDt8ufVBLD0WhLYE3tG3t/nIZ3Iac= github.com/pulumi/pulumi/sdk/v2 v2.0.0/go.mod h1:W7k1UDYerc5o97mHnlHHp5iQZKEby+oQrQefWt+2RF4= -github.com/pulumi/pulumi/sdk/v2 v2.1.0 h1:NZCLrvggMHlBzsaAcvChdDhQ5i9vJxARnLCY7NCFl18= -github.com/pulumi/pulumi/sdk/v2 v2.1.0/go.mod h1:W7k1UDYerc5o97mHnlHHp5iQZKEby+oQrQefWt+2RF4= +github.com/pulumi/pulumi/sdk/v2 v2.1.1-0.20200506045153-0e512aa0ef84 h1:6qDezDHciRcIKyhQQr/dA7numrfYmm3guPlQU6bYXp4= +github.com/pulumi/pulumi/sdk/v2 v2.1.1-0.20200506045153-0e512aa0ef84/go.mod h1:QNbWpL4gvf3X0lUFT7TXA2Jo1ff/Ti2l97AyFGYwvW4= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= @@ -472,6 +474,8 @@ github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs= github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -521,6 +525,8 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= gocloud.dev v0.19.0/go.mod h1:SmKwiR8YwIMMJvQBKLsC3fHNyMwXLw3PMDO+VVteJMI= @@ -563,6 +569,7 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367 h1:0IiAsCRByjO2QjX7ZPkw5oU9x+n1YqRL802rjC0c3Aw= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -570,6 +577,7 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -687,6 +695,7 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -700,6 +709,7 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2 h1:L/G4KZvrQn7FWLN/LlulBtBzrLUhqjiGfTWWDmrh+IQ= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/provider/pkg/gen/go-templates/yaml/configFile.tmpl b/provider/pkg/gen/go-templates/yaml/configFile.tmpl new file mode 100644 index 0000000000..04e251fe4f --- /dev/null +++ b/provider/pkg/gen/go-templates/yaml/configFile.tmpl @@ -0,0 +1,96 @@ +// Copyright 2016-2020, 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. + +// *** WARNING: this file was generated by pulumigen. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +package yaml + +import ( + "fmt" + + "github.com/pkg/errors" + "github.com/pulumi/pulumi/sdk/v2/go/pulumi" +) + +// ConfigFile creates a set of Kubernetes resources from a Kubernetes YAML file. +type ConfigFile struct { + pulumi.ResourceState + + Resources map[string]pulumi.Resource +} + +// The set of arguments for constructing a ConfigFile resource. +type ConfigFileArgs struct { + // File is a path or URL that uniquely identifies a file. + File string + // Transformations is an optional list of transformations to apply to Kubernetes resource definitions + // before registering with the engine. + Transformations []Transformation + // ResourcePrefix is an optional prefix for the auto-generated resource names. For example, a resource named `bar` + // created with resource prefix of `"foo"` would produce a resource named `"foo-bar"`. + ResourcePrefix string +} + +// NewConfigFile registers a new resource with the given unique name, arguments, and options. +func NewConfigFile(ctx *pulumi.Context, + name string, args *ConfigFileArgs, opts ...pulumi.ResourceOption) (*ConfigFile, error) { + + // Register the resulting resource state. + configFile := &ConfigFile{ + Resources: map[string]pulumi.Resource{}, + } + err := ctx.RegisterComponentResource("kubernetes:yaml:ConfigFile", name, configFile, opts...) + if err != nil { + return nil, err + } + + // Now provision all child resources by parsing the YAML file. + if args != nil { + // Honor the resource name prefix if specified. + if args.ResourcePrefix != "" { + name = args.ResourcePrefix + "-" + name + } + + // Parse and decode the YAML files. + rs, err := parseDecodeYamlFiles(ctx, &ConfigGroupArgs{ + Files: []string{args.File}, + Transformations: args.Transformations, + ResourcePrefix: args.ResourcePrefix, + }, true, pulumi.Parent(configFile)) + if err != nil { + return nil, err + } + configFile.Resources = rs + } + + // Finally, register all of the resources found. + err = ctx.RegisterResourceOutputs(configFile, pulumi.Map{}) + if err != nil { + return nil, errors.Wrapf(err, "registering child resources") + } + + return configFile, nil +} + +// GetResource returns a resource defined by a built-in Kubernetes group/version/kind, name and namespace. +// For example, GetResource("v1/Pod", "foo", "") would return a Pod called "foo" from the "default" namespace. +func (cf *ConfigFile) GetResource(gvk, name, namespace string) pulumi.Resource { + id := name + if len(namespace) > 0 && namespace != "default" { + id = fmt.Sprintf("%s/%s", namespace, name) + } + key := fmt.Sprintf("%s::%s", gvk, id) + return cf.Resources[key] +} diff --git a/provider/pkg/gen/go-templates/yaml/configGroup.tmpl b/provider/pkg/gen/go-templates/yaml/configGroup.tmpl new file mode 100644 index 0000000000..7435964929 --- /dev/null +++ b/provider/pkg/gen/go-templates/yaml/configGroup.tmpl @@ -0,0 +1,96 @@ +// Copyright 2016-2020, 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. + +// *** WARNING: this file was generated by pulumigen. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +package yaml + +import ( + "fmt" + + "github.com/pkg/errors" + "github.com/pulumi/pulumi/sdk/v2/go/pulumi" +) + +// ConfigGroup creates a set of Kubernetes resources from Kubernetes YAML. +type ConfigGroup struct { + pulumi.ResourceState + + Resources map[string]pulumi.Resource +} + +// The set of arguments for constructing a ConfigGroup resource. +type ConfigGroupArgs struct { + // Files is a set of paths, globs, or URLs that uniquely identify files. + Files []string + // YAML is list of strings containing Kubernetes resource definitions in YAML. + YAML []string + // Objs is a collection of object maps representing Kubernetes resources. + Objs []map[string]interface{} + // Transformations is an optional list of transformations to apply to Kubernetes resource definitions + // before registering with the engine. + Transformations []Transformation + // ResourcePrefix is an optional prefix for the auto-generated resource names. For example, a resource named `bar` + // created with resource prefix of `"foo"` would produce a resource named `"foo-bar"`. + ResourcePrefix string +} + +// NewConfigGroup registers a new resource with the given unique name, arguments, and options. +func NewConfigGroup(ctx *pulumi.Context, + name string, args *ConfigGroupArgs, opts ...pulumi.ResourceOption) (*ConfigGroup, error) { + + // Register the resulting resource state. + configGroup := &ConfigGroup{ + Resources: map[string]pulumi.Resource{}, + } + err := ctx.RegisterComponentResource("kubernetes:yaml:ConfigGroup", name, configGroup, opts...) + if err != nil { + return nil, err + } + + // Now provision all child resources by parsing the YAML files. + if args != nil { + // Honor the resource name prefix if specified. + if args.ResourcePrefix != "" { + name = args.ResourcePrefix + "-" + name + } + + // Parse and decode the YAML files. + rs, err := parseDecodeYamlFiles(ctx, args, true, pulumi.Parent(configGroup)) + if err != nil { + return nil, err + } + configGroup.Resources = rs + } + + // Finally, register all of the resources found. + err = ctx.RegisterResourceOutputs(configGroup, pulumi.Map{}) + if err != nil { + return nil, errors.Wrapf(err, "registering child resources") + } + + return configGroup, nil +} + +// GetResource returns a resource defined by a built-in Kubernetes group/version/kind, name and namespace. +// For example, GetResource("v1/Pod", "foo", "") would return a Pod called "foo" from the "default" namespace. +func (cf *ConfigGroup) GetResource(gvk, name, namespace string) pulumi.Resource { + id := name + if len(namespace) > 0 && namespace != "default" { + id = fmt.Sprintf("%s/%s", namespace, name) + } + key := fmt.Sprintf("%s::%s", gvk, id) + return cf.Resources[key] +} diff --git a/provider/pkg/gen/go-templates/yaml/transformation.tmpl b/provider/pkg/gen/go-templates/yaml/transformation.tmpl new file mode 100644 index 0000000000..4dbb48f295 --- /dev/null +++ b/provider/pkg/gen/go-templates/yaml/transformation.tmpl @@ -0,0 +1,28 @@ +// Copyright 2016-2020, 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. + +// *** WARNING: this file was generated by pulumigen. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +package yaml + +import ( + "github.com/pulumi/pulumi/sdk/v2/go/pulumi" +) + +// Transformation is the callback signature for YAML-related resources. A transformation is passed a map +// of resource arguments, resource options, and can modify the state prior to the resource actually being +// created. The effect will be as though those properties were passed in place of the original call to the +// resource constructor. Important: any values set on the state must be prompt (not Output values). +type Transformation = func(state map[string]interface{}, opts ...pulumi.ResourceOption) diff --git a/provider/pkg/gen/go-templates/yaml/yaml.tmpl b/provider/pkg/gen/go-templates/yaml/yaml.tmpl new file mode 100644 index 0000000000..066aef8274 --- /dev/null +++ b/provider/pkg/gen/go-templates/yaml/yaml.tmpl @@ -0,0 +1,231 @@ +// Copyright 2016-2020, 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. + +// *** WARNING: this file was generated by pulumigen. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +package yaml + +import ( + "fmt" + "io/ioutil" + "net/http" + "net/url" + "path/filepath" + "reflect" + + "github.com/pkg/errors" +{{- range .Imports}} + {{.}} +{{- end}} + "github.com/pulumi/pulumi/sdk/v2/go/pulumi" +) + +func parseDecodeYamlFiles(ctx *pulumi.Context, args *ConfigGroupArgs, glob bool, opts ...pulumi.ResourceOption, +) (map[string]pulumi.Resource, error) { + + // Start with the provided objects and YAML arrays, if any, and we'll append to them. + objs := args.Objs + yamls := args.YAML + + // Start by gathering up any other YAML from files provided. + for _, file := range args.Files { + // Read the raw YAML file(s) specified in the input file parameter. It might be a URL or a file path. + var yaml []byte + u, err := url.Parse(file) + if err != nil && u.IsAbs() { + // If the string looks like a URL, in that it begins with a scheme, fetch it over the network. + resp, err := http.Get(file) + if err != nil { + return nil, errors.Wrapf(err, "fetching YAML over network") + } + defer resp.Body.Close() + yaml, err = ioutil.ReadAll(resp.Body) + if err != nil { + return nil, errors.Wrapf(err, "reading YAML over network") + } + yamls = append(yamls, string(yaml)) + } else { + // Otherwise, assume this is a path to a file on disk. If globbing is enabled, we might have + // multiple files -- otherwise just read a singular file. + var files []string + if glob { + files, err = filepath.Glob(file) + if err != nil { + return nil, errors.Wrapf(err, "expanding glob") + } + } else { + files = []string{file} + } + for _, f := range files { + yaml, err = ioutil.ReadFile(f) + if err != nil { + return nil, errors.Wrapf(err, "reading YAML file from disk") + } + yamls = append(yamls, string(yaml)) + } + } + } + + // Next parse all YAML documents into objects. + for _, yaml := range yamls { + // Parse the resulting YAML bytes and turn them into raw Kubernetes objects. + dec, err := yamlDecode(ctx, yaml, opts...) + if err != nil { + return nil, errors.Wrapf(err, "decoding YAML") + } + objs = append(objs, dec...) + } + + // Now process the resulting list of Kubernetes objects. + return parseYamlObjects(ctx, objs, args.Transformations, args.ResourcePrefix, opts...) +} + +// yamlDecode invokes the function to decode a single YAML file and decompose it into object structures. +func yamlDecode(ctx *pulumi.Context, text string, opts ...pulumi.ResourceOption) ([]map[string]interface{}, error) { + args := struct { + Text string `pulumi:"text"` + }{Text: text} + var ret struct { + Result []map[string]interface{} `pulumi:"result"` + } + if err := ctx.Invoke("kubernetes:yaml:decode", &args, &ret); err != nil { + return nil, err + } + return ret.Result, nil +} + +func parseYamlObjects(ctx *pulumi.Context, objs []map[string]interface{}, transformations []Transformation, + resourcePrefix string, opts ...pulumi.ResourceOption, +) (map[string]pulumi.Resource, error) { + var intermediates []resourceTuple + for _, obj := range objs { + res, err := parseYamlObject(ctx, obj, transformations, resourcePrefix, opts...) + if err != nil { + return nil, err + } + for _, r := range res { + intermediates = append(intermediates, r) + } + } + + resources := map[string]pulumi.Resource{} + for _, r := range intermediates { + resources[r.Name] = r.Resource + } + return resources, nil +} + +type resourceTuple struct { + Name string + Resource pulumi.Resource +} + +type UntypedArgs map[string]interface{} + +func (UntypedArgs) ElementType() reflect.Type { + return reflect.TypeOf((*map[string]interface{})(nil)).Elem() +} + +func parseYamlObject(ctx *pulumi.Context, obj map[string]interface{}, transformations []Transformation, + resourcePrefix string, opts ...pulumi.ResourceOption, +) ([]resourceTuple, error) { + + // Allow users to change API objects before any validation. + for _, t := range transformations { + t(obj, opts...) + } + + // Ensure there is a kind and API version. + kind, hasKind := obj["kind"] + apiVersion, hasAPIVersion := obj["apiVersion"] + if !hasKind || !hasAPIVersion { + return nil, errors.Errorf("Kubernetes resources require a kind and apiVersion: %+v", obj) + } + fullKind := fmt.Sprintf("%s/%s", apiVersion, kind) + + // Recursively traverse built-in Kubernetes list types into a single set of "naked" resource + // definitions that we can register with the Pulumi engine. + // + // Kubernetes does not instantiate list types like `v1.List`. When the API server receives + // a list, it will recursively traverse it and perform the necessary operations on the + // each "instantiable" resource it finds. For example, `kubectl apply` on a + // `v1.ConfigMapList` will cause the API server to traverse the list, and `apply` each + // `v1.ConfigMap` it finds. + // + // Since Kubernetes does not instantiate list types directly, Pulumi also traverses lists + // for resource definitions that can be managed by Kubernetes, and registers those with the + // engine instead. + switch fullKind { + case {{range $idx, $v := .ListKinds -}} {{if $idx}}, + {{end}}"{{$v.GVK}}" {{- end}}: + var resources []resourceTuple + if rawItems, hasItems := obj["items"]; hasItems { + if items, ok := rawItems.([]interface{}); ok { + for _, item := range items { + if obj, ok := item.(map[string]interface{}); ok { + rs, err := parseYamlObject(ctx, obj, transformations, resourcePrefix, opts...) + if err != nil { + return nil, err + } + for _, r := range rs { + resources = append(resources, r) + } + } + } + } + } + return resources, nil + } + + // If we got here, it's not a recursively traversed type, so process it directly. + // First, validate that it has the requisite metadata and name properties. + meta, hasMeta := obj["metadata"] + if !hasMeta { + return nil, errors.Errorf("YAML object does not have a .metadata field: %s %+v", fullKind, obj) + } + metaDict, hasMetaDict := meta.(map[string]interface{}) + if !hasMetaDict { + return nil, errors.Errorf("YAML object does not have a .metadata dictionary: %s %+v", fullKind, obj) + } + metaName, hasMetaName := metaDict["name"].(string) + if !hasMetaName || metaName == "" { + return nil, errors.Errorf("YAML object does not have a .metadata.name: %s %+v", fullKind, obj) + } + + // Manufacture a name as appropriate, out of the meta name, namespace, and optional prefix. + if ns, hasNS := metaDict["namespace"]; hasNS { + metaName = fmt.Sprintf("%s/%s", ns, metaName) + } + if resourcePrefix != "" { + metaName = fmt.Sprintf("%s-%s", resourcePrefix, metaName) + } + + key := fmt.Sprintf("%s::%s", fullKind, metaName) + + // Finally allocate a resource of the correct type. + switch fullKind { +{{- range .NonListKinds}} + case "{{.GVK}}": + var res {{.Alias}}.{{.Name}} + err := ctx.RegisterResource("{{.Token}}", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + {{`return []resourceTuple{{Name: key, Resource: &res}}, nil`}} +{{- end}} + default: + return nil, errors.Errorf("unrecognized kind %s %+v", fullKind, obj) + } +} diff --git a/provider/pkg/gen/types.go b/provider/pkg/gen/types.go new file mode 100644 index 0000000000..bb674584f5 --- /dev/null +++ b/provider/pkg/gen/types.go @@ -0,0 +1,64 @@ +// Copyright 2016-2020, 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 gen + +import ( + "strings" + + "github.com/pulumi/pulumi/sdk/v2/go/common/util/contract" +) + +type TemplateResource struct { + Alias string + Name string + Package string + Token string +} + +func (tr TemplateResource) GVK() string { + parts := strings.Split(tr.Token, ":") + contract.Assert(len(parts) == 3) + gvk := parts[1] + "/" + parts[2] + return strings.TrimPrefix(gvk, "core/") +} + +func (tr TemplateResource) IsListKind() bool { + return strings.HasSuffix(tr.Name, "List") +} + +type TemplateResources struct { + Resources []TemplateResource + Imports []string +} + +func (tr TemplateResources) ListKinds() []TemplateResource { + var resources []TemplateResource + for _, r := range tr.Resources { + if r.IsListKind() { + resources = append(resources, r) + } + } + return resources +} + +func (tr TemplateResources) NonListKinds() []TemplateResource { + var resources []TemplateResource + for _, r := range tr.Resources { + if !r.IsListKind() { + resources = append(resources, r) + } + } + return resources +} diff --git a/sdk/go.mod b/sdk/go.mod index 45d17269c3..471a95f6c3 100644 --- a/sdk/go.mod +++ b/sdk/go.mod @@ -3,10 +3,9 @@ module github.com/pulumi/pulumi-kubernetes/sdk/v2 go 1.13 require ( - github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d // indirect github.com/google/go-cmp v0.4.0 // indirect github.com/pkg/errors v0.9.1 - github.com/pulumi/pulumi/sdk/v2 v2.0.0 + github.com/pulumi/pulumi/sdk/v2 v2.1.1-0.20200506045153-0e512aa0ef84 github.com/sergi/go-diff v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect google.golang.org/genproto v0.0.0-20200318110522-7735f76e9fa5 // indirect diff --git a/sdk/go.sum b/sdk/go.sum index eaf3b2efcb..968c591105 100644 --- a/sdk/go.sum +++ b/sdk/go.sum @@ -60,8 +60,8 @@ github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14j github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= -github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -149,8 +149,8 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/pulumi/pulumi/sdk/v2 v2.0.0 h1:3VMXbEo3bqeaU+YDt8ufVBLD0WhLYE3tG3t/nIZ3Iac= -github.com/pulumi/pulumi/sdk/v2 v2.0.0/go.mod h1:W7k1UDYerc5o97mHnlHHp5iQZKEby+oQrQefWt+2RF4= +github.com/pulumi/pulumi/sdk/v2 v2.1.1-0.20200506045153-0e512aa0ef84 h1:6qDezDHciRcIKyhQQr/dA7numrfYmm3guPlQU6bYXp4= +github.com/pulumi/pulumi/sdk/v2 v2.1.1-0.20200506045153-0e512aa0ef84/go.mod h1:QNbWpL4gvf3X0lUFT7TXA2Jo1ff/Ti2l97AyFGYwvW4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= @@ -164,9 +164,10 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs= -github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -198,6 +199,8 @@ github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1: go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -211,6 +214,8 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -256,6 +261,8 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e h1:aZzprAO9/8oim3qStq3wc1Xuxx4QmAGriC4VU4ojemQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/sdk/go/kubernetes/config/config.go b/sdk/go/kubernetes/config/config.go new file mode 100644 index 0000000000..c7a79db686 --- /dev/null +++ b/sdk/go/kubernetes/config/config.go @@ -0,0 +1,65 @@ +// *** WARNING: this file was generated by pulumigen. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +package config + +import ( + "github.com/pulumi/pulumi/sdk/v2/go/pulumi" + "github.com/pulumi/pulumi/sdk/v2/go/pulumi/config" +) + +// If present, the name of the kubeconfig cluster to use. +func GetCluster(ctx *pulumi.Context) string { + return config.Get(ctx, "kubernetes:cluster") +} + +// If present, the name of the kubeconfig context to use. +func GetContext(ctx *pulumi.Context) string { + return config.Get(ctx, "kubernetes:context") +} + +// BETA FEATURE - If present and set to true, enable server-side diff calculations. +// This feature is in developer preview, and is disabled by default. +// +// This config can be specified in the following ways, using this precedence: +// 1. This `enableDryRun` parameter. +// 2. The `PULUMI_K8S_ENABLE_DRY_RUN` environment variable. +func GetEnableDryRun(ctx *pulumi.Context) bool { + return config.GetBool(ctx, "kubernetes:enableDryRun") +} + +// The contents of a kubeconfig file. If this is set, this config will be used instead of $KUBECONFIG. +func GetKubeconfig(ctx *pulumi.Context) string { + return config.Get(ctx, "kubernetes:kubeconfig") +} + +// If present, the default namespace to use. This flag is ignored for cluster-scoped resources. +// +// A namespace can be specified in multiple places, and the precedence is as follows: +// 1. `.metadata.namespace` set on the resource. +// 2. This `namespace` parameter. +// 3. `namespace` set for the active context in the kubeconfig. +func GetNamespace(ctx *pulumi.Context) string { + return config.Get(ctx, "kubernetes:namespace") +} + +// BETA FEATURE - If present, render resource manifests to this directory. In this mode, resources will not +// be created on a Kubernetes cluster, but the rendered manifests will be kept in sync with changes +// to the Pulumi program. This feature is in developer preview, and is disabled by default. +// +// Note that some computed Outputs such as status fields will not be populated +// since the resources are not created on a Kubernetes cluster. These Output values will remain undefined, +// and may result in an error if they are referenced by other resources. Also note that any secret values +// used in these resources will be rendered in plaintext to the resulting YAML. +func GetRenderYamlToDirectory(ctx *pulumi.Context) string { + return config.Get(ctx, "kubernetes:renderYamlToDirectory") +} + +// If present and set to true, suppress apiVersion deprecation warnings from the CLI. +// +// This config can be specified in the following ways, using this precedence: +// 1. This `suppressDeprecationWarnings` parameter. +// 2. The `PULUMI_K8S_SUPPRESS_DEPRECATION_WARNINGS` environment variable. +func GetSuppressDeprecationWarnings(ctx *pulumi.Context) bool { + return config.GetBool(ctx, "kubernetes:suppressDeprecationWarnings") +} diff --git a/sdk/go/kubernetes/doc.go b/sdk/go/kubernetes/doc.go new file mode 100644 index 0000000000..cdec4c6f08 --- /dev/null +++ b/sdk/go/kubernetes/doc.go @@ -0,0 +1,3 @@ +// A Pulumi package for creating and managing Kubernetes resources. +// +package kubernetes diff --git a/sdk/go/kubernetes/provider.go b/sdk/go/kubernetes/provider.go new file mode 100644 index 0000000000..1c14aea456 --- /dev/null +++ b/sdk/go/kubernetes/provider.go @@ -0,0 +1,110 @@ +// *** WARNING: this file was generated by pulumigen. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +package kubernetes + +import ( + "reflect" + + "github.com/pulumi/pulumi/sdk/v2/go/pulumi" +) + +// The provider type for the kubernetes package. +type Provider struct { + pulumi.ProviderResourceState +} + +// NewProvider registers a new resource with the given unique name, arguments, and options. +func NewProvider(ctx *pulumi.Context, + name string, args *ProviderArgs, opts ...pulumi.ResourceOption) (*Provider, error) { + if args == nil { + args = &ProviderArgs{} + } + var resource Provider + err := ctx.RegisterResource("pulumi:providers:kubernetes", name, args, &resource, opts...) + if err != nil { + return nil, err + } + return &resource, nil +} + +type providerArgs struct { + // If present, the name of the kubeconfig cluster to use. + Cluster *string `pulumi:"cluster"` + // If present, the name of the kubeconfig context to use. + Context *string `pulumi:"context"` + // BETA FEATURE - If present and set to true, enable server-side diff calculations. + // This feature is in developer preview, and is disabled by default. + // + // This config can be specified in the following ways, using this precedence: + // 1. This `enableDryRun` parameter. + // 2. The `PULUMI_K8S_ENABLE_DRY_RUN` environment variable. + EnableDryRun *bool `pulumi:"enableDryRun"` + // The contents of a kubeconfig file. If this is set, this config will be used instead of $KUBECONFIG. + Kubeconfig *string `pulumi:"kubeconfig"` + // If present, the default namespace to use. This flag is ignored for cluster-scoped resources. + // + // A namespace can be specified in multiple places, and the precedence is as follows: + // 1. `.metadata.namespace` set on the resource. + // 2. This `namespace` parameter. + // 3. `namespace` set for the active context in the kubeconfig. + Namespace *string `pulumi:"namespace"` + // BETA FEATURE - If present, render resource manifests to this directory. In this mode, resources will not + // be created on a Kubernetes cluster, but the rendered manifests will be kept in sync with changes + // to the Pulumi program. This feature is in developer preview, and is disabled by default. + // + // Note that some computed Outputs such as status fields will not be populated + // since the resources are not created on a Kubernetes cluster. These Output values will remain undefined, + // and may result in an error if they are referenced by other resources. Also note that any secret values + // used in these resources will be rendered in plaintext to the resulting YAML. + RenderYamlToDirectory *string `pulumi:"renderYamlToDirectory"` + // If present and set to true, suppress apiVersion deprecation warnings from the CLI. + // + // This config can be specified in the following ways, using this precedence: + // 1. This `suppressDeprecationWarnings` parameter. + // 2. The `PULUMI_K8S_SUPPRESS_DEPRECATION_WARNINGS` environment variable. + SuppressDeprecationWarnings *bool `pulumi:"suppressDeprecationWarnings"` +} + +// The set of arguments for constructing a Provider resource. +type ProviderArgs struct { + // If present, the name of the kubeconfig cluster to use. + Cluster pulumi.StringPtrInput + // If present, the name of the kubeconfig context to use. + Context pulumi.StringPtrInput + // BETA FEATURE - If present and set to true, enable server-side diff calculations. + // This feature is in developer preview, and is disabled by default. + // + // This config can be specified in the following ways, using this precedence: + // 1. This `enableDryRun` parameter. + // 2. The `PULUMI_K8S_ENABLE_DRY_RUN` environment variable. + EnableDryRun pulumi.BoolPtrInput + // The contents of a kubeconfig file. If this is set, this config will be used instead of $KUBECONFIG. + Kubeconfig pulumi.StringPtrInput + // If present, the default namespace to use. This flag is ignored for cluster-scoped resources. + // + // A namespace can be specified in multiple places, and the precedence is as follows: + // 1. `.metadata.namespace` set on the resource. + // 2. This `namespace` parameter. + // 3. `namespace` set for the active context in the kubeconfig. + Namespace pulumi.StringPtrInput + // BETA FEATURE - If present, render resource manifests to this directory. In this mode, resources will not + // be created on a Kubernetes cluster, but the rendered manifests will be kept in sync with changes + // to the Pulumi program. This feature is in developer preview, and is disabled by default. + // + // Note that some computed Outputs such as status fields will not be populated + // since the resources are not created on a Kubernetes cluster. These Output values will remain undefined, + // and may result in an error if they are referenced by other resources. Also note that any secret values + // used in these resources will be rendered in plaintext to the resulting YAML. + RenderYamlToDirectory pulumi.StringPtrInput + // If present and set to true, suppress apiVersion deprecation warnings from the CLI. + // + // This config can be specified in the following ways, using this precedence: + // 1. This `suppressDeprecationWarnings` parameter. + // 2. The `PULUMI_K8S_SUPPRESS_DEPRECATION_WARNINGS` environment variable. + SuppressDeprecationWarnings pulumi.BoolPtrInput +} + +func (ProviderArgs) ElementType() reflect.Type { + return reflect.TypeOf((*providerArgs)(nil)).Elem() +} diff --git a/sdk/go/kubernetes/yaml/configFile.go b/sdk/go/kubernetes/yaml/configFile.go new file mode 100644 index 0000000000..9f6d325dbb --- /dev/null +++ b/sdk/go/kubernetes/yaml/configFile.go @@ -0,0 +1,96 @@ +// Copyright 2016-2020, 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. + +// *** WARNING: this file was generated by pulumigen. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +package yaml + +import ( + "fmt" + + "github.com/pkg/errors" + "github.com/pulumi/pulumi/sdk/v2/go/pulumi" +) + +// ConfigFile creates a set of Kubernetes resources from a Kubernetes YAML file. +type ConfigFile struct { + pulumi.ResourceState + + Resources map[string]pulumi.Resource +} + +// The set of arguments for constructing a ConfigFile resource. +type ConfigFileArgs struct { + // File is a path or URL that uniquely identifies a file. + File string + // Transformations is an optional list of transformations to apply to Kubernetes resource definitions + // before registering with the engine. + Transformations []Transformation + // ResourcePrefix is an optional prefix for the auto-generated resource names. For example, a resource named `bar` + // created with resource prefix of `"foo"` would produce a resource named `"foo-bar"`. + ResourcePrefix string +} + +// NewConfigFile registers a new resource with the given unique name, arguments, and options. +func NewConfigFile(ctx *pulumi.Context, + name string, args *ConfigFileArgs, opts ...pulumi.ResourceOption) (*ConfigFile, error) { + + // Register the resulting resource state. + configFile := &ConfigFile{ + Resources: map[string]pulumi.Resource{}, + } + err := ctx.RegisterComponentResource("kubernetes:yaml:ConfigFile", name, configFile, opts...) + if err != nil { + return nil, err + } + + // Now provision all child resources by parsing the YAML file. + if args != nil { + // Honor the resource name prefix if specified. + if args.ResourcePrefix != "" { + name = args.ResourcePrefix + "-" + name + } + + // Parse and decode the YAML files. + rs, err := parseDecodeYamlFiles(ctx, &ConfigGroupArgs{ + Files: []string{args.File}, + Transformations: args.Transformations, + ResourcePrefix: args.ResourcePrefix, + }, true, pulumi.Parent(configFile)) + if err != nil { + return nil, err + } + configFile.Resources = rs + } + + // Finally, register all of the resources found. + err = ctx.RegisterResourceOutputs(configFile, pulumi.Map{}) + if err != nil { + return nil, errors.Wrapf(err, "registering child resources") + } + + return configFile, nil +} + +// GetResource returns a resource defined by a built-in Kubernetes group/version/kind, name and namespace. +// For example, GetResource("v1/Pod", "foo", "") would return a Pod called "foo" from the "default" namespace. +func (cf *ConfigFile) GetResource(gvk, name, namespace string) pulumi.Resource { + id := name + if len(namespace) > 0 && namespace != "default" { + id = fmt.Sprintf("%s/%s", namespace, name) + } + key := fmt.Sprintf("%s::%s", gvk, id) + return cf.Resources[key] +} diff --git a/sdk/go/kubernetes/yaml/configGroup.go b/sdk/go/kubernetes/yaml/configGroup.go new file mode 100644 index 0000000000..9962aefcac --- /dev/null +++ b/sdk/go/kubernetes/yaml/configGroup.go @@ -0,0 +1,96 @@ +// Copyright 2016-2020, 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. + +// *** WARNING: this file was generated by pulumigen. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +package yaml + +import ( + "fmt" + + "github.com/pkg/errors" + "github.com/pulumi/pulumi/sdk/v2/go/pulumi" +) + +// ConfigGroup creates a set of Kubernetes resources from Kubernetes YAML. +type ConfigGroup struct { + pulumi.ResourceState + + Resources map[string]pulumi.Resource +} + +// The set of arguments for constructing a ConfigGroup resource. +type ConfigGroupArgs struct { + // Files is a set of paths, globs, or URLs that uniquely identify files. + Files []string + // YAML is list of strings containing Kubernetes resource definitions in YAML. + YAML []string + // Objs is a collection of object maps representing Kubernetes resources. + Objs []map[string]interface{} + // Transformations is an optional list of transformations to apply to Kubernetes resource definitions + // before registering with the engine. + Transformations []Transformation + // ResourcePrefix is an optional prefix for the auto-generated resource names. For example, a resource named `bar` + // created with resource prefix of `"foo"` would produce a resource named `"foo-bar"`. + ResourcePrefix string +} + +// NewConfigGroup registers a new resource with the given unique name, arguments, and options. +func NewConfigGroup(ctx *pulumi.Context, + name string, args *ConfigGroupArgs, opts ...pulumi.ResourceOption) (*ConfigGroup, error) { + + // Register the resulting resource state. + configGroup := &ConfigGroup{ + Resources: map[string]pulumi.Resource{}, + } + err := ctx.RegisterComponentResource("kubernetes:yaml:ConfigGroup", name, configGroup, opts...) + if err != nil { + return nil, err + } + + // Now provision all child resources by parsing the YAML files. + if args != nil { + // Honor the resource name prefix if specified. + if args.ResourcePrefix != "" { + name = args.ResourcePrefix + "-" + name + } + + // Parse and decode the YAML files. + rs, err := parseDecodeYamlFiles(ctx, args, true, pulumi.Parent(configGroup)) + if err != nil { + return nil, err + } + configGroup.Resources = rs + } + + // Finally, register all of the resources found. + err = ctx.RegisterResourceOutputs(configGroup, pulumi.Map{}) + if err != nil { + return nil, errors.Wrapf(err, "registering child resources") + } + + return configGroup, nil +} + +// GetResource returns a resource defined by a built-in Kubernetes group/version/kind, name and namespace. +// For example, GetResource("v1/Pod", "foo", "") would return a Pod called "foo" from the "default" namespace. +func (cf *ConfigGroup) GetResource(gvk, name, namespace string) pulumi.Resource { + id := name + if len(namespace) > 0 && namespace != "default" { + id = fmt.Sprintf("%s/%s", namespace, name) + } + key := fmt.Sprintf("%s::%s", gvk, id) + return cf.Resources[key] +} diff --git a/sdk/go/kubernetes/yaml/transformation.go b/sdk/go/kubernetes/yaml/transformation.go new file mode 100644 index 0000000000..4dbb48f295 --- /dev/null +++ b/sdk/go/kubernetes/yaml/transformation.go @@ -0,0 +1,28 @@ +// Copyright 2016-2020, 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. + +// *** WARNING: this file was generated by pulumigen. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +package yaml + +import ( + "github.com/pulumi/pulumi/sdk/v2/go/pulumi" +) + +// Transformation is the callback signature for YAML-related resources. A transformation is passed a map +// of resource arguments, resource options, and can modify the state prior to the resource actually being +// created. The effect will be as though those properties were passed in place of the original call to the +// resource constructor. Important: any values set on the state must be prompt (not Output values). +type Transformation = func(state map[string]interface{}, opts ...pulumi.ResourceOption) diff --git a/sdk/go/kubernetes/yaml/yaml.go b/sdk/go/kubernetes/yaml/yaml.go new file mode 100644 index 0000000000..c0f7106cc5 --- /dev/null +++ b/sdk/go/kubernetes/yaml/yaml.go @@ -0,0 +1,1064 @@ +// Copyright 2016-2020, 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. + +// *** WARNING: this file was generated by pulumigen. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +package yaml + +import ( + "fmt" + "io/ioutil" + "net/http" + "net/url" + "path/filepath" + "reflect" + + "github.com/pkg/errors" + admissionregistrationv1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/admissionregistration/v1" + admissionregistrationv1beta1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/admissionregistration/v1beta1" + apiextensionsv1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/apiextensions/v1" + apiextensionsv1beta1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/apiextensions/v1beta1" + apiregistrationv1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/apiregistration/v1" + apiregistrationv1beta1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/apiregistration/v1beta1" + appsv1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/apps/v1" + appsv1beta1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/apps/v1beta1" + appsv1beta2 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/apps/v1beta2" + auditregistrationv1alpha1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/auditregistration/v1alpha1" + authenticationv1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/authentication/v1" + authenticationv1beta1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/authentication/v1beta1" + authorizationv1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/authorization/v1" + authorizationv1beta1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/authorization/v1beta1" + autoscalingv1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/autoscaling/v1" + autoscalingv2beta1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/autoscaling/v2beta1" + autoscalingv2beta2 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/autoscaling/v2beta2" + batchv1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/batch/v1" + batchv1beta1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/batch/v1beta1" + batchv2alpha1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/batch/v2alpha1" + certificatesv1beta1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/certificates/v1beta1" + coordinationv1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/coordination/v1" + coordinationv1beta1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/coordination/v1beta1" + corev1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/core/v1" + discoveryv1beta1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/discovery/v1beta1" + eventsv1beta1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/events/v1beta1" + extensionsv1beta1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/extensions/v1beta1" + flowcontrolv1alpha1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/flowcontrol/v1alpha1" + metav1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/meta/v1" + networkingv1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/networking/v1" + networkingv1beta1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/networking/v1beta1" + nodev1alpha1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/node/v1alpha1" + nodev1beta1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/node/v1beta1" + policyv1beta1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/policy/v1beta1" + rbacv1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/rbac/v1" + rbacv1alpha1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/rbac/v1alpha1" + rbacv1beta1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/rbac/v1beta1" + schedulingv1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/scheduling/v1" + schedulingv1alpha1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/scheduling/v1alpha1" + schedulingv1beta1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/scheduling/v1beta1" + settingsv1alpha1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/settings/v1alpha1" + storagev1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/storage/v1" + storagev1alpha1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/storage/v1alpha1" + storagev1beta1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/storage/v1beta1" + "github.com/pulumi/pulumi/sdk/v2/go/pulumi" +) + +func parseDecodeYamlFiles(ctx *pulumi.Context, args *ConfigGroupArgs, glob bool, opts ...pulumi.ResourceOption, +) (map[string]pulumi.Resource, error) { + + // Start with the provided objects and YAML arrays, if any, and we'll append to them. + objs := args.Objs + yamls := args.YAML + + // Start by gathering up any other YAML from files provided. + for _, file := range args.Files { + // Read the raw YAML file(s) specified in the input file parameter. It might be a URL or a file path. + var yaml []byte + u, err := url.Parse(file) + if err != nil && u.IsAbs() { + // If the string looks like a URL, in that it begins with a scheme, fetch it over the network. + resp, err := http.Get(file) + if err != nil { + return nil, errors.Wrapf(err, "fetching YAML over network") + } + defer resp.Body.Close() + yaml, err = ioutil.ReadAll(resp.Body) + if err != nil { + return nil, errors.Wrapf(err, "reading YAML over network") + } + yamls = append(yamls, string(yaml)) + } else { + // Otherwise, assume this is a path to a file on disk. If globbing is enabled, we might have + // multiple files -- otherwise just read a singular file. + var files []string + if glob { + files, err = filepath.Glob(file) + if err != nil { + return nil, errors.Wrapf(err, "expanding glob") + } + } else { + files = []string{file} + } + for _, f := range files { + yaml, err = ioutil.ReadFile(f) + if err != nil { + return nil, errors.Wrapf(err, "reading YAML file from disk") + } + yamls = append(yamls, string(yaml)) + } + } + } + + // Next parse all YAML documents into objects. + for _, yaml := range yamls { + // Parse the resulting YAML bytes and turn them into raw Kubernetes objects. + dec, err := yamlDecode(ctx, yaml, opts...) + if err != nil { + return nil, errors.Wrapf(err, "decoding YAML") + } + objs = append(objs, dec...) + } + + // Now process the resulting list of Kubernetes objects. + return parseYamlObjects(ctx, objs, args.Transformations, args.ResourcePrefix, opts...) +} + +// yamlDecode invokes the function to decode a single YAML file and decompose it into object structures. +func yamlDecode(ctx *pulumi.Context, text string, opts ...pulumi.ResourceOption) ([]map[string]interface{}, error) { + args := struct { + Text string `pulumi:"text"` + }{Text: text} + var ret struct { + Result []map[string]interface{} `pulumi:"result"` + } + if err := ctx.Invoke("kubernetes:yaml:decode", &args, &ret); err != nil { + return nil, err + } + return ret.Result, nil +} + +func parseYamlObjects(ctx *pulumi.Context, objs []map[string]interface{}, transformations []Transformation, + resourcePrefix string, opts ...pulumi.ResourceOption, +) (map[string]pulumi.Resource, error) { + var intermediates []resourceTuple + for _, obj := range objs { + res, err := parseYamlObject(ctx, obj, transformations, resourcePrefix, opts...) + if err != nil { + return nil, err + } + for _, r := range res { + intermediates = append(intermediates, r) + } + } + + resources := map[string]pulumi.Resource{} + for _, r := range intermediates { + resources[r.Name] = r.Resource + } + return resources, nil +} + +type resourceTuple struct { + Name string + Resource pulumi.Resource +} + +type UntypedArgs map[string]interface{} + +func (UntypedArgs) ElementType() reflect.Type { + return reflect.TypeOf((*map[string]interface{})(nil)).Elem() +} + +func parseYamlObject(ctx *pulumi.Context, obj map[string]interface{}, transformations []Transformation, + resourcePrefix string, opts ...pulumi.ResourceOption, +) ([]resourceTuple, error) { + + // Allow users to change API objects before any validation. + for _, t := range transformations { + t(obj, opts...) + } + + // Ensure there is a kind and API version. + kind, hasKind := obj["kind"] + apiVersion, hasAPIVersion := obj["apiVersion"] + if !hasKind || !hasAPIVersion { + return nil, errors.Errorf("Kubernetes resources require a kind and apiVersion: %+v", obj) + } + fullKind := fmt.Sprintf("%s/%s", apiVersion, kind) + + // Recursively traverse built-in Kubernetes list types into a single set of "naked" resource + // definitions that we can register with the Pulumi engine. + // + // Kubernetes does not instantiate list types like `v1.List`. When the API server receives + // a list, it will recursively traverse it and perform the necessary operations on the + // each "instantiable" resource it finds. For example, `kubectl apply` on a + // `v1.ConfigMapList` will cause the API server to traverse the list, and `apply` each + // `v1.ConfigMap` it finds. + // + // Since Kubernetes does not instantiate list types directly, Pulumi also traverses lists + // for resource definitions that can be managed by Kubernetes, and registers those with the + // engine instead. + switch fullKind { + case "admissionregistration.k8s.io/v1/MutatingWebhookConfigurationList", + "admissionregistration.k8s.io/v1/ValidatingWebhookConfigurationList", + "admissionregistration.k8s.io/v1beta1/MutatingWebhookConfigurationList", + "admissionregistration.k8s.io/v1beta1/ValidatingWebhookConfigurationList", + "apiextensions.k8s.io/v1/CustomResourceDefinitionList", + "apiextensions.k8s.io/v1beta1/CustomResourceDefinitionList", + "apiregistration.k8s.io/v1/APIServiceList", + "apiregistration.k8s.io/v1beta1/APIServiceList", + "apps/v1/ControllerRevisionList", + "apps/v1/DaemonSetList", + "apps/v1/DeploymentList", + "apps/v1/ReplicaSetList", + "apps/v1/StatefulSetList", + "apps/v1beta1/ControllerRevisionList", + "apps/v1beta1/DeploymentList", + "apps/v1beta1/StatefulSetList", + "apps/v1beta2/ControllerRevisionList", + "apps/v1beta2/DaemonSetList", + "apps/v1beta2/DeploymentList", + "apps/v1beta2/ReplicaSetList", + "apps/v1beta2/StatefulSetList", + "auditregistration.k8s.io/v1alpha1/AuditSinkList", + "autoscaling/v1/HorizontalPodAutoscalerList", + "autoscaling/v2beta1/HorizontalPodAutoscalerList", + "autoscaling/v2beta2/HorizontalPodAutoscalerList", + "batch/v1/JobList", + "batch/v1beta1/CronJobList", + "batch/v2alpha1/CronJobList", + "certificates.k8s.io/v1beta1/CertificateSigningRequestList", + "coordination.k8s.io/v1/LeaseList", + "coordination.k8s.io/v1beta1/LeaseList", + "v1/ComponentStatusList", + "v1/ConfigMapList", + "v1/EndpointsList", + "v1/EventList", + "v1/LimitRangeList", + "v1/NamespaceList", + "v1/NodeList", + "v1/PersistentVolumeClaimList", + "v1/PersistentVolumeList", + "v1/PodList", + "v1/PodTemplateList", + "v1/ReplicationControllerList", + "v1/ResourceQuotaList", + "v1/SecretList", + "v1/ServiceAccountList", + "v1/ServiceList", + "discovery.k8s.io/v1beta1/EndpointSliceList", + "events.k8s.io/v1beta1/EventList", + "extensions/v1beta1/DaemonSetList", + "extensions/v1beta1/DeploymentList", + "extensions/v1beta1/IngressList", + "extensions/v1beta1/NetworkPolicyList", + "extensions/v1beta1/PodSecurityPolicyList", + "extensions/v1beta1/ReplicaSetList", + "flowcontrol.apiserver.k8s.io/v1alpha1/FlowSchemaList", + "flowcontrol.apiserver.k8s.io/v1alpha1/PriorityLevelConfigurationList", + "networking.k8s.io/v1/NetworkPolicyList", + "networking.k8s.io/v1beta1/IngressClassList", + "networking.k8s.io/v1beta1/IngressList", + "node.k8s.io/v1alpha1/RuntimeClassList", + "node.k8s.io/v1beta1/RuntimeClassList", + "policy/v1beta1/PodDisruptionBudgetList", + "policy/v1beta1/PodSecurityPolicyList", + "rbac.authorization.k8s.io/v1/ClusterRoleBindingList", + "rbac.authorization.k8s.io/v1/ClusterRoleList", + "rbac.authorization.k8s.io/v1/RoleBindingList", + "rbac.authorization.k8s.io/v1/RoleList", + "rbac.authorization.k8s.io/v1alpha1/ClusterRoleBindingList", + "rbac.authorization.k8s.io/v1alpha1/ClusterRoleList", + "rbac.authorization.k8s.io/v1alpha1/RoleBindingList", + "rbac.authorization.k8s.io/v1alpha1/RoleList", + "rbac.authorization.k8s.io/v1beta1/ClusterRoleBindingList", + "rbac.authorization.k8s.io/v1beta1/ClusterRoleList", + "rbac.authorization.k8s.io/v1beta1/RoleBindingList", + "rbac.authorization.k8s.io/v1beta1/RoleList", + "scheduling.k8s.io/v1/PriorityClassList", + "scheduling.k8s.io/v1alpha1/PriorityClassList", + "scheduling.k8s.io/v1beta1/PriorityClassList", + "settings.k8s.io/v1alpha1/PodPresetList", + "storage.k8s.io/v1/CSIDriverList", + "storage.k8s.io/v1/CSINodeList", + "storage.k8s.io/v1/StorageClassList", + "storage.k8s.io/v1/VolumeAttachmentList", + "storage.k8s.io/v1alpha1/VolumeAttachmentList", + "storage.k8s.io/v1beta1/CSIDriverList", + "storage.k8s.io/v1beta1/CSINodeList", + "storage.k8s.io/v1beta1/StorageClassList", + "storage.k8s.io/v1beta1/VolumeAttachmentList": + var resources []resourceTuple + if rawItems, hasItems := obj["items"]; hasItems { + if items, ok := rawItems.([]interface{}); ok { + for _, item := range items { + if obj, ok := item.(map[string]interface{}); ok { + rs, err := parseYamlObject(ctx, obj, transformations, resourcePrefix, opts...) + if err != nil { + return nil, err + } + for _, r := range rs { + resources = append(resources, r) + } + } + } + } + } + return resources, nil + } + + // If we got here, it's not a recursively traversed type, so process it directly. + // First, validate that it has the requisite metadata and name properties. + meta, hasMeta := obj["metadata"] + if !hasMeta { + return nil, errors.Errorf("YAML object does not have a .metadata field: %s %+v", fullKind, obj) + } + metaDict, hasMetaDict := meta.(map[string]interface{}) + if !hasMetaDict { + return nil, errors.Errorf("YAML object does not have a .metadata dictionary: %s %+v", fullKind, obj) + } + metaName, hasMetaName := metaDict["name"].(string) + if !hasMetaName || metaName == "" { + return nil, errors.Errorf("YAML object does not have a .metadata.name: %s %+v", fullKind, obj) + } + + // Manufacture a name as appropriate, out of the meta name, namespace, and optional prefix. + if ns, hasNS := metaDict["namespace"]; hasNS { + metaName = fmt.Sprintf("%s/%s", ns, metaName) + } + if resourcePrefix != "" { + metaName = fmt.Sprintf("%s-%s", resourcePrefix, metaName) + } + + key := fmt.Sprintf("%s::%s", fullKind, metaName) + + // Finally allocate a resource of the correct type. + switch fullKind { + case "admissionregistration.k8s.io/v1/MutatingWebhookConfiguration": + var res admissionregistrationv1.MutatingWebhookConfiguration + err := ctx.RegisterResource("kubernetes:admissionregistration.k8s.io/v1:MutatingWebhookConfiguration", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "admissionregistration.k8s.io/v1/ValidatingWebhookConfiguration": + var res admissionregistrationv1.ValidatingWebhookConfiguration + err := ctx.RegisterResource("kubernetes:admissionregistration.k8s.io/v1:ValidatingWebhookConfiguration", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "admissionregistration.k8s.io/v1beta1/MutatingWebhookConfiguration": + var res admissionregistrationv1beta1.MutatingWebhookConfiguration + err := ctx.RegisterResource("kubernetes:admissionregistration.k8s.io/v1beta1:MutatingWebhookConfiguration", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "admissionregistration.k8s.io/v1beta1/ValidatingWebhookConfiguration": + var res admissionregistrationv1beta1.ValidatingWebhookConfiguration + err := ctx.RegisterResource("kubernetes:admissionregistration.k8s.io/v1beta1:ValidatingWebhookConfiguration", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "apiextensions.k8s.io/v1/CustomResourceDefinition": + var res apiextensionsv1.CustomResourceDefinition + err := ctx.RegisterResource("kubernetes:apiextensions.k8s.io/v1:CustomResourceDefinition", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "apiextensions.k8s.io/v1beta1/CustomResourceDefinition": + var res apiextensionsv1beta1.CustomResourceDefinition + err := ctx.RegisterResource("kubernetes:apiextensions.k8s.io/v1beta1:CustomResourceDefinition", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "apiregistration.k8s.io/v1/APIService": + var res apiregistrationv1.APIService + err := ctx.RegisterResource("kubernetes:apiregistration.k8s.io/v1:APIService", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "apiregistration.k8s.io/v1beta1/APIService": + var res apiregistrationv1beta1.APIService + err := ctx.RegisterResource("kubernetes:apiregistration.k8s.io/v1beta1:APIService", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "apps/v1/ControllerRevision": + var res appsv1.ControllerRevision + err := ctx.RegisterResource("kubernetes:apps/v1:ControllerRevision", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "apps/v1/DaemonSet": + var res appsv1.DaemonSet + err := ctx.RegisterResource("kubernetes:apps/v1:DaemonSet", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "apps/v1/Deployment": + var res appsv1.Deployment + err := ctx.RegisterResource("kubernetes:apps/v1:Deployment", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "apps/v1/ReplicaSet": + var res appsv1.ReplicaSet + err := ctx.RegisterResource("kubernetes:apps/v1:ReplicaSet", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "apps/v1/StatefulSet": + var res appsv1.StatefulSet + err := ctx.RegisterResource("kubernetes:apps/v1:StatefulSet", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "apps/v1beta1/ControllerRevision": + var res appsv1beta1.ControllerRevision + err := ctx.RegisterResource("kubernetes:apps/v1beta1:ControllerRevision", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "apps/v1beta1/Deployment": + var res appsv1beta1.Deployment + err := ctx.RegisterResource("kubernetes:apps/v1beta1:Deployment", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "apps/v1beta1/StatefulSet": + var res appsv1beta1.StatefulSet + err := ctx.RegisterResource("kubernetes:apps/v1beta1:StatefulSet", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "apps/v1beta2/ControllerRevision": + var res appsv1beta2.ControllerRevision + err := ctx.RegisterResource("kubernetes:apps/v1beta2:ControllerRevision", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "apps/v1beta2/DaemonSet": + var res appsv1beta2.DaemonSet + err := ctx.RegisterResource("kubernetes:apps/v1beta2:DaemonSet", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "apps/v1beta2/Deployment": + var res appsv1beta2.Deployment + err := ctx.RegisterResource("kubernetes:apps/v1beta2:Deployment", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "apps/v1beta2/ReplicaSet": + var res appsv1beta2.ReplicaSet + err := ctx.RegisterResource("kubernetes:apps/v1beta2:ReplicaSet", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "apps/v1beta2/StatefulSet": + var res appsv1beta2.StatefulSet + err := ctx.RegisterResource("kubernetes:apps/v1beta2:StatefulSet", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "auditregistration.k8s.io/v1alpha1/AuditSink": + var res auditregistrationv1alpha1.AuditSink + err := ctx.RegisterResource("kubernetes:auditregistration.k8s.io/v1alpha1:AuditSink", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "authentication.k8s.io/v1/TokenRequest": + var res authenticationv1.TokenRequest + err := ctx.RegisterResource("kubernetes:authentication.k8s.io/v1:TokenRequest", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "authentication.k8s.io/v1/TokenReview": + var res authenticationv1.TokenReview + err := ctx.RegisterResource("kubernetes:authentication.k8s.io/v1:TokenReview", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "authentication.k8s.io/v1beta1/TokenReview": + var res authenticationv1beta1.TokenReview + err := ctx.RegisterResource("kubernetes:authentication.k8s.io/v1beta1:TokenReview", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "authorization.k8s.io/v1/LocalSubjectAccessReview": + var res authorizationv1.LocalSubjectAccessReview + err := ctx.RegisterResource("kubernetes:authorization.k8s.io/v1:LocalSubjectAccessReview", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "authorization.k8s.io/v1/SelfSubjectAccessReview": + var res authorizationv1.SelfSubjectAccessReview + err := ctx.RegisterResource("kubernetes:authorization.k8s.io/v1:SelfSubjectAccessReview", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "authorization.k8s.io/v1/SelfSubjectRulesReview": + var res authorizationv1.SelfSubjectRulesReview + err := ctx.RegisterResource("kubernetes:authorization.k8s.io/v1:SelfSubjectRulesReview", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "authorization.k8s.io/v1/SubjectAccessReview": + var res authorizationv1.SubjectAccessReview + err := ctx.RegisterResource("kubernetes:authorization.k8s.io/v1:SubjectAccessReview", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "authorization.k8s.io/v1beta1/LocalSubjectAccessReview": + var res authorizationv1beta1.LocalSubjectAccessReview + err := ctx.RegisterResource("kubernetes:authorization.k8s.io/v1beta1:LocalSubjectAccessReview", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "authorization.k8s.io/v1beta1/SelfSubjectAccessReview": + var res authorizationv1beta1.SelfSubjectAccessReview + err := ctx.RegisterResource("kubernetes:authorization.k8s.io/v1beta1:SelfSubjectAccessReview", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "authorization.k8s.io/v1beta1/SelfSubjectRulesReview": + var res authorizationv1beta1.SelfSubjectRulesReview + err := ctx.RegisterResource("kubernetes:authorization.k8s.io/v1beta1:SelfSubjectRulesReview", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "authorization.k8s.io/v1beta1/SubjectAccessReview": + var res authorizationv1beta1.SubjectAccessReview + err := ctx.RegisterResource("kubernetes:authorization.k8s.io/v1beta1:SubjectAccessReview", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "autoscaling/v1/HorizontalPodAutoscaler": + var res autoscalingv1.HorizontalPodAutoscaler + err := ctx.RegisterResource("kubernetes:autoscaling/v1:HorizontalPodAutoscaler", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "autoscaling/v2beta1/HorizontalPodAutoscaler": + var res autoscalingv2beta1.HorizontalPodAutoscaler + err := ctx.RegisterResource("kubernetes:autoscaling/v2beta1:HorizontalPodAutoscaler", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "autoscaling/v2beta2/HorizontalPodAutoscaler": + var res autoscalingv2beta2.HorizontalPodAutoscaler + err := ctx.RegisterResource("kubernetes:autoscaling/v2beta2:HorizontalPodAutoscaler", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "batch/v1/Job": + var res batchv1.Job + err := ctx.RegisterResource("kubernetes:batch/v1:Job", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "batch/v1beta1/CronJob": + var res batchv1beta1.CronJob + err := ctx.RegisterResource("kubernetes:batch/v1beta1:CronJob", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "batch/v2alpha1/CronJob": + var res batchv2alpha1.CronJob + err := ctx.RegisterResource("kubernetes:batch/v2alpha1:CronJob", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "certificates.k8s.io/v1beta1/CertificateSigningRequest": + var res certificatesv1beta1.CertificateSigningRequest + err := ctx.RegisterResource("kubernetes:certificates.k8s.io/v1beta1:CertificateSigningRequest", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "coordination.k8s.io/v1/Lease": + var res coordinationv1.Lease + err := ctx.RegisterResource("kubernetes:coordination.k8s.io/v1:Lease", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "coordination.k8s.io/v1beta1/Lease": + var res coordinationv1beta1.Lease + err := ctx.RegisterResource("kubernetes:coordination.k8s.io/v1beta1:Lease", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "v1/Binding": + var res corev1.Binding + err := ctx.RegisterResource("kubernetes:core/v1:Binding", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "v1/ComponentStatus": + var res corev1.ComponentStatus + err := ctx.RegisterResource("kubernetes:core/v1:ComponentStatus", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "v1/ConfigMap": + var res corev1.ConfigMap + err := ctx.RegisterResource("kubernetes:core/v1:ConfigMap", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "v1/Endpoints": + var res corev1.Endpoints + err := ctx.RegisterResource("kubernetes:core/v1:Endpoints", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "v1/Event": + var res corev1.Event + err := ctx.RegisterResource("kubernetes:core/v1:Event", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "v1/LimitRange": + var res corev1.LimitRange + err := ctx.RegisterResource("kubernetes:core/v1:LimitRange", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "v1/Namespace": + var res corev1.Namespace + err := ctx.RegisterResource("kubernetes:core/v1:Namespace", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "v1/Node": + var res corev1.Node + err := ctx.RegisterResource("kubernetes:core/v1:Node", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "v1/PersistentVolume": + var res corev1.PersistentVolume + err := ctx.RegisterResource("kubernetes:core/v1:PersistentVolume", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "v1/PersistentVolumeClaim": + var res corev1.PersistentVolumeClaim + err := ctx.RegisterResource("kubernetes:core/v1:PersistentVolumeClaim", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "v1/Pod": + var res corev1.Pod + err := ctx.RegisterResource("kubernetes:core/v1:Pod", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "v1/PodTemplate": + var res corev1.PodTemplate + err := ctx.RegisterResource("kubernetes:core/v1:PodTemplate", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "v1/ReplicationController": + var res corev1.ReplicationController + err := ctx.RegisterResource("kubernetes:core/v1:ReplicationController", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "v1/ResourceQuota": + var res corev1.ResourceQuota + err := ctx.RegisterResource("kubernetes:core/v1:ResourceQuota", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "v1/Secret": + var res corev1.Secret + err := ctx.RegisterResource("kubernetes:core/v1:Secret", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "v1/Service": + var res corev1.Service + err := ctx.RegisterResource("kubernetes:core/v1:Service", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "v1/ServiceAccount": + var res corev1.ServiceAccount + err := ctx.RegisterResource("kubernetes:core/v1:ServiceAccount", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "discovery.k8s.io/v1beta1/EndpointSlice": + var res discoveryv1beta1.EndpointSlice + err := ctx.RegisterResource("kubernetes:discovery.k8s.io/v1beta1:EndpointSlice", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "events.k8s.io/v1beta1/Event": + var res eventsv1beta1.Event + err := ctx.RegisterResource("kubernetes:events.k8s.io/v1beta1:Event", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "extensions/v1beta1/DaemonSet": + var res extensionsv1beta1.DaemonSet + err := ctx.RegisterResource("kubernetes:extensions/v1beta1:DaemonSet", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "extensions/v1beta1/Deployment": + var res extensionsv1beta1.Deployment + err := ctx.RegisterResource("kubernetes:extensions/v1beta1:Deployment", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "extensions/v1beta1/Ingress": + var res extensionsv1beta1.Ingress + err := ctx.RegisterResource("kubernetes:extensions/v1beta1:Ingress", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "extensions/v1beta1/NetworkPolicy": + var res extensionsv1beta1.NetworkPolicy + err := ctx.RegisterResource("kubernetes:extensions/v1beta1:NetworkPolicy", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "extensions/v1beta1/PodSecurityPolicy": + var res extensionsv1beta1.PodSecurityPolicy + err := ctx.RegisterResource("kubernetes:extensions/v1beta1:PodSecurityPolicy", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "extensions/v1beta1/ReplicaSet": + var res extensionsv1beta1.ReplicaSet + err := ctx.RegisterResource("kubernetes:extensions/v1beta1:ReplicaSet", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "flowcontrol.apiserver.k8s.io/v1alpha1/FlowSchema": + var res flowcontrolv1alpha1.FlowSchema + err := ctx.RegisterResource("kubernetes:flowcontrol.apiserver.k8s.io/v1alpha1:FlowSchema", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "flowcontrol.apiserver.k8s.io/v1alpha1/PriorityLevelConfiguration": + var res flowcontrolv1alpha1.PriorityLevelConfiguration + err := ctx.RegisterResource("kubernetes:flowcontrol.apiserver.k8s.io/v1alpha1:PriorityLevelConfiguration", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "meta/v1/Status": + var res metav1.Status + err := ctx.RegisterResource("kubernetes:meta/v1:Status", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "networking.k8s.io/v1/NetworkPolicy": + var res networkingv1.NetworkPolicy + err := ctx.RegisterResource("kubernetes:networking.k8s.io/v1:NetworkPolicy", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "networking.k8s.io/v1beta1/Ingress": + var res networkingv1beta1.Ingress + err := ctx.RegisterResource("kubernetes:networking.k8s.io/v1beta1:Ingress", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "networking.k8s.io/v1beta1/IngressClass": + var res networkingv1beta1.IngressClass + err := ctx.RegisterResource("kubernetes:networking.k8s.io/v1beta1:IngressClass", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "node.k8s.io/v1alpha1/RuntimeClass": + var res nodev1alpha1.RuntimeClass + err := ctx.RegisterResource("kubernetes:node.k8s.io/v1alpha1:RuntimeClass", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "node.k8s.io/v1beta1/RuntimeClass": + var res nodev1beta1.RuntimeClass + err := ctx.RegisterResource("kubernetes:node.k8s.io/v1beta1:RuntimeClass", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "policy/v1beta1/PodDisruptionBudget": + var res policyv1beta1.PodDisruptionBudget + err := ctx.RegisterResource("kubernetes:policy/v1beta1:PodDisruptionBudget", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "policy/v1beta1/PodSecurityPolicy": + var res policyv1beta1.PodSecurityPolicy + err := ctx.RegisterResource("kubernetes:policy/v1beta1:PodSecurityPolicy", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "rbac.authorization.k8s.io/v1/ClusterRole": + var res rbacv1.ClusterRole + err := ctx.RegisterResource("kubernetes:rbac.authorization.k8s.io/v1:ClusterRole", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "rbac.authorization.k8s.io/v1/ClusterRoleBinding": + var res rbacv1.ClusterRoleBinding + err := ctx.RegisterResource("kubernetes:rbac.authorization.k8s.io/v1:ClusterRoleBinding", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "rbac.authorization.k8s.io/v1/Role": + var res rbacv1.Role + err := ctx.RegisterResource("kubernetes:rbac.authorization.k8s.io/v1:Role", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "rbac.authorization.k8s.io/v1/RoleBinding": + var res rbacv1.RoleBinding + err := ctx.RegisterResource("kubernetes:rbac.authorization.k8s.io/v1:RoleBinding", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "rbac.authorization.k8s.io/v1alpha1/ClusterRole": + var res rbacv1alpha1.ClusterRole + err := ctx.RegisterResource("kubernetes:rbac.authorization.k8s.io/v1alpha1:ClusterRole", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "rbac.authorization.k8s.io/v1alpha1/ClusterRoleBinding": + var res rbacv1alpha1.ClusterRoleBinding + err := ctx.RegisterResource("kubernetes:rbac.authorization.k8s.io/v1alpha1:ClusterRoleBinding", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "rbac.authorization.k8s.io/v1alpha1/Role": + var res rbacv1alpha1.Role + err := ctx.RegisterResource("kubernetes:rbac.authorization.k8s.io/v1alpha1:Role", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "rbac.authorization.k8s.io/v1alpha1/RoleBinding": + var res rbacv1alpha1.RoleBinding + err := ctx.RegisterResource("kubernetes:rbac.authorization.k8s.io/v1alpha1:RoleBinding", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "rbac.authorization.k8s.io/v1beta1/ClusterRole": + var res rbacv1beta1.ClusterRole + err := ctx.RegisterResource("kubernetes:rbac.authorization.k8s.io/v1beta1:ClusterRole", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "rbac.authorization.k8s.io/v1beta1/ClusterRoleBinding": + var res rbacv1beta1.ClusterRoleBinding + err := ctx.RegisterResource("kubernetes:rbac.authorization.k8s.io/v1beta1:ClusterRoleBinding", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "rbac.authorization.k8s.io/v1beta1/Role": + var res rbacv1beta1.Role + err := ctx.RegisterResource("kubernetes:rbac.authorization.k8s.io/v1beta1:Role", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "rbac.authorization.k8s.io/v1beta1/RoleBinding": + var res rbacv1beta1.RoleBinding + err := ctx.RegisterResource("kubernetes:rbac.authorization.k8s.io/v1beta1:RoleBinding", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "scheduling.k8s.io/v1/PriorityClass": + var res schedulingv1.PriorityClass + err := ctx.RegisterResource("kubernetes:scheduling.k8s.io/v1:PriorityClass", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "scheduling.k8s.io/v1alpha1/PriorityClass": + var res schedulingv1alpha1.PriorityClass + err := ctx.RegisterResource("kubernetes:scheduling.k8s.io/v1alpha1:PriorityClass", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "scheduling.k8s.io/v1beta1/PriorityClass": + var res schedulingv1beta1.PriorityClass + err := ctx.RegisterResource("kubernetes:scheduling.k8s.io/v1beta1:PriorityClass", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "settings.k8s.io/v1alpha1/PodPreset": + var res settingsv1alpha1.PodPreset + err := ctx.RegisterResource("kubernetes:settings.k8s.io/v1alpha1:PodPreset", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "storage.k8s.io/v1/CSIDriver": + var res storagev1.CSIDriver + err := ctx.RegisterResource("kubernetes:storage.k8s.io/v1:CSIDriver", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "storage.k8s.io/v1/CSINode": + var res storagev1.CSINode + err := ctx.RegisterResource("kubernetes:storage.k8s.io/v1:CSINode", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "storage.k8s.io/v1/StorageClass": + var res storagev1.StorageClass + err := ctx.RegisterResource("kubernetes:storage.k8s.io/v1:StorageClass", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "storage.k8s.io/v1/VolumeAttachment": + var res storagev1.VolumeAttachment + err := ctx.RegisterResource("kubernetes:storage.k8s.io/v1:VolumeAttachment", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "storage.k8s.io/v1alpha1/VolumeAttachment": + var res storagev1alpha1.VolumeAttachment + err := ctx.RegisterResource("kubernetes:storage.k8s.io/v1alpha1:VolumeAttachment", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "storage.k8s.io/v1beta1/CSIDriver": + var res storagev1beta1.CSIDriver + err := ctx.RegisterResource("kubernetes:storage.k8s.io/v1beta1:CSIDriver", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "storage.k8s.io/v1beta1/CSINode": + var res storagev1beta1.CSINode + err := ctx.RegisterResource("kubernetes:storage.k8s.io/v1beta1:CSINode", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "storage.k8s.io/v1beta1/StorageClass": + var res storagev1beta1.StorageClass + err := ctx.RegisterResource("kubernetes:storage.k8s.io/v1beta1:StorageClass", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + case "storage.k8s.io/v1beta1/VolumeAttachment": + var res storagev1beta1.VolumeAttachment + err := ctx.RegisterResource("kubernetes:storage.k8s.io/v1beta1:VolumeAttachment", metaName, UntypedArgs(obj), &res, opts...) + if err != nil { + return nil, err + } + return []resourceTuple{{Name: key, Resource: &res}}, nil + default: + return nil, errors.Errorf("unrecognized kind %s %+v", fullKind, obj) + } +} diff --git a/tests/go.mod b/tests/go.mod index 3e44f39131..6faf5c64bc 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -10,8 +10,8 @@ replace ( require ( github.com/pulumi/pulumi-kubernetes/provider/v2 v2.0.0-00010101000000-000000000000 - github.com/pulumi/pulumi-kubernetes/sdk/v2 v2.0.0-00010101000000-000000000000 - github.com/pulumi/pulumi/pkg/v2 v2.1.0 - github.com/pulumi/pulumi/sdk/v2 v2.1.0 + github.com/pulumi/pulumi-kubernetes/sdk/v2 v2.0.0 + github.com/pulumi/pulumi/pkg/v2 v2.1.1-0.20200506045153-0e512aa0ef84 + github.com/pulumi/pulumi/sdk/v2 v2.1.1-0.20200506045153-0e512aa0ef84 github.com/stretchr/testify v1.5.1 ) diff --git a/tests/go.sum b/tests/go.sum index c213cf96a4..c4de0737f2 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -235,6 +235,8 @@ github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= +github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -485,12 +487,12 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/pulumi/pulumi/pkg/v2 v2.1.0 h1:L/gaZ4XQGLODxzXu1SVfIHUHWCR8ENO4mYQnpv6u+Go= -github.com/pulumi/pulumi/pkg/v2 v2.1.0/go.mod h1:NadTQy17wc69lQt/xTl5b6/fbl/tBiOPYMIZ+M/KtBI= +github.com/pulumi/pulumi/pkg/v2 v2.1.1-0.20200506045153-0e512aa0ef84 h1:IuN+CUhkLj7CwthEnWhifL25N4KRykiQEfKJXTI//mQ= +github.com/pulumi/pulumi/pkg/v2 v2.1.1-0.20200506045153-0e512aa0ef84/go.mod h1:hXaFYjGEnsQ7qGRJbCDhjuGh7sip3TsaOGNkU3ADt9s= github.com/pulumi/pulumi/sdk/v2 v2.0.0 h1:3VMXbEo3bqeaU+YDt8ufVBLD0WhLYE3tG3t/nIZ3Iac= github.com/pulumi/pulumi/sdk/v2 v2.0.0/go.mod h1:W7k1UDYerc5o97mHnlHHp5iQZKEby+oQrQefWt+2RF4= -github.com/pulumi/pulumi/sdk/v2 v2.1.0 h1:NZCLrvggMHlBzsaAcvChdDhQ5i9vJxARnLCY7NCFl18= -github.com/pulumi/pulumi/sdk/v2 v2.1.0/go.mod h1:W7k1UDYerc5o97mHnlHHp5iQZKEby+oQrQefWt+2RF4= +github.com/pulumi/pulumi/sdk/v2 v2.1.1-0.20200506045153-0e512aa0ef84 h1:6qDezDHciRcIKyhQQr/dA7numrfYmm3guPlQU6bYXp4= +github.com/pulumi/pulumi/sdk/v2 v2.1.1-0.20200506045153-0e512aa0ef84/go.mod h1:QNbWpL4gvf3X0lUFT7TXA2Jo1ff/Ti2l97AyFGYwvW4= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8= github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM= @@ -524,6 +526,8 @@ github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs= github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -578,6 +582,8 @@ go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= gocloud.dev v0.19.0 h1:EDRyaRAnMGSq/QBto486gWFxMLczAfIYUmusV7XLNBM= @@ -750,6 +756,7 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= diff --git a/tests/integration/go/go_test.go b/tests/integration/go/go_test.go index ad191c5d4f..fecc4a87eb 100644 --- a/tests/integration/go/go_test.go +++ b/tests/integration/go/go_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package ints +package test import ( "testing" @@ -21,12 +21,18 @@ import ( ) func TestGo_Basic(t *testing.T) { - t.Skip("temporarily skip while we make an initial release of the package") integration.ProgramTest(t, &integration.ProgramTestOptions{ Dir: "basic", Dependencies: []string{ - "github.com/pulumi/pulumi-kubernetes", + "github.com/pulumi/pulumi-kubernetes/sdk/v2", }, Quick: true, }) } + +func TestGo_YAML(t *testing.T) { + integration.ProgramTest(t, &integration.ProgramTestOptions{ + Dir: "yaml", + Quick: true, + }) +} diff --git a/tests/integration/go/yaml/Pulumi.yaml b/tests/integration/go/yaml/Pulumi.yaml new file mode 100644 index 0000000000..0a3395685c --- /dev/null +++ b/tests/integration/go/yaml/Pulumi.yaml @@ -0,0 +1,3 @@ +name: go_yaml_kubernetes +description: Test Kubernetes YAML package. +runtime: go diff --git a/tests/integration/go/yaml/go.mod b/tests/integration/go/yaml/go.mod new file mode 100644 index 0000000000..8217f647f6 --- /dev/null +++ b/tests/integration/go/yaml/go.mod @@ -0,0 +1,10 @@ +module github.com/pulumi/pulumi-kubernetes/provider/cmd/yaml-test + +go 1.14 + +require ( + github.com/pulumi/pulumi-kubernetes/sdk/v2 v2.0.0 + github.com/pulumi/pulumi/sdk/v2 v2.1.1-0.20200501175207-cca94a5a7113 +) + +replace github.com/pulumi/pulumi-kubernetes/sdk/v2 => ../github.com/pulumi/pulumi-kubernetes/sdk diff --git a/tests/integration/go/yaml/guestbook-all-in-one.yaml b/tests/integration/go/yaml/guestbook-all-in-one.yaml new file mode 100644 index 0000000000..b081367016 --- /dev/null +++ b/tests/integration/go/yaml/guestbook-all-in-one.yaml @@ -0,0 +1,147 @@ +apiVersion: v1 +kind: Service +metadata: + name: redis-master + labels: + app: redis + tier: backend + role: master +spec: + ports: + - port: 6379 + targetPort: 6379 + selector: + app: redis + tier: backend + role: master +--- +apiVersion: apps/v1 # for k8s versions before 1.9.0 use apps/v1beta2 and before 1.8.0 use extensions/v1beta1 +kind: Deployment +metadata: + name: redis-master +spec: + selector: + matchLabels: + app: redis + role: master + tier: backend + replicas: 1 + template: + metadata: + labels: + app: redis + role: master + tier: backend + spec: + containers: + - name: master + image: k8s.gcr.io/redis:e2e # or just image: redis + resources: + requests: + cpu: 100m + memory: 100Mi + ports: + - containerPort: 6379 +--- +apiVersion: v1 +kind: Service +metadata: + name: redis-slave + labels: + app: redis + tier: backend + role: slave +spec: + ports: + - port: 6379 + selector: + app: redis + tier: backend + role: slave +--- +apiVersion: apps/v1 # for k8s versions before 1.9.0 use apps/v1beta2 and before 1.8.0 use extensions/v1beta1 +kind: Deployment +metadata: + name: redis-slave +spec: + selector: + matchLabels: + app: redis + role: slave + tier: backend + replicas: 2 + template: + metadata: + labels: + app: redis + role: slave + tier: backend + spec: + containers: + - name: slave + image: gcr.io/google_samples/gb-redisslave:v1 + resources: + requests: + cpu: 100m + memory: 100Mi + env: + - name: GET_HOSTS_FROM + value: dns + # If your cluster config does not include a dns service, then to + # instead access an environment variable to find the master + # service's host, comment out the 'value: dns' line above, and + # uncomment the line below: + # value: env + ports: + - containerPort: 6379 +--- +apiVersion: v1 +kind: Service +metadata: + name: frontend + labels: + app: guestbook + tier: frontend +spec: + # if your cluster supports it, uncomment the following to automatically create + # an external load-balanced IP for the frontend service. + # type: LoadBalancer + ports: + - port: 80 + selector: + app: guestbook + tier: frontend +--- +apiVersion: apps/v1 # for k8s versions before 1.9.0 use apps/v1beta2 and before 1.8.0 use extensions/v1beta1 +kind: Deployment +metadata: + name: frontend +spec: + selector: + matchLabels: + app: guestbook + tier: frontend + replicas: 3 + template: + metadata: + labels: + app: guestbook + tier: frontend + spec: + containers: + - name: php-redis + image: gcr.io/google-samples/gb-frontend:v4 + resources: + requests: + cpu: 100m + memory: 100Mi + env: + - name: GET_HOSTS_FROM + value: dns + # If your cluster config does not include a dns service, then to + # instead access environment variables to find service host + # info, comment out the 'value: dns' line above, and uncomment the + # line below: + # value: env + ports: + - containerPort: 80 diff --git a/tests/integration/go/yaml/main.go b/tests/integration/go/yaml/main.go new file mode 100644 index 0000000000..6659d225b2 --- /dev/null +++ b/tests/integration/go/yaml/main.go @@ -0,0 +1,48 @@ +package main + +import ( + "path/filepath" + + corev1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/core/v1" + "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/yaml" + "github.com/pulumi/pulumi/sdk/v2/go/pulumi" +) + +func main() { + pulumi.Run(func(ctx *pulumi.Context) error { + _, err := yaml.NewConfigFile(ctx, "guestbook", + &yaml.ConfigFileArgs{File: "guestbook-all-in-one.yaml"}, + ) + if err != nil { + return err + } + + resources, err := yaml.NewConfigGroup(ctx, "manifests", + &yaml.ConfigGroupArgs{ + Files: []string{filepath.Join("manifests", "*.yaml")}, + Transformations: []yaml.Transformation{ + func(state map[string]interface{}, opts ...pulumi.ResourceOption) { + if state["apiVersion"] == "v1" && state["kind"] == "Pod" { + metadata := state["metadata"].(map[string]interface{}) + _, ok := metadata["labels"] + if !ok { + metadata["labels"] = map[string]string{"foo": "bar"} + } else { + labels := metadata["labels"].(map[string]string) + labels["foo"] = "bar" + } + } + }, + }, + }, + ) + if err != nil { + return err + } + + hostIP := resources.GetResource("v1/Pod", "foo", "").(*corev1.Pod).Status.HostIP() + ctx.Export("hostIP", hostIP) + + return nil + }) +} diff --git a/tests/integration/go/yaml/manifests/pod.yaml b/tests/integration/go/yaml/manifests/pod.yaml new file mode 100644 index 0000000000..3e76ab5734 --- /dev/null +++ b/tests/integration/go/yaml/manifests/pod.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Pod +metadata: + name: foo +spec: + containers: + - name: nginx + image: nginx:1.15-alpine diff --git a/tests/integration/go/yaml/manifests/podList.yaml b/tests/integration/go/yaml/manifests/podList.yaml new file mode 100644 index 0000000000..151daa6d0d --- /dev/null +++ b/tests/integration/go/yaml/manifests/podList.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: PodList +items: + - apiVersion: v1 + kind: Pod + metadata: + name: bar + spec: + containers: + - name: nginx + image: nginx:1.15-alpine + - apiVersion: v1 + kind: Pod + metadata: + name: baz + spec: + containers: + - name: nginx + image: nginx:1.15-alpine