Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add a Go SDK #1029

Merged
merged 52 commits into from
Mar 21, 2020
Merged
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
5b96865
WIP: schema-based codegen
pgavlin Jan 13, 2020
7f5f4e7
Add GetSchema stub
lblackstone Feb 28, 2020
62038cd
WIP
lblackstone Mar 2, 2020
2a5c7d4
WIP
lblackstone Mar 2, 2020
58f9bc0
WIP aliasing
lblackstone Mar 3, 2020
33d30cd
Cleanup pulumi-gen-kubernetes
lblackstone Mar 3, 2020
25fc425
Update package schema
lblackstone Mar 3, 2020
d852a6c
Change URN for apiregistration resources
lblackstone Mar 5, 2020
db9595a
WIP
lblackstone Mar 5, 2020
538d4d4
Almost working
lblackstone Mar 7, 2020
20e1889
Fix meta typing
lblackstone Mar 9, 2020
f7c8ec5
More fixes
lblackstone Mar 9, 2020
f974a24
WIP
lblackstone Mar 9, 2020
6969a0e
More fixes
lblackstone Mar 9, 2020
727a8c7
Remove old files
lblackstone Mar 9, 2020
f9a374a
Fix schema pkg name
lblackstone Mar 10, 2020
b56781f
Fix import sort order
lblackstone Mar 10, 2020
1a8319a
Formatting
lblackstone Mar 10, 2020
a3ddeba
Run goimport on SDK files
lblackstone Mar 10, 2020
f7c64ec
Fixed imports
lblackstone Mar 10, 2020
1acd192
Add apiVersion and kind to all resources
lblackstone Mar 10, 2020
9fe1dde
Add a test
lukehoban Mar 12, 2020
ee41c52
Support running Go-based test
lukehoban Mar 12, 2020
63163ac
Add a CHANGELOG entry
lukehoban Mar 12, 2020
4948d86
Updates from pulumi/pulumi
lblackstone Mar 17, 2020
1d212ff
Pin to upstream pulumi/pulumi commit
lblackstone Mar 17, 2020
e37e0a7
Fix merge conflict
lblackstone Mar 17, 2020
a6d476b
Fix test name
lblackstone Mar 17, 2020
e9ee163
WIP
lblackstone Mar 18, 2020
9681b8f
Fix lint warnings
lblackstone Mar 18, 2020
0119c62
Fix more lint issues
lblackstone Mar 18, 2020
38941aa
Fix regression
lblackstone Mar 18, 2020
534a59c
Pin to Luke's no_Type_suffix commit
lblackstone Mar 19, 2020
a3b52ad
Pull in pulumi/pulumi codegen fixes
lblackstone Mar 19, 2020
e45050b
Bump p/p tag to merged commit
lblackstone Mar 19, 2020
0f69453
hack: ignore pulumiManifest.go files
lblackstone Mar 19, 2020
2bf94c3
Split linting per-directory
lblackstone Mar 19, 2020
e11fa81
Adjust linter opts
lblackstone Mar 19, 2020
0dee26d
Lower linter concurrency again
lblackstone Mar 19, 2020
251f6eb
And again
lblackstone Mar 19, 2020
71ede0b
And yet again
lblackstone Mar 19, 2020
0bd39a0
Again
lblackstone Mar 19, 2020
0b354ec
Try updating to newer linter release
lblackstone Mar 19, 2020
fa313ad
Tweak linter settings again
lblackstone Mar 19, 2020
52b6390
Again
lblackstone Mar 19, 2020
ed1a904
Still timing out
lblackstone Mar 19, 2020
9a05ada
Try with default opts and longer deadline
lblackstone Mar 19, 2020
5d70fb9
Add link to issue tracking golangci-lint update
lblackstone Mar 20, 2020
f98aa73
Address feedback
lblackstone Mar 20, 2020
b88a349
Merge branch 'master' into lukehoban/schema
lblackstone Mar 20, 2020
10cbbf9
Merge branch 'master' into lukehoban/schema
lblackstone Mar 21, 2020
5babcde
Don't need to check in schema.json
lblackstone Mar 21, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ before_install:
install:
- source ${PULUMI_SCRIPTS}/ci/install-common-toolchain.sh

# Try using a newer version of golangci-lint
- curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b "$(go env GOPATH)/bin" "v1.24.0"

# Install Helm CLI. Do not install Tiller.
- curl -LO https://get.helm.sh/helm-v3.0.0-linux-amd64.tar.gz
- tar -xvf helm-v3.0.0-linux-amd64.tar.gz
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## HEAD (Unreleased)

### Improvements

- Add a Go SDK. (https://github.com/pulumi/pulumi-kubernetes/pull/1029).

## 1.5.8 (March 16, 2020)

### Improvements
Expand All @@ -11,6 +15,7 @@

### Bug fixes

- Change URN for apiregistration resources. (https://github.com/pulumi/pulumi-kubernetes/pull/1021).
- Replace PersistentVolume if volume source changes. (https://github.com/pulumi/pulumi-kubernetes/pull/1015).
- Fix bool Python provider opts. (https://github.com/pulumi/pulumi-kubernetes/pull/1027).

Expand Down
6 changes: 4 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ build:: $(OPENAPI_FILE)
$(GO) install $(VERSION_FLAGS) $(PROJECT)/cmd/$(CODEGEN)
# Delete only files and folders that are generated.
rm -r sdk/python/pulumi_kubernetes/*/ sdk/python/pulumi_kubernetes/__init__.py
for LANGUAGE in "dotnet" "nodejs" "python" ; do \
for LANGUAGE in "dotnet" "go" "nodejs" "python"; do \
$(CODEGEN) $$LANGUAGE $(OPENAPI_FILE) pkg/gen/$${LANGUAGE}-templates $(PACKDIR) || exit 3 ; \
done
cd ${PACKDIR}/nodejs/ && \
Expand All @@ -66,7 +66,9 @@ build:: $(OPENAPI_FILE)
dotnet build /p:Version=${DOTNET_VERSION}

lint::
golangci-lint run
for DIR in "cmd" "pkg" "sdk" "tests" ; do \
pushd $$DIR && golangci-lint run -c ../.golangci.yml --deadline 10m && popd ; \
done

install::
GOBIN=$(PULUMI_BIN) $(GO) install $(VERSION_FLAGS) $(PROJECT)/cmd/$(PROVIDER)
Expand Down
33 changes: 33 additions & 0 deletions cmd/pulumi-gen-kubernetes/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ package main

import (
"fmt"
gogen "github.com/pulumi/pulumi/pkg/codegen/go"
"github.com/pulumi/pulumi/pkg/codegen/schema"
"io/ioutil"
"log"
"os"
Expand Down Expand Up @@ -70,6 +72,8 @@ func main() {
writePythonClient(data, outdir, templateDir)
case "dotnet":
writeDotnetClient(data, outdir, templateDir)
case "go":
writeGoClient(data, outdir)
default:
panic(fmt.Sprintf("Unrecognized language '%s'", language))
}
Expand Down Expand Up @@ -307,3 +311,32 @@ func writeDotnetClient(data map[string]interface{}, outdir, templateDir string)
panic(err)
}
}

func writeGoClient(data map[string]interface{}, outdir string) {
pkg := writePulumiSchema(data)
files, err := gogen.GeneratePackage("pulumigen", pkg)
if err != nil {
panic(err)
}
for filename, contents := range files {
//filename = strings.TrimPrefix(filename, "kubernetes/")
lblackstone marked this conversation as resolved.
Show resolved Hide resolved
path := filepath.Join(outdir, filename)

if err = os.MkdirAll(filepath.Dir(path), 0755); err != nil {
panic(err)
}
err := ioutil.WriteFile(path, contents, 0644)
if err != nil {
panic(err)
}
}
}

func writePulumiSchema(data map[string]interface{}) *schema.Package {
pkgSpec := gen.PulumiSchema(data)
pkg, err := schema.ImportSpec(pkgSpec)
if err != nil {
panic(err)
}
return pkg
}
7 changes: 3 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,11 @@ require (
github.com/golang/protobuf v1.3.2
github.com/googleapis/gnostic v0.2.0
github.com/imdario/mergo v0.3.8
github.com/jinzhu/copier v0.0.0-20180308034124-7e38e58719c3
github.com/mitchellh/go-wordwrap v1.0.0
github.com/pkg/errors v0.8.1
github.com/pulumi/pulumi v1.6.1
github.com/pkg/errors v0.9.1
github.com/pulumi/pulumi v1.13.1-0.20200319153240-65899569ee27
github.com/stretchr/testify v1.4.1-0.20191106224347-f1bd0923b832
google.golang.org/grpc v1.21.1
google.golang.org/grpc v1.27.1
k8s.io/api v0.17.0
k8s.io/apimachinery v0.17.0
k8s.io/client-go v0.17.0
Expand Down
47 changes: 43 additions & 4 deletions go.sum

Large diffs are not rendered by default.

250 changes: 250 additions & 0 deletions pkg/gen/schema.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
// Copyright 2016-2018, 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.

//nolint: goconst
package gen

import (
"encoding/json"
"fmt"
"strings"

providerVersion "github.com/pulumi/pulumi-kubernetes/pkg/version"

pschema "github.com/pulumi/pulumi/pkg/codegen/schema"
"github.com/pulumi/pulumi/pkg/util/contract"
)

// PulumiSchema will generate a Pulumi schema for the given k8s schema.
func PulumiSchema(swagger map[string]interface{}) pschema.PackageSpec {
pkg := pschema.PackageSpec{
Name: "kubernetes",
Version: providerVersion.Version,
Description: "A Pulumi package for creating and managing Kubernetes resources.",
License: "Apache-2.0",
Keywords: []string{"pulumi", "kubernetes"},
Homepage: "https://pulumi.com",
Repository: "https://github.com/pulumi/pulumi-kubernetes",

Config: pschema.ConfigSpec{
Variables: map[string]pschema.PropertySpec{
"kubeconfig": {
Description: "The contents of a kubeconfig file. If this is set, this config will be used instead of $KUBECONFIG.",
TypeSpec: pschema.TypeSpec{Type: "string"},
},
"context": {
Description: "If present, the name of the kubeconfig context to use.",
TypeSpec: pschema.TypeSpec{Type: "string"},
},
"cluster": {
Description: "If present, the name of the kubeconfig cluster to use.",
TypeSpec: pschema.TypeSpec{Type: "string"},
},
"namespace": {
Description: "If present, the default namespace to use. This flag is ignored for cluster-scoped resources.\n\nA namespace can be specified in multiple places, and the precedence is as follows:\n1. `.metadata.namespace` set on the resource.\n2. This `namespace` parameter.\n3. `namespace` set for the active context in the kubeconfig.",
TypeSpec: pschema.TypeSpec{Type: "string"},
},
"enableDryRun": {
Description: "BETA FEATURE - If present and set to true, enable server-side diff calculations.\nThis feature is in developer preview, and is disabled by default.\n\nThis config can be specified in the following ways, using this precedence:\n1. This `enableDryRun` parameter.\n2. The `PULUMI_K8S_ENABLE_DRY_RUN` environment variable.",
TypeSpec: pschema.TypeSpec{Type: "boolean"},
},
"suppressDeprecationWarnings": {
Description: "If present and set to true, suppress apiVersion deprecation warnings from the CLI.\n\nThis config can be specified in the following ways, using this precedence:\n1. This `suppressDeprecationWarnings` parameter.\n2. The `PULUMI_K8S_SUPPRESS_DEPRECATION_WARNINGS` environment variable.",
TypeSpec: pschema.TypeSpec{Type: "boolean"},
},
},
},

Provider: pschema.ResourceSpec{
ObjectTypeSpec: pschema.ObjectTypeSpec{
Description: "The provider type for the kubernetes package.",
Type: "object",
},
InputProperties: map[string]pschema.PropertySpec{
"kubeconfig": {
Description: "The contents of a kubeconfig file. If this is set, this config will be used instead of $KUBECONFIG.",
TypeSpec: pschema.TypeSpec{Type: "string"},
},
"context": {
Description: "If present, the name of the kubeconfig context to use.",
TypeSpec: pschema.TypeSpec{Type: "string"},
},
"cluster": {
Description: "If present, the name of the kubeconfig cluster to use.",
TypeSpec: pschema.TypeSpec{Type: "string"},
},
"namespace": {
Description: "If present, the default namespace to use. This flag is ignored for cluster-scoped resources.\n\nA namespace can be specified in multiple places, and the precedence is as follows:\n1. `.metadata.namespace` set on the resource.\n2. This `namespace` parameter.\n3. `namespace` set for the active context in the kubeconfig.",
TypeSpec: pschema.TypeSpec{Type: "string"},
},
"enableDryRun": {
Description: "BETA FEATURE - If present and set to true, enable server-side diff calculations.\nThis feature is in developer preview, and is disabled by default.\n\nThis config can be specified in the following ways, using this precedence:\n1. This `enableDryRun` parameter.\n2. The `PULUMI_K8S_ENABLE_DRY_RUN` environment variable.",
TypeSpec: pschema.TypeSpec{Type: "boolean"},
},
"suppressDeprecationWarnings": {
Description: "If present and set to true, suppress apiVersion deprecation warnings from the CLI.\n\nThis config can be specified in the following ways, using this precedence:\n1. This `suppressDeprecationWarnings` parameter.\n2. The `PULUMI_K8S_SUPPRESS_DEPRECATION_WARNINGS` environment variable.",
TypeSpec: pschema.TypeSpec{Type: "boolean"},
},
},
},

Types: map[string]pschema.ObjectTypeSpec{},
Resources: map[string]pschema.ResourceSpec{},
Functions: map[string]pschema.FunctionSpec{},
Language: map[string]json.RawMessage{
"nodejs": rawMessage(map[string]interface{}{
"dependencies": map[string]string{
"@pulumi/pulumi": "^1.11.0",
"shell-quote": "^1.6.1",
"tmp": "^0.0.33",
"@types/tmp": "^0.0.33",
"glob": "^7.1.2",
"@types/glob": "^5.0.35",
"node-fetch": "^2.3.0",
"@types/node-fetch": "^2.1.4",
},
"devDependencies": map[string]string{
"mocha": "^5.2.0",
"@types/mocha": "^5.2.5",
"@types/shell-quote": "^1.6.0",
},
}),
"python": rawMessage(map[string]interface{}{
"requires": map[string]string{
"pulumi": ">=1.11.0,<2.0.0",
"requests": ">=2.21.0,<2.22.0",
"pyyaml": ">=5.1,<5.2",
"semver": ">=2.8.1",
"parver": ">=0.2.1",
},
}),
},
}

goImportPath := "github.com/pulumi/pulumi-kubernetes/sdk/go/kubernetes"

csharpNamespaces := map[string]string{}
modToPkg := map[string]string{}
pkgImportAliases := map[string]string{}

definitions := swagger["definitions"].(map[string]interface{})
groupsSlice := createGroups(definitions, schemaOpts())
for _, group := range groupsSlice {
for _, version := range group.Versions() {
mod := version.gv.String()
csharpNamespaces[mod] = fmt.Sprintf("%s.%s", pascalCase(group.Group()), pascalCase(version.Version()))

for _, kind := range version.Kinds() {
tok := fmt.Sprintf(`kubernetes:%s:%s`, kind.canonicalGV, kind.kind)

modToPkg[kind.canonicalGV] = kind.schemaPkgName
pkgImportAliases[fmt.Sprintf("%s/%s", goImportPath, kind.schemaPkgName)] = strings.Replace(
kind.schemaPkgName, "/", "", -1)

objectSpec := pschema.ObjectTypeSpec{
Description: kind.Comment(),
Type: "object",
Properties: map[string]pschema.PropertySpec{},
}

for _, p := range kind.Properties() {
// JSONSchema type includes `$ref` and `$schema` properties, and $ is an invalid character in
// the generated names.
if strings.HasPrefix(p.name, "$") {
p.name = "t_" + p.name[1:]
}
objectSpec.Properties[p.name] = genPropertySpec(p, kind.canonicalGV, kind.kind)
//objectSpec.Required = append(objectSpec.Required, p.name)
}

pkg.Types[tok] = objectSpec
if kind.IsNested() {
continue
}

resourceSpec := pschema.ResourceSpec{
ObjectTypeSpec: objectSpec,
DeprecationMessage: kind.DeprecationComment(),
InputProperties: map[string]pschema.PropertySpec{},
}

for _, p := range kind.RequiredInputProperties() {
resourceSpec.InputProperties[p.name] = genPropertySpec(p, kind.canonicalGV, kind.kind)
resourceSpec.RequiredInputs = append(resourceSpec.RequiredInputs, p.name)
}
for _, p := range kind.OptionalInputProperties() {
resourceSpec.InputProperties[p.name] = genPropertySpec(p, kind.canonicalGV, kind.kind)
}

for _, t := range kind.Aliases() {
aliasedType := t
resourceSpec.Aliases = append(resourceSpec.Aliases, pschema.AliasSpec{Type: &aliasedType})
}

pkg.Resources[tok] = resourceSpec
}
}
}

pkg.Language["csharp"] = rawMessage(map[string]interface{}{
"packageReferences": map[string]string{
"Pulumi": "1.7.0-preview-alpha.1574743805",
"System.Collections.Immutable": "1.6.0",
},
"namespaces": csharpNamespaces,
})
pkg.Language["go"] = rawMessage(map[string]interface{}{
"importBasePath": goImportPath,
"moduleToPackage": modToPkg,
"packageImportAliases": pkgImportAliases,
})

return pkg
}

func genPropertySpec(p Property, resourceGV string, resourceKind string) pschema.PropertySpec {
var typ pschema.TypeSpec
err := json.Unmarshal([]byte(p.ProviderType()), &typ)
contract.Assert(err == nil)

defaultValue := func() *string {
if p.name == "apiVersion" {
if strings.HasPrefix(resourceGV, "core/") {
dv := strings.TrimPrefix(resourceGV, "core/")
return &dv
}
return &resourceGV
}
if p.name == "kind" {
return &resourceKind
}

return nil
}

propertySpec := pschema.PropertySpec{
Description: p.Comment(),
TypeSpec: typ,
}
if dv := defaultValue(); dv != nil {
propertySpec.Default = *dv
}
return propertySpec
}

func rawMessage(v interface{}) json.RawMessage {
bytes, err := json.Marshal(v)
contract.Assert(err == nil)
return json.RawMessage(bytes)
}
Loading