Merge branch 'master' of https://github.com/pulumi/pulumi into evan/auto

This commit is contained in:
evanboyle 2020-08-24 17:51:40 -07:00
commit 463c7b6588
132 changed files with 50613 additions and 976 deletions

29
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View file

@ -0,0 +1,29 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: needs-triage
assignees: ''
---
<!--- Provide a general summary of the issue -->
## Expected Behavior
<!--- Tell us what should happen -->
## Current Behavior
<!--- Tell us what happens instead of the expected behavior -->
## Steps to Reproduce
<!--- Provide a link to a live example, or an unambiguous set of steps to -->
<!--- reproduce this bug. Include code to reproduce, if relevant -->
1.
2.
3.
4.
## Context (Environment)
<!--- How has this issue affected you? What are you trying to accomplish? -->
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
<!--- Provide a general summary of the issue in the Title above -->

View file

@ -4,6 +4,8 @@ on:
paths:
- 'pkg/codegen/**'
- '.github/workflows/codegen-test.yml'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
downstream-aws:
@ -24,6 +26,10 @@ jobs:
python-version: 3.6.11
- name: Install Pulumi CLI
uses: pulumi/action-install-pulumi-cli@releases/v1
- name: Install pulumictl
uses: jaxxstorm/action-install-gh-release@release/v1-alpha
with:
repo: pulumi/pulumictl
- name: Check out source code
uses: actions/checkout@master
@ -57,6 +63,10 @@ jobs:
python-version: 3.6.11
- name: Install Pulumi CLI
uses: pulumi/action-install-pulumi-cli@releases/v1
- name: Install pulumictl
uses: jaxxstorm/action-install-gh-release@release/v1-alpha
with:
repo: pulumi/pulumictl
- name: Check out source code
uses: actions/checkout@master
@ -90,6 +100,10 @@ jobs:
python-version: 3.6.11
- name: Install Pulumi CLI
uses: pulumi/action-install-pulumi-cli@releases/v1
- name: Install pulumictl
uses: jaxxstorm/action-install-gh-release@release/v1-alpha
with:
repo: pulumi/pulumictl
- name: Check out source code
uses: actions/checkout@master
@ -123,6 +137,10 @@ jobs:
python-version: 3.6.11
- name: Install Pulumi CLI
uses: pulumi/action-install-pulumi-cli@releases/v1
- name: Install pulumictl
uses: jaxxstorm/action-install-gh-release@release/v1-alpha
with:
repo: pulumi/pulumictl
- name: Check out source code
uses: actions/checkout@master
@ -156,6 +174,10 @@ jobs:
python-version: 3.6.11
- name: Install Pulumi CLI
uses: pulumi/action-install-pulumi-cli@releases/v1
- name: Install pulumictl
uses: jaxxstorm/action-install-gh-release@release/v1-alpha
with:
repo: pulumi/pulumictl
- name: Check out source code
uses: actions/checkout@master
@ -189,6 +211,10 @@ jobs:
python-version: 3.6.11
- name: Install Pulumi CLI
uses: pulumi/action-install-pulumi-cli@releases/v1
- name: Install pulumictl
uses: jaxxstorm/action-install-gh-release@release/v1-alpha
with:
repo: pulumi/pulumictl
- name: Check out source code
uses: actions/checkout@master

21
.github/workflows/homebrew-bump.yml vendored Normal file
View file

@ -0,0 +1,21 @@
env:
GITHUB_TOKEN: ${{ secrets.PULUMI_BOT_TOKEN }}
VERSION: ${{ github.event.client_payload.ref }}
COMMIT_SHA: ${{ github.event.client_payload.commitSha }}
on:
repository_dispatch:
types:
- homebrew-bump
jobs:
homebrew:
name: Bump Homebrew formula
runs-on: ubuntu-latest
steps:
- uses: dawidd6/action-homebrew-bump-formula@v3
with:
token: ${{secrets.GITHUB_TOKEN}}
formula: pulumi
tag: ${{env.VERSION}}
revision: ${{env.COMMIT_SHA}}

View file

@ -44,7 +44,7 @@ jobs:
run: |
echo "::set-env name=PULUMI_TEST_OWNER::moolumi"
echo "::set-env name=PULUMI_LOCAL_NUGET::D:\\Pulumi\\nuget"
echo "::set-env name=PULUMI_ACCESS_TOKEN::${{ secrets.PULUMI_ACCESS_TOKEN }}"
echo "::set-env name=PULUMI_API::https://api.pulumi-staging.io"
echo "::set-env name=PULUMI_ACCESS_TOKEN::${{ secrets.PULUMI_ACCESS_TOKEN }}"
echo "::add-path::D:\\Pulumi\\bin"
- name: Install AWS CLI Tools

View file

@ -40,7 +40,7 @@ jobs:
run: |
echo "::set-env name=PULUMI_TEST_OWNER::moolumi"
echo "::set-env name=PULUMI_LOCAL_NUGET::D:\\Pulumi\\nuget"
echo "::set-env name=PULUMI_ACCESS_TOKEN::${{ secrets.PULUMI_ACCESS_TOKEN }}"
echo "::set-env name=PULUMI_API::https://api.pulumi-staging.io"
echo "::set-env name=PULUMI_ACCESS_TOKEN::${{ secrets.PULUMI_ACCESS_TOKEN }}"
echo "::add-path::D:\\Pulumi\\bin"
- name: Set AWS Env Vars

View file

@ -2,12 +2,87 @@ CHANGELOG
=========
## HEAD (Unreleased)
_(none)
## 2.9.0 (2020-08-19)
- Fix support for CheckFailures in Python Dynamic Providers
[#5138](https://github.com/pulumi/pulumi/pull/5138)
- Upgrade version of `gocloud.dev`. This ensures that 'AWSKMS' secrets
providers can now be used with full ARNs rather than just Aliases
[#5138](https://github.com/pulumi/pulumi/pull/5138)
- Ensure the 'history' command is a subcommand of 'stack'.
This means that `pulumi history` has been deprecated in favour
of `pulumi stack history`.
[#5158](https://github.com/pulumi/pulumi/pull/5158)
- Add support for extracting jar files in archive resources
[#5150](https://github.com/pulumi/pulumi/pull/5150)
- SDK changes to support Python input/output classes
[#5033](https://github.com/pulumi/pulumi/pull/5033)
## 2.8.2 (2020-08-07)
- Add nuget badge to README [#5117](https://github.com/pulumi/pulumi/pull/5117)
- Support publishing and consuming Policy Packs using any runtime
[#5102](https://github.com/pulumi/pulumi/pull/5102)
- Fix regression where any CLI integration for any stack with a default
secrets provider would sort the config alphabetically and new stacks created
would get created with an empty map `{}` in the config file
[#5132](https://github.com/pulumi/pulumi/pull/5132)
## 2.8.1 (2020-08-05)
- Fix a bug where passphrase managers were not being
recognised correctly when getting the configuration
for the current stack.
**Please Note:**
This specific bug may have caused the stack config
file to remove the password encryption salt.
[#5110](https://github.com/pulumi/pulumi/pull/5110)
## 2.8.0 (2020-08-04)
- Add missing MapMap and ArrayArray types to Go SDK
[#5092](https://github.com/pulumi/pulumi/pull/5092)
- Switch os/user package with luser drop in replacement
[#5065](https://github.com/pulumi/pulumi/pull/5065)
- Update pip/setuptools/wheel in virtual environment before installing dependencies
[#5042](https://github.com/pulumi/pulumi/pull/5042)
- Add ability to change a secrets provider for the current stack
[#5031](https://github.com/pulumi/pulumi/pull/5031)
- Add ability to create a stack based on the config from an existing stack
[#5062](https://github.com/pulumi/pulumi/pull/5062)
- Python: Improved error message when `virtualenv` doesn't exist
[#5069](https://github.com/pulumi/pulumi/pull/5069)
- Enable pushing to Artifact Registry in actions
[#5075](https://github.com/pulumi/pulumi/pull/5075)
## 2.7.1 (2020-07-22)
- Fix logic to parse pulumi venv on github action
[5038](https://github.com/pulumi/pulumi/pull/5038)
## 2.7.0 (2020-07-22)
- Add pluginDownloadURL field to package definition
[#4947](https://github.com/pulumi/pulumi/pull/4947)
- Add support for streamInvoke during update
[#4990](https://github.com/pulumi/pulumi/pull/4990)
- Add ability to copy configuration values between stacks
[#4971](https://github.com/pulumi/pulumi/pull/4971)

View file

@ -5,6 +5,7 @@
[![Slack](http://www.pulumi.com/images/docs/badges/slack.svg)](https://slack.pulumi.com?utm_campaign=pulumi-pulumi-github-repo&utm_source=github.com&utm_medium=slack-badge)
[![NPM version](https://badge.fury.io/js/%40pulumi%2Fpulumi.svg)](https://npmjs.com/package/@pulumi/pulumi)
[![Python version](https://badge.fury.io/py/pulumi.svg)](https://pypi.org/project/pulumi)
[![NuGet version](https://badge.fury.io/nu/pulumi.svg)](https://badge.fury.io/nu/pulumi)
[![GoDoc](https://godoc.org/github.com/pulumi/pulumi?status.svg)](https://godoc.org/github.com/pulumi/pulumi)
[![License](https://img.shields.io/npm/l/%40pulumi%2Fpulumi.svg)](https://github.com/pulumi/pulumi/blob/master/LICENSE)

View file

@ -88,7 +88,7 @@ if [ ! -z "$GOOGLE_CREDENTIALS" ]; then
echo "$GOOGLE_CREDENTIALS" > $GOOGLE_APPLICATION_CREDENTIALS
fi
gcloud auth activate-service-account --key-file=$GOOGLE_APPLICATION_CREDENTIALS
gcloud --quiet auth configure-docker
gcloud --quiet auth configure-docker $GOOGLE_DOCKER_HOSTNAME_LIST
fi
# Next, run npm install. We always call this, as
@ -121,12 +121,12 @@ if [ -e requirements.txt ]; then
# Check if should use venv
PULUMI_VENV=$(cat Pulumi.yaml | grep "virtualenv:" | cut -d':' -f2)
if [ -z $PULUMI_VENV ]; then
pip3 install -r requirements.txt
else
python3 -m venv $PULUMI_VENV
source $PULUMI_VENV/bin/activate
pip3 install -r requirements.txt
deactivate
else
pip3 install -r requirements.txt
fi
fi

View file

@ -18,9 +18,9 @@ import (
"context"
"encoding/json"
"fmt"
user "github.com/tweekmonster/luser"
"net/url"
"os"
"os/user"
"path"
"path/filepath"
"regexp"

View file

@ -1,7 +1,7 @@
package filestate
import (
"os/user"
user "github.com/tweekmonster/luser"
"path/filepath"
"runtime"
"testing"

View file

@ -185,19 +185,15 @@ func (pack *cloudPolicyPack) Publish(
return result.FromError(
errors.Wrap(err, "could not publish policies because of error running npm pack"))
}
} else if strings.EqualFold(runtime, "python") {
} else {
// npm pack puts all the files in a "package" subdirectory inside the .tgz it produces, so we'll do
// the same for Python. That way, after unpacking, we can look for the PulumiPolicy.yaml inside the
// the same for other runtimes. That way, after unpacking, we can look for the PulumiPolicy.yaml inside the
// package directory to determine the runtime of the policy pack.
packTarball, err = archive.TGZ(op.PlugCtx.Pwd, "package", true /*useDefaultExcludes*/)
if err != nil {
return result.FromError(
errors.Wrap(err, "could not publish policies because of error creating the .tgz"))
}
} else {
return result.Errorf(
"failed to publish policies because PulumiPolicy.yaml specifies an unsupported runtime %s",
runtime)
}
//
@ -298,12 +294,19 @@ func installRequiredPolicy(finalDir string, tarball []byte) error {
// TODO[pulumi/pulumi#1334]: move to the language plugins so we don't have to hard code here.
if strings.EqualFold(proj.Runtime.Name(), "nodejs") {
return completeNodeJSInstall(finalDir)
if err := completeNodeJSInstall(finalDir); err != nil {
return err
}
} else if strings.EqualFold(proj.Runtime.Name(), "python") {
return completePythonInstall(finalDir, projPath, proj)
if err := completePythonInstall(finalDir, projPath, proj); err != nil {
return err
}
}
return errors.Errorf("unsupported policy runtime %s", proj.Runtime.Name())
fmt.Println("Finished installing policy pack")
fmt.Println()
return nil
}
func completeNodeJSInstall(finalDir string) error {
@ -314,8 +317,6 @@ func completeNodeJSInstall(finalDir string) error {
"in %q before this policy pack works", bin, finalDir)
}
fmt.Println("Finished installing policy pack")
fmt.Println()
return nil
}
@ -331,7 +332,5 @@ func completePythonInstall(finalDir, projPath string, proj *workspace.PolicyPack
return err
}
fmt.Println("Finished installing policy pack")
fmt.Println()
return nil
}

View file

@ -61,11 +61,11 @@ func getStackSecretsManager(s backend.Stack) (secrets.Manager, error) {
return newPassphraseSecretsManager(s.Ref().Name(), stackConfigFile)
}
switch stack := s.(type) {
case httpstate.Stack:
return newServiceSecretsManager(stack)
switch s.(type) {
case filestate.Stack:
return newPassphraseSecretsManager(s.Ref().Name(), stackConfigFile)
case httpstate.Stack:
return newServiceSecretsManager(s.(httpstate.Stack), s.Ref().Name(), stackConfigFile)
}
return nil, errors.Errorf("unknown stack type %s", reflect.TypeOf(s))

View file

@ -18,11 +18,69 @@ import (
"github.com/pulumi/pulumi/pkg/v2/backend/httpstate"
"github.com/pulumi/pulumi/pkg/v2/secrets"
"github.com/pulumi/pulumi/pkg/v2/secrets/service"
"github.com/pulumi/pulumi/sdk/v2/go/common/tokens"
"github.com/pulumi/pulumi/sdk/v2/go/common/util/contract"
"github.com/pulumi/pulumi/sdk/v2/go/common/workspace"
)
func newServiceSecretsManager(s httpstate.Stack) (secrets.Manager, error) {
func newServiceSecretsManager(s httpstate.Stack, stackName tokens.QName, configFile string) (secrets.Manager, error) {
contract.Assertf(stackName != "", "stackName %s", "!= \"\"")
if configFile == "" {
f, err := workspace.DetectProjectStackPath(stackName)
if err != nil {
return nil, err
}
configFile = f
}
info, err := workspace.LoadProjectStack(configFile)
if err != nil {
return nil, err
}
client := s.Backend().(httpstate.Backend).Client()
id := s.StackIdentifier()
// We should only save the ProjectStack at this point IF we have changed the
// secrets provider. To change the secrets provider to a serviceSecretsManager
// we would need to ensure that there are no remnants of the old secret manager
// To remove those remnants, we would set those values to be empty in the project
// stack, as per changeProjectStackSecretDetails func.
// If we do not check to see if the secrets provider has changed, then we will actually
// reload the configuration file to be sorted or an empty {} when creating a stack
// this is not the desired behaviour.
if changeProjectStackSecretDetails(info) {
if err := workspace.SaveProjectStack(stackName, info); err != nil {
return nil, err
}
}
return service.NewServiceSecretsManager(client, id)
}
// A passphrase secrets provider has an encryption salt, therefore, changing
// from passphrase to serviceSecretsManager requires the encryption salt
// to be removed.
// A cloud secrets manager has an encryption key and a secrets provider,
// therefore, changing from cloud to serviceSecretsManager requires the
// encryption key and secrets provider to be removed.
// Regardless of what the current secrets provider is, all of these values
// need to be empty otherwise `getStackSecretsManager` in crypto.go can
// potentially return the incorrect secret type for the stack.
func changeProjectStackSecretDetails(info *workspace.ProjectStack) bool {
var requiresSave bool
if info.SecretsProvider != "" {
info.SecretsProvider = ""
requiresSave = true
}
if info.EncryptedKey != "" {
info.EncryptedKey = ""
requiresSave = true
}
if info.EncryptionSalt != "" {
info.EncryptionSalt = ""
requiresSave = true
}
return requiresSave
}

View file

@ -0,0 +1,49 @@
package main
import (
"testing"
"github.com/pulumi/pulumi/sdk/v2/go/common/resource/config"
"github.com/pulumi/pulumi/sdk/v2/go/common/workspace"
"github.com/stretchr/testify/assert"
)
func TestChangeProjectStackSecretDetails(t *testing.T) {
tests := []struct {
TestName string
ProjectStack workspace.ProjectStack
Expected bool
}{
{
TestName: "Expects to save stack when existing secrets manager is cloud",
ProjectStack: workspace.ProjectStack{
Config: make(config.Map),
SecretsProvider: "awskms://alias/TestProvider?region=us-west-2",
EncryptedKey: "AQICAHhAA+FYp21DcGwS7xUizcOsoZihxKtWVCjZpgsK7owkfQF3sftIrKkJOJ0VYq69rHxvAAAAfjB8Bgkqhk",
},
Expected: true,
},
{
TestName: "Expects to save stack when existing secrets manager is passphrase",
ProjectStack: workspace.ProjectStack{
Config: make(config.Map),
EncryptionSalt: "v1:/AQICAHhAA+FYp21DcGwS7xUizcOsoZihxKtWVCjZpgsK7owkfQF3sftIrKkJOJ0VYq69rHxvAAAAfjB8Bgkqhk",
},
Expected: true,
},
{
TestName: "Does not expect to save stack when existing secrets manager is service",
ProjectStack: workspace.ProjectStack{
Config: make(config.Map),
},
Expected: false,
},
}
for _, test := range tests {
t.Run(test.TestName, func(t *testing.T) {
requiresProjectSave := changeProjectStackSecretDetails(&test.ProjectStack)
assert.Equal(t, test.Expected, requiresProjectSave)
})
}
}

View file

@ -15,24 +15,15 @@
package main
import (
"encoding/json"
"fmt"
"sort"
"strings"
"time"
"github.com/dustin/go-humanize"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/pulumi/pulumi/pkg/v2/backend"
"github.com/pulumi/pulumi/pkg/v2/backend/display"
"github.com/pulumi/pulumi/sdk/v2/go/common/diag/colors"
"github.com/pulumi/pulumi/sdk/v2/go/common/resource/config"
"github.com/pulumi/pulumi/sdk/v2/go/common/util/cmdutil"
"github.com/pulumi/pulumi/sdk/v2/go/common/util/contract"
)
// TO-DO: Remove as part of Pulumi v3.0.0
func newHistoryCmd() *cobra.Command {
var stack string
var jsonOut bool
@ -41,10 +32,12 @@ func newHistoryCmd() *cobra.Command {
Use: "history",
Aliases: []string{"hist"},
SuggestFor: []string{"updates"},
Short: "[PREVIEW] Update history for a stack",
Long: `Update history for a stack
This command lists data about previous updates for a stack.`,
Hidden: true,
Short: "[DEPRECATED] Display history for a stack",
Long: "Display history for a stack.\n\n" +
"This command displays data about previous updates for a stack.\n\n" +
"This command is now DEPRECATED, please use `pulumi stack history`.\n" +
"The command will be removed in a future release",
Args: cmdutil.NoArgs,
Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error {
opts := display.Options{
@ -85,123 +78,3 @@ This command lists data about previous updates for a stack.`,
&jsonOut, "json", "j", false, "Emit output as JSON")
return cmd
}
// updateInfoJSON is the shape of the --json output for a configuration value. While we can add fields to this
// structure in the future, we should not change existing fields.
type updateInfoJSON struct {
Kind string `json:"kind"`
StartTime string `json:"startTime"`
Message string `json:"message"`
Environment map[string]string `json:"environment"`
Config map[string]configValueJSON `json:"config"`
Result string `json:"result,omitempty"`
// These values are only present once the update finishes
EndTime *string `json:"endTime,omitempty"`
ResourceChanges *map[string]int `json:"resourceChanges,omitempty"`
}
func displayUpdatesJSON(updates []backend.UpdateInfo, decrypter config.Decrypter) error {
makeStringRef := func(s string) *string {
return &s
}
updatesJSON := make([]updateInfoJSON, len(updates))
for idx, update := range updates {
info := updateInfoJSON{
Kind: string(update.Kind),
StartTime: time.Unix(update.StartTime, 0).UTC().Format(timeFormat),
Message: update.Message,
Environment: update.Environment,
}
info.Config = make(map[string]configValueJSON)
for k, v := range update.Config {
configValue := configValueJSON{
Secret: v.Secure(),
}
if !v.Secure() || (v.Secure() && decrypter != nil) {
value, err := v.Value(decrypter)
contract.AssertNoError(err)
configValue.Value = makeStringRef(value)
if v.Object() {
var obj interface{}
if err := json.Unmarshal([]byte(value), &obj); err != nil {
return err
}
configValue.ObjectValue = obj
}
}
info.Config[k.String()] = configValue
}
info.Result = string(update.Result)
if update.Result != backend.InProgressResult {
info.EndTime = makeStringRef(time.Unix(update.EndTime, 0).UTC().Format(timeFormat))
resourceChanges := make(map[string]int)
for k, v := range update.ResourceChanges {
resourceChanges[string(k)] = v
}
info.ResourceChanges = &resourceChanges
}
updatesJSON[idx] = info
}
return printJSON(updatesJSON)
}
func displayUpdatesConsole(updates []backend.UpdateInfo, opts display.Options) error {
if len(updates) == 0 {
fmt.Println("Stack has never been updated")
return nil
}
printResourceChanges := func(background, text, sign, reset string, amount int) {
msg := opts.Color.Colorize(fmt.Sprintf("%s%s%s%v%s", background, text, sign, amount, reset))
fmt.Print(msg)
}
for _, update := range updates {
fmt.Printf("UpdateKind: %v\n", update.Kind)
if update.Result == "succeeded" {
fmt.Print(opts.Color.Colorize(fmt.Sprintf("%sStatus: %v%s\n", colors.Green, update.Result, colors.Reset)))
} else {
fmt.Print(opts.Color.Colorize(fmt.Sprintf("%sStatus: %v%s\n", colors.Red, update.Result, colors.Reset)))
}
fmt.Printf("Message: %v\n", update.Message)
printResourceChanges(colors.GreenBackground, colors.Black, "+", colors.Reset, update.ResourceChanges["create"])
printResourceChanges(colors.RedBackground, colors.Black, "-", colors.Reset, update.ResourceChanges["delete"])
printResourceChanges(colors.YellowBackground, colors.Black, "~", colors.Reset, update.ResourceChanges["update"])
printResourceChanges(colors.BlueBackground, colors.Black, " ", colors.Reset, update.ResourceChanges["same"])
timeStart := time.Unix(update.StartTime, 0)
timeCreated := humanize.Time(timeStart)
timeEnd := time.Unix(update.EndTime, 0)
duration := timeEnd.Sub(timeStart)
fmt.Printf("%sUpdated %s took %s\n", " ", timeCreated, duration)
isEmpty := func(s string) bool {
return len(strings.TrimSpace(s)) == 0
}
var keys []string
for k := range update.Environment {
keys = append(keys, k)
}
sort.Strings(keys)
indent := 4
for _, k := range keys {
if k == backend.GitHead && !isEmpty(update.Environment[k]) {
fmt.Print(opts.Color.Colorize(
fmt.Sprintf("%*s%s%s: %s%s\n", indent, "", colors.Yellow, k, update.Environment[k], colors.Reset)))
} else if !isEmpty(update.Environment[k]) {
fmt.Printf("%*s%s: %s\n", indent, "", k, update.Environment[k])
}
}
fmt.Println("")
}
return nil
}

View file

@ -751,8 +751,11 @@ func pythonCommands() []string {
commands = append(commands, "source venv/bin/activate")
}
// Install dependencies within the virtualenv
commands = append(commands, "pip3 install -r requirements.txt")
// Update pip, setuptools, and wheel within the virtualenv.
commands = append(commands, "python -m pip install --upgrade pip setuptools wheel")
// Install dependencies within the virtualenv.
commands = append(commands, "python -m pip install -r requirements.txt")
return commands
}

View file

@ -19,11 +19,11 @@ import (
"bytes"
"encoding/json"
"fmt"
user "github.com/tweekmonster/luser"
"net/http"
"net/url"
"os"
"os/exec"
"os/user"
"path/filepath"
"regexp"
"runtime"

View file

@ -179,6 +179,8 @@ func newStackCmd() *cobra.Command {
cmd.AddCommand(newStackSelectCmd())
cmd.AddCommand(newStackTagCmd())
cmd.AddCommand(newStackRenameCmd())
cmd.AddCommand(newStackChangeSecretsProviderCmd())
cmd.AddCommand(newStackHistoryCmd())
return cmd
}

View file

@ -0,0 +1,177 @@
// 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 main
import (
"context"
"encoding/json"
"github.com/pulumi/pulumi/pkg/v2/backend"
"github.com/pulumi/pulumi/pkg/v2/resource/stack"
"github.com/pulumi/pulumi/sdk/v2/go/common/apitype"
"github.com/pulumi/pulumi/sdk/v2/go/common/resource/config"
"github.com/spf13/cobra"
"github.com/pulumi/pulumi/pkg/v2/backend/display"
"github.com/pulumi/pulumi/sdk/v2/go/common/util/cmdutil"
)
func newStackChangeSecretsProviderCmd() *cobra.Command {
var cmd = &cobra.Command{
Use: "change-secrets-provider <new-secrets-provider>",
Args: cmdutil.ExactArgs(1),
Short: "Change the secrets provider for the current stack",
Long: "Change the secrets provider for the current stack. " +
"Valid secret providers types are `default`, `passphrase`, `awskms`, `azurekeyvault`, `gcpkms`, `hashivault`.\n\n" +
"To change to using the Pulumi Default Secrets Provider, use the following:\n" +
"\n" +
"pulumi stack change-secrets-provider default" +
"\n" +
"\n" +
"To change the stack to use a cloud secrets backend, use one of the following:\n" +
"\n" +
"* `pulumi stack change-secrets-provider \"awskms://alias/ExampleAlias?region=us-east-1\"" +
"`\n" +
"* `pulumi stack change-secrets-provider " +
"\"awskms://1234abcd-12ab-34cd-56ef-1234567890ab?region=us-east-1\"`\n" +
"* `pulumi stack change-secrets-provider " +
"\"azurekeyvault://mykeyvaultname.vault.azure.net/keys/mykeyname\"`\n" +
"* `pulumi stack change-secrets-provider " +
"\"gcpkms://projects/<p>/locations/<l>/keyRings/<r>/cryptoKeys/<k>\"`\n" +
"* `pulumi stack change-secrets-provider \"hashivault://mykey\"`",
Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error {
opts := display.Options{
Color: cmdutil.GetGlobalColorization(),
}
// Validate secrets provider type
if err := validateSecretsProvider(args[0]); err != nil {
return err
}
// Get the current backend
b, err := currentBackend(opts)
if err != nil {
return err
}
// Get the current stack and its project
currentStack, err := requireStack("", false, opts, true /*setCurrent*/)
if err != nil {
return err
}
currentProjectStack, err := loadProjectStack(currentStack)
if err != nil {
return err
}
// Build decrypter based on the existing secrets provider
var decrypter config.Decrypter
currentConfig := currentProjectStack.Config
if currentConfig.HasSecureValue() {
dec, decerr := getStackDecrypter(currentStack)
if decerr != nil {
return decerr
}
decrypter = dec
} else {
decrypter = config.NewPanicCrypter()
}
// Create the new secrets provider and set to the currentStack
if err := createSecretsManager(b, currentStack.Ref(), args[0]); err != nil {
return err
}
// Change the config to use the new secrets provider
err = migrateConfigToNewSecretsProvider(currentStack, currentConfig, decrypter)
if err != nil {
return err
}
// Fixup the checkpoint
return migrateCheckpointToNewSecretsProvider(commandContext(), currentStack)
}),
}
return cmd
}
func migrateCheckpointToNewSecretsProvider(ctx context.Context, currentStack backend.Stack) error {
// Load the current checkpoint so those secrets can also be decrypted
checkpoint, err := currentStack.ExportDeployment(ctx)
if err != nil {
return err
}
snap, err := stack.DeserializeUntypedDeployment(checkpoint, stack.DefaultSecretsProvider)
if err != nil {
return checkDeploymentVersionError(err, currentStack.Ref().Name().String())
}
// Get the newly created secrets manager for the stack
newSecretsManager, err := getStackSecretsManager(currentStack)
if err != nil {
return err
}
// Reserialize the Snapshopshot with the NewSecrets Manager
reserializedDeployment, err := stack.SerializeDeployment(snap, newSecretsManager, false /*showSecrets*/)
if err != nil {
return err
}
bytes, err := json.Marshal(reserializedDeployment)
if err != nil {
return err
}
dep := apitype.UntypedDeployment{
Version: apitype.DeploymentSchemaVersionCurrent,
Deployment: bytes,
}
// Import the newly changes Deployment
return currentStack.ImportDeployment(ctx, &dep)
}
func migrateConfigToNewSecretsProvider(currentStack backend.Stack, currentConfig config.Map,
decrypter config.Decrypter) error {
// Get the new encrypter for the current stack
newEncrypter, err := getStackEncrypter(currentStack)
if err != nil {
return err
}
// Create a copy of the current config map and re-encrypt using the new secrets provider
newProjectConfig, err := currentConfig.Copy(decrypter, newEncrypter)
if err != nil {
return err
}
// Reload the project stack after the new secretsProvider is in place
reloadedProjectStack, err := loadProjectStack(currentStack)
if err != nil {
return err
}
for key, val := range newProjectConfig {
if err := reloadedProjectStack.Config.Set(key, val, false); err != nil {
return err
}
}
return saveProjectStack(currentStack, reloadedProjectStack)
}

View file

@ -0,0 +1,194 @@
package main
import (
"encoding/json"
"fmt"
"sort"
"strings"
"time"
"github.com/dustin/go-humanize"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/pulumi/pulumi/pkg/v2/backend"
"github.com/pulumi/pulumi/pkg/v2/backend/display"
"github.com/pulumi/pulumi/sdk/v2/go/common/diag/colors"
"github.com/pulumi/pulumi/sdk/v2/go/common/resource/config"
"github.com/pulumi/pulumi/sdk/v2/go/common/util/cmdutil"
"github.com/pulumi/pulumi/sdk/v2/go/common/util/contract"
)
func newStackHistoryCmd() *cobra.Command {
var stack string
var jsonOut bool
var showSecrets bool
cmd := &cobra.Command{
Use: "history",
Aliases: []string{"hist"},
SuggestFor: []string{"updates"},
Short: "[PREVIEW] Display history for a stack",
Long: `Display history for a stack
This command displays data about previous updates for a stack.`,
Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error {
opts := display.Options{
Color: cmdutil.GetGlobalColorization(),
}
s, err := requireStack(stack, false /*offerNew */, opts, false /*setCurrent*/)
if err != nil {
return err
}
b := s.Backend()
updates, err := b.GetHistory(commandContext(), s.Ref())
if err != nil {
return errors.Wrap(err, "getting history")
}
var decrypter config.Decrypter
if showSecrets {
crypter, err := getStackDecrypter(s)
if err != nil {
return errors.Wrap(err, "decrypting secrets")
}
decrypter = crypter
}
if jsonOut {
return displayUpdatesJSON(updates, decrypter)
}
return displayUpdatesConsole(updates, opts)
}),
}
cmd.PersistentFlags().StringVarP(
&stack, "stack", "s", "",
"Choose a stack other than the currently selected one")
cmd.Flags().BoolVar(
&showSecrets, "show-secrets", false,
"Show secret values when listing config instead of displaying blinded values")
cmd.PersistentFlags().BoolVarP(
&jsonOut, "json", "j", false, "Emit output as JSON")
return cmd
}
// updateInfoJSON is the shape of the --json output for a configuration value. While we can add fields to this
// structure in the future, we should not change existing fields.
type updateInfoJSON struct {
Kind string `json:"kind"`
StartTime string `json:"startTime"`
Message string `json:"message"`
Environment map[string]string `json:"environment"`
Config map[string]configValueJSON `json:"config"`
Result string `json:"result,omitempty"`
// These values are only present once the update finishes
EndTime *string `json:"endTime,omitempty"`
ResourceChanges *map[string]int `json:"resourceChanges,omitempty"`
}
func displayUpdatesJSON(updates []backend.UpdateInfo, decrypter config.Decrypter) error {
makeStringRef := func(s string) *string {
return &s
}
updatesJSON := make([]updateInfoJSON, len(updates))
for idx, update := range updates {
info := updateInfoJSON{
Kind: string(update.Kind),
StartTime: time.Unix(update.StartTime, 0).UTC().Format(timeFormat),
Message: update.Message,
Environment: update.Environment,
}
info.Config = make(map[string]configValueJSON)
for k, v := range update.Config {
configValue := configValueJSON{
Secret: v.Secure(),
}
if !v.Secure() || (v.Secure() && decrypter != nil) {
value, err := v.Value(decrypter)
contract.AssertNoError(err)
configValue.Value = makeStringRef(value)
if v.Object() {
var obj interface{}
if err := json.Unmarshal([]byte(value), &obj); err != nil {
return err
}
configValue.ObjectValue = obj
}
}
info.Config[k.String()] = configValue
}
info.Result = string(update.Result)
if update.Result != backend.InProgressResult {
info.EndTime = makeStringRef(time.Unix(update.EndTime, 0).UTC().Format(timeFormat))
resourceChanges := make(map[string]int)
for k, v := range update.ResourceChanges {
resourceChanges[string(k)] = v
}
info.ResourceChanges = &resourceChanges
}
updatesJSON[idx] = info
}
return printJSON(updatesJSON)
}
func displayUpdatesConsole(updates []backend.UpdateInfo, opts display.Options) error {
if len(updates) == 0 {
fmt.Println("Stack has never been updated")
return nil
}
printResourceChanges := func(background, text, sign, reset string, amount int) {
msg := opts.Color.Colorize(fmt.Sprintf("%s%s%s%v%s", background, text, sign, amount, reset))
fmt.Print(msg)
}
for _, update := range updates {
fmt.Printf("UpdateKind: %v\n", update.Kind)
if update.Result == "succeeded" {
fmt.Print(opts.Color.Colorize(fmt.Sprintf("%sStatus: %v%s\n", colors.Green, update.Result, colors.Reset)))
} else {
fmt.Print(opts.Color.Colorize(fmt.Sprintf("%sStatus: %v%s\n", colors.Red, update.Result, colors.Reset)))
}
fmt.Printf("Message: %v\n", update.Message)
printResourceChanges(colors.GreenBackground, colors.Black, "+", colors.Reset, update.ResourceChanges["create"])
printResourceChanges(colors.RedBackground, colors.Black, "-", colors.Reset, update.ResourceChanges["delete"])
printResourceChanges(colors.YellowBackground, colors.Black, "~", colors.Reset, update.ResourceChanges["update"])
printResourceChanges(colors.BlueBackground, colors.Black, " ", colors.Reset, update.ResourceChanges["same"])
timeStart := time.Unix(update.StartTime, 0)
timeCreated := humanize.Time(timeStart)
timeEnd := time.Unix(update.EndTime, 0)
duration := timeEnd.Sub(timeStart)
fmt.Printf("%sUpdated %s took %s\n", " ", timeCreated, duration)
isEmpty := func(s string) bool {
return len(strings.TrimSpace(s)) == 0
}
var keys []string
for k := range update.Environment {
keys = append(keys, k)
}
sort.Strings(keys)
indent := 4
for _, k := range keys {
if k == backend.GitHead && !isEmpty(update.Environment[k]) {
fmt.Print(opts.Color.Colorize(
fmt.Sprintf("%*s%s%s: %s%s\n", indent, "", colors.Yellow, k, update.Environment[k], colors.Reset)))
} else if !isEmpty(update.Environment[k]) {
fmt.Printf("%*s%s: %s\n", indent, "", k, update.Environment[k])
}
}
fmt.Println("")
}
return nil
}

View file

@ -32,6 +32,7 @@ const (
func newStackInitCmd() *cobra.Command {
var secretsProvider string
var stackName string
var stackToCopy string
cmd := &cobra.Command{
Use: "init [<org-name>/]<stack-name>",
@ -60,7 +61,11 @@ func newStackInitCmd() *cobra.Command {
"* `pulumi stack init --secrets-provider=\"awskms://1234abcd-12ab-34cd-56ef-1234567890ab?region=us-east-1\"`\n" +
"* `pulumi stack init --secrets-provider=\"azurekeyvault://mykeyvaultname.vault.azure.net/keys/mykeyname\"`\n" +
"* `pulumi stack init --secrets-provider=\"gcpkms://projects/<p>/locations/<l>/keyRings/<r>/cryptoKeys/<k>\"`\n" +
"* `pulumi stack init --secrets-provider=\"hashivault://mykey\"`",
"* `pulumi stack init --secrets-provider=\"hashivault://mykey\"\n`" +
"\n" +
"A stack can be created based on the configuration of an existing stack by passing the\n" +
"`--copy-config-from` flag.\n" +
"* `pulumi stack init --copy-config-from dev",
Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error {
opts := display.Options{
Color: cmdutil.GetGlobalColorization(),
@ -112,13 +117,40 @@ func newStackInitCmd() *cobra.Command {
}
var createOpts interface{} // Backend-specific config options, none currently.
_, err = createStack(b, stackRef, createOpts, true /*setCurrent*/, secretsProvider)
return err
newStack, err := createStack(b, stackRef, createOpts, true /*setCurrent*/, secretsProvider)
if err != nil {
return err
}
if stackToCopy != "" {
// load the old stack and its project
copyStack, err := requireStack(stackToCopy, false, opts, false /*setCurrent*/)
if err != nil {
return err
}
copyProjectStack, err := loadProjectStack(copyStack)
if err != nil {
return err
}
// get the project for the newly created stack
newProjectStack, err := loadProjectStack(newStack)
if err != nil {
return err
}
// copy the config from the old to the new
return copyEntireConfigMap(copyStack, copyProjectStack, newStack, newProjectStack)
}
return nil
}),
}
cmd.PersistentFlags().StringVarP(
&stackName, "stack", "s", "", "The name of the stack to create")
cmd.PersistentFlags().StringVar(
&secretsProvider, "secrets-provider", "default", possibleSecretsProviderChoices)
cmd.PersistentFlags().StringVar(
&stackToCopy, "copy-config-from", "", "The name of the stack to copy existing config from")
return cmd
}

View file

@ -114,11 +114,7 @@ func commandContext() context.Context {
return ctx
}
// createStack creates a stack with the given name, and optionally selects it as the current.
func createStack(
b backend.Backend, stackRef backend.StackReference, opts interface{}, setCurrent bool,
secretsProvider string) (backend.Stack, error) {
func createSecretsManager(b backend.Backend, stackRef backend.StackReference, secretsProvider string) error {
// As part of creating the stack, we also need to configure the secrets provider for the stack.
// We need to do this configuration step for cases where we will be using with the passphrase
// secrets provider or one of the cloud-backed secrets providers. We do not need to do this
@ -128,9 +124,27 @@ func createStack(
// The default when using the filestate backend is the passphrase secrets provider
secretsProvider = passphrase.Type
}
if _, ok := b.(httpstate.Backend); ok && isDefaultSecretsProvider {
stack, err := state.CurrentStack(commandContext(), b)
if err != nil {
return err
}
if stack == nil {
// This means this is the first time we are initiating a stack
// there is no way a stack will exist here so we need to just return nil
// this will mean the "old" default behaviour will work for us
return nil
}
if _, serviceSecretsErr := newServiceSecretsManager(stack.(httpstate.Stack),
stackRef.Name(), stackConfigFile); serviceSecretsErr != nil {
return serviceSecretsErr
}
}
if secretsProvider == passphrase.Type {
if _, pharseErr := newPassphraseSecretsManager(stackRef.Name(), stackConfigFile); pharseErr != nil {
return nil, pharseErr
return pharseErr
}
} else if !isDefaultSecretsProvider {
// All other non-default secrets providers are handled by the cloud secrets provider which
@ -141,7 +155,7 @@ func createStack(
if strings.HasPrefix(secretsProvider, "azurekeyvault://") {
parsed, err := url.Parse(secretsProvider)
if err != nil {
return nil, errors.Wrap(err, "failed to parse secrets provider URL")
return errors.Wrap(err, "failed to parse secrets provider URL")
}
if parsed.Query().Get("algorithm") == "" {
@ -151,10 +165,18 @@ func createStack(
}
if _, secretsErr := newCloudSecretsManager(stackRef.Name(), stackConfigFile, secretsProvider); secretsErr != nil {
return nil, secretsErr
return secretsErr
}
}
return nil
}
// createStack creates a stack with the given name, and optionally selects it as the current.
func createStack(
b backend.Backend, stackRef backend.StackReference, opts interface{}, setCurrent bool,
secretsProvider string) (backend.Stack, error) {
stack, err := b.CreateStack(commandContext(), stackRef, opts)
if err != nil {
// If it's a well-known error, don't wrap it.
@ -167,6 +189,10 @@ func createStack(
return nil, errors.Wrapf(err, "could not create stack")
}
if err := createSecretsManager(b, stackRef, secretsProvider); err != nil {
return nil, err
}
if setCurrent {
if err = state.SetCurrentStack(stack.Ref().String()); err != nil {
return nil, err

View file

@ -60,6 +60,7 @@ var (
goPkgInfo go_gen.GoPackageInfo
csharpPkgInfo dotnet.CSharpPackageInfo
nodePkgInfo nodejs.NodePackageInfo
pythonPkgInfo python.PackageInfo
// langModuleNameLookup is a map of module name to its language-specific
// name.
@ -347,6 +348,8 @@ func (mod *modContext) getLanguageModuleName(lang string) string {
switch lang {
case "go":
// Go module names use lowercase.
modName = strings.ToLower(modName)
if override, ok := goPkgInfo.ModuleToPackage[modName]; ok {
modName = override
}
@ -358,6 +361,10 @@ func (mod *modContext) getLanguageModuleName(lang string) string {
if override, ok := nodePkgInfo.ModuleToPackage[modName]; ok {
modName = override
}
case "python":
if override, ok := pythonPkgInfo.ModuleNameOverrides[modName]; ok {
modName = override
}
}
langModuleNameLookup[lookupKey] = modName
@ -368,11 +375,9 @@ func (mod *modContext) getLanguageModuleName(lang string) string {
// The result of this function should be used display purposes only.
func (mod *modContext) cleanTypeString(t schema.Type, langTypeString, lang, modName string, isInput bool) string {
switch lang {
case "go":
case "go", "python":
parts := strings.Split(langTypeString, ".")
return parts[len(parts)-1]
case "python":
return langTypeString
}
cleanCSharpName := func(pkgName, objModName string) string {
@ -499,7 +504,11 @@ func cleanOptionalIdentifier(s, lang string) string {
case "csharp":
return strings.TrimSuffix(s, "?")
case "python":
return s
if strings.HasPrefix(s, "Optional[") && strings.HasSuffix(s, "]") {
s = strings.TrimPrefix(s, "Optional[")
s = strings.TrimSuffix(s, "]")
return s
}
}
return s
}
@ -714,6 +723,47 @@ func (mod *modContext) genConstructorCS(r *schema.Resource, argsOptional bool) [
}
}
func (mod *modContext) genConstructorPython(r *schema.Resource, argsOptional bool) []formalParam {
docLanguageHelper := getLanguageDocHelper("python")
isK8sOverlayMod := mod.isKubernetesOverlayModule()
isDockerImageResource := mod.pkg.Name == "docker" && resourceName(r) == "Image"
// Kubernetes overlay resources use a different ordering of formal params in Python.
if isK8sOverlayMod {
return getKubernetesOverlayPythonFormalParams(mod.mod)
} else if isDockerImageResource {
return getDockerImagePythonFormalParams()
}
params := make([]formalParam, 0, len(r.InputProperties)+1)
// All other resources accept the resource options as a second parameter.
params = append(params, formalParam{
Name: "opts",
DefaultValue: " = None",
Type: propertyType{
Name: "Optional[ResourceOptions]",
Link: "/docs/reference/pkg/python/pulumi/#pulumi.ResourceOptions",
},
})
for _, p := range r.InputProperties {
// If the property defines a const value, then skip it.
// For example, in k8s, `apiVersion` and `kind` are often hard-coded
// in the SDK and are not really user-provided input properties.
if p.ConstValue != nil {
continue
}
typ := docLanguageHelper.GetLanguageTypeString(mod.pkg, mod.mod, p.Type, true /*input*/, false /*optional*/)
params = append(params, formalParam{
Name: python.InitParamName(p.Name),
DefaultValue: " = None",
Type: propertyType{
Name: fmt.Sprintf("Optional[%s]", typ),
},
})
}
return params
}
func (mod *modContext) genNestedTypes(member interface{}, resourceType bool) []docNestedType {
tokens := nestedTypeUsageInfo{}
// Collect all of the types for this "member" as a map of resource names
@ -835,9 +885,15 @@ func (mod *modContext) getProperties(properties []*schema.Property, lang string,
}
langDocHelper := getLanguageDocHelper(lang)
var propLangName string
switch lang {
case "python":
name, err := langDocHelper.GetPropertyName(prop)
if err != nil {
panic(err)
}
propLangName := name
// TODO[pulumi/pulumi#5145]: Delete this if check once all providers have UsesIOClasses set to true in their
// schema.
if lang == "python" && !pythonPkgInfo.UsesIOClasses {
pyName := python.PyName(prop.Name)
// The default casing for a Python property name is snake_case unless
// it is a property of a nested object, in which case, we should check the property
@ -857,13 +913,6 @@ func (mod *modContext) getProperties(properties []*schema.Property, lang string,
propLangName = prop.Name
}
}
default:
name, err := langDocHelper.GetPropertyName(prop)
if err != nil {
panic(err)
}
propLangName = name
}
propID := strings.ToLower(propLangName + propertyLangSeparator + lang)
@ -926,9 +975,6 @@ func getDockerImagePythonFormalParams() []formalParam {
func (mod *modContext) genConstructors(r *schema.Resource, allOptionalInputs bool) (map[string]string, map[string][]formalParam) {
renderedParams := make(map[string]string)
formalParams := make(map[string][]formalParam)
isK8sOverlayMod := mod.isKubernetesOverlayModule()
isK8sPackage := isKubernetesPackage(mod.pkg)
isDockerImageResource := mod.pkg.Name == "docker" && resourceName(r) == "Image"
for _, lang := range supportedLanguages {
var (
@ -948,59 +994,19 @@ func (mod *modContext) genConstructors(r *schema.Resource, allOptionalInputs boo
params = mod.genConstructorCS(r, allOptionalInputs)
paramTemplate = "csharp_formal_param"
case "python":
params = mod.genConstructorPython(r, allOptionalInputs)
paramTemplate = "py_formal_param"
// The Pulumi Python SDK does not have types for constructor args.
// All of the input properties are spread out in the signature as format params.
// Kubernetes overlay resources use a different ordering of formal params in Python.
if isK8sOverlayMod {
params = getKubernetesOverlayPythonFormalParams(mod.mod)
break
} else if isDockerImageResource {
params = getDockerImagePythonFormalParams()
break
}
params = make([]formalParam, 0, len(r.InputProperties)+1)
// All other resources accept the resource options as a second parameter.
params = append(params, formalParam{
Name: "opts",
DefaultValue: "=None",
})
for _, p := range r.InputProperties {
// If the property defines a const value, then skip it.
// For example, in k8s, `apiVersion` and `kind` are often hard-coded
// in the SDK and are not really user-provided input properties.
if p.ConstValue != nil {
continue
}
params = append(params, formalParam{
Name: python.PyName(p.Name),
DefaultValue: "=None",
})
}
// Kubernetes resources do not accept a props param.
if isK8sPackage {
break
}
params = append(params, formalParam{
Name: "__props__",
DefaultValue: "=None",
})
}
n := len(params)
for i, p := range params {
if err := templates.ExecuteTemplate(b, paramTemplate, p); err != nil {
panic(err)
}
if i != n-1 {
if i != 0 {
if err := templates.ExecuteTemplate(b, "param_separator", nil); err != nil {
panic(err)
}
}
if err := templates.ExecuteTemplate(b, paramTemplate, p); err != nil {
panic(err)
}
}
renderedParams[lang] = b.String()
formalParams[lang] = params
@ -1181,6 +1187,24 @@ func (mod *modContext) getCSLookupParams(r *schema.Resource, stateParam string)
}
}
func (mod *modContext) getPythonLookupParams(r *schema.Resource, stateParam string) []formalParam {
// The input properties for a resource needs to be exploded as
// individual constructor params.
docLanguageHelper := getLanguageDocHelper("python")
params := make([]formalParam, 0, len(r.StateInputs.Properties))
for _, p := range r.StateInputs.Properties {
typ := docLanguageHelper.GetLanguageTypeString(mod.pkg, mod.mod, p.Type, true /*input*/, false /*optional*/)
params = append(params, formalParam{
Name: python.PyName(p.Name),
DefaultValue: " = None",
Type: propertyType{
Name: fmt.Sprintf("Optional[%s]", typ),
},
})
}
return params
}
// genLookupParams generates a map of per-language way of rendering the formal parameters of the lookup function
// used to lookup an existing resource.
func (mod *modContext) genLookupParams(r *schema.Resource, stateParam string) map[string]string {
@ -1207,17 +1231,8 @@ func (mod *modContext) genLookupParams(r *schema.Resource, stateParam string) ma
params = mod.getCSLookupParams(r, stateParam)
paramTemplate = "csharp_formal_param"
case "python":
params = mod.getPythonLookupParams(r, stateParam)
paramTemplate = "py_formal_param"
// The Pulumi Python SDK does not yet have types for formal parameters.
// The input properties for a resource needs to be exploded as
// individual constructor params.
params = make([]formalParam, 0, len(r.StateInputs.Properties))
for _, p := range r.StateInputs.Properties {
params = append(params, formalParam{
Name: python.PyName(p.Name),
DefaultValue: "=None",
})
}
}
n := len(params)
@ -1728,6 +1743,8 @@ func getMod(pkg *schema.Package, token string, modules map[string]*modContext, t
// If the parent name is blank, it means this is the package-level.
if parentName == "." || parentName == "" {
parentName = ":index:"
} else {
parentName = ":" + parentName + ":"
}
parent := getMod(pkg, parentName, modules, tool)
parent.children = append(parent.children, mod)
@ -1765,6 +1782,7 @@ func generateModulesFromSchemaPackage(tool string, pkg *schema.Package) map[stri
goPkgInfo, _ = pkg.Language["go"].(go_gen.GoPackageInfo)
csharpPkgInfo, _ = pkg.Language["csharp"].(dotnet.CSharpPackageInfo)
nodePkgInfo, _ = pkg.Language["nodejs"].(nodejs.NodePackageInfo)
pythonPkgInfo, _ = pkg.Language["python"].(python.PackageInfo)
goLangHelper := getLanguageDocHelper("go").(*go_gen.DocLanguageHelper)
// Generate the Go package map info now, so we can use that to get the type string

View file

@ -87,8 +87,7 @@ func (mod *modContext) getFunctionResourceInfo(f *schema.Function) map[string]pr
}
case "python":
// Pulumi's Python language SDK does not have "types" yet, so we will skip it for now.
continue
resultTypeName = docLangHelper.GetResourceFunctionResultName(mod.mod, f)
default:
panic(errors.Errorf("cannot generate function resource info for unhandled language %q", lang))
}
@ -212,6 +211,7 @@ func (mod *modContext) genFunctionCS(f *schema.Function, funcName string) []form
}
func (mod *modContext) genFunctionPython(f *schema.Function, resourceName string) []formalParam {
docLanguageHelper := getLanguageDocHelper("python")
var params []formalParam
// Some functions don't have any inputs other than the InvokeOptions.
@ -219,11 +219,14 @@ func (mod *modContext) genFunctionPython(f *schema.Function, resourceName string
if f.Inputs != nil {
params = make([]formalParam, 0, len(f.Inputs.Properties))
for _, prop := range f.Inputs.Properties {
fArg := formalParam{
typ := docLanguageHelper.GetLanguageTypeString(mod.pkg, mod.mod, prop.Type, true /*input*/, false /*optional*/)
params = append(params, formalParam{
Name: python.PyName(prop.Name),
DefaultValue: "=None",
}
params = append(params, fArg)
DefaultValue: " = None",
Type: propertyType{
Name: fmt.Sprintf("Optional[%s]", typ),
},
})
}
} else {
params = make([]formalParam, 0, 1)
@ -231,7 +234,11 @@ func (mod *modContext) genFunctionPython(f *schema.Function, resourceName string
params = append(params, formalParam{
Name: "opts",
DefaultValue: "=None",
DefaultValue: " = None",
Type: propertyType{
Name: "Optional[InvokeOptions]",
Link: "/docs/reference/pkg/python/pulumi/#pulumi.InvokeOptions",
},
})
return params

View file

@ -6,4 +6,4 @@
{{ define "csharp_formal_param" }}{{ template "linkify_param" .Type }}<span class="p">{{ .OptionalFlag }} </span><span class="nx">{{ .Name }}{{ .DefaultValue }}{{ end }}
{{ define "py_formal_param" }}{{ .Name }}{{ .DefaultValue }}{{ end }}
{{ define "py_formal_param" }}<span class="nx">{{ .Name }}</span><span class="p">:</span> {{ template "linkify_param" .Type }}{{ .DefaultValue }}{{ end }}

View file

@ -24,7 +24,7 @@
<!-- Python -->
{{ print "{{% choosable language python %}}" }}
<div class="highlight"><pre class="chroma"><code class="language-python" data-lang="python"><span class="k">function </span> {{ .FunctionName.python }}(</span>{{ htmlSafe .FunctionArgs.python }}<span class="p">)</span></code></pre></div>
<div class="highlight"><pre class="chroma"><code class="language-python" data-lang="python"><span class="k">def </span>{{ .FunctionName.python }}(</span>{{ htmlSafe .FunctionArgs.python }}<span class="p">) -&gt;</span> {{ .FunctionResult.python.Name }}</code></pre></div>
{{ print "{{% /choosable %}}" }}
<!-- Go -->

View file

@ -31,7 +31,7 @@
{{ htmlSafe "{{% /choosable %}}" }}
{{ htmlSafe "{{% choosable language python %}}" }}
<div class="highlight"><pre class="chroma"><code class="language-python" data-lang="python"><span class="k">def </span>{{ template "linkify_param" .ConstructorResource.python }}<span class="p">(resource_name, </span>{{ htmlSafe .ConstructorParams.python }}<span class="p">)</span></code></pre></div>
<div class="highlight"><pre class="chroma"><code class="language-python" data-lang="python"><span class="k">def </span>{{ template "linkify_param" .ConstructorResource.python }}<span class="p">(</span><span class="nx">resource_name</span><span class="p">:</span> <span class="nx">str</span><span class="p">, </span>{{ htmlSafe .ConstructorParams.python }}<span class="p">)</span></code></pre></div>
{{ htmlSafe "{{% /choosable %}}" }}
{{ htmlSafe "{{% choosable language go %}}" }}
@ -111,7 +111,8 @@ Get an existing {{.Header.Title}} resource's state with the given name, ID, and
{{ htmlSafe "{{% /choosable %}}" }}
{{ htmlSafe "{{% choosable language python %}}" }}
<div class="highlight"><pre class="chroma"><code class="language-python" data-lang="python"><span class="k">static </span><span class="nf">get</span><span class="p">(resource_name, id, opts=None, </span>{{ htmlSafe .LookupParams.python }}<span class="p">, __props__=None)</span></code></pre></div>
<div class="highlight"><pre class="chroma"><code class="language-python" data-lang="python"><span class=nd>@staticmethod</span>
<span class="k">def </span><span class="nf">get</span><span class="p">(</span><span class="nx">resource_name</span><span class="p">:</span> <span class="nx">str</span><span class="p">, </span><span class="nx">id</span><span class="p">:</span> <span class="nx">str</span><span class="p">, </span><span class="nx">opts</span><span class="p">:</span> <span class="nx"><a href="/docs/reference/pkg/python/pulumi/#pulumi.ResourceOptions">Optional[ResourceOptions]</a></span> = None<span class="p">, </span>{{ htmlSafe .LookupParams.python }}<span class="p">) -&gt;</span> {{ .ConstructorResource.python.Name }}</code></pre></div>
{{ htmlSafe "{{% /choosable %}}" }}
{{ htmlSafe "{{% choosable language go %}}" }}

View file

@ -1,5 +1,5 @@
<!-- linkify_param is used to wrap constructor/function params in an anchor tag. -->
{{ define "linkify_param" }}<span class="nx"><a href="{{ .Link }}">{{ if ne .DisplayName "" }}{{ .DisplayName }}{{ else }}{{ .Name }}{{ end }}</a></span>{{ end }}
{{ define "linkify_param" }}<span class="nx">{{ if ne .Link "" }}<a href="{{ .Link }}">{{ end }}{{ if ne .DisplayName "" }}{{ .DisplayName }}{{ else }}{{ .Name }}{{ end }}{{ if ne .Link "" }}</a>{{ end }}</span>{{ end }}
<!-- linkify_go_param is used to wrap constructor/function params in an anchor tag specifically for go constuctors. We are treating this as a snowflake for now. -->
{{ define "linkify_go_param" }}<span class="nx"><a href="{{ .Link }}">New{{ if ne .DisplayName "" }}{{ .DisplayName }}{{ else }}{{ .Name }}{{ end }}</a></span>{{ end }}

View file

@ -36,7 +36,17 @@ var _ codegen.DocLanguageHelper = DocLanguageHelper{}
// GetDocLinkForPulumiType returns the .Net API doc link for a Pulumi type.
func (d DocLanguageHelper) GetDocLinkForPulumiType(pkg *schema.Package, typeName string) string {
return fmt.Sprintf("/docs/reference/pkg/dotnet/Pulumi/%s.html", typeName)
var filename string
switch typeName {
// We use docfx to generate the .NET language docs. docfx adds a suffix
// to generic classes. The suffix depends on the number of type args the class accepts,
// which in the case of the Pulumi.Input class is 1.
case "Pulumi.Input":
filename = "Pulumi.Input-1"
default:
filename = typeName
}
return fmt.Sprintf("/docs/reference/pkg/dotnet/Pulumi/%s.html", filename)
}
// GetDocLinkForResourceType returns the .NET API doc URL for a type belonging to a resource provider.

View file

@ -36,6 +36,10 @@ type generator struct {
program *hcl2.Program
// C# namespace map per package.
namespaces map[string]map[string]string
// C# codegen compatibility mode per package.
compatibilities map[string]string
// A function to convert tokens to module names per package (utilizes the `moduleFormat` setting internally).
tokenToModules map[string]func(x string) string
// Type names per invoke function token.
functionArgs map[string]string
// Whether awaits are needed, and therefore an async Initialize method should be declared.
@ -44,20 +48,27 @@ type generator struct {
diagnostics hcl.Diagnostics
}
const pulumiPackage = "pulumi"
func GenerateProgram(program *hcl2.Program) (map[string][]byte, hcl.Diagnostics, error) {
// Linearize the nodes into an order appropriate for procedural code generation.
nodes := hcl2.Linearize(program)
// Import C#-specific schema info.
namespaces := make(map[string]map[string]string)
compatibilities := make(map[string]string)
tokenToModules := make(map[string]func(x string) string)
functionArgs := make(map[string]string)
for _, p := range program.Packages() {
if err := p.ImportLanguages(map[string]schema.Language{"csharp": Importer}); err != nil {
return make(map[string][]byte), nil, err
}
packageNamespaces := p.Language["csharp"].(CSharpPackageInfo).Namespaces
csharpInfo := p.Language["csharp"].(CSharpPackageInfo)
packageNamespaces := csharpInfo.Namespaces
namespaces[p.Name] = packageNamespaces
compatibilities[p.Name] = csharpInfo.Compatibility
tokenToModules[p.Name] = p.TokenToModule
for _, f := range p.Functions {
if f.Inputs != nil {
@ -67,9 +78,11 @@ func GenerateProgram(program *hcl2.Program) (map[string][]byte, hcl.Diagnostics,
}
g := &generator{
program: program,
namespaces: namespaces,
functionArgs: functionArgs,
program: program,
namespaces: namespaces,
compatibilities: compatibilities,
tokenToModules: tokenToModules,
functionArgs: functionArgs,
}
g.Formatter = format.NewFormatter(g)
@ -133,7 +146,7 @@ func (g *generator) genPreamble(w io.Writer, program *hcl2.Program) {
for _, n := range program.Nodes {
if r, isResource := n.(*hcl2.Resource); isResource {
pkg, _, _, _ := r.DecomposeToken()
if pkg != "pulumi" {
if pkg != pulumiPackage {
namespace := namespaceName(g.namespaces[pkg], pkg)
pulumiUsings.Add(fmt.Sprintf("%s = Pulumi.%[1]s", namespace))
}
@ -260,14 +273,13 @@ func (g *generator) resourceTypeName(r *hcl2.Resource) string {
// Compute the resource type from the Pulumi type token.
pkg, module, member, diags := r.DecomposeToken()
contract.Assert(len(diags) == 0)
if pkg == "pulumi" && module == "providers" {
if pkg == pulumiPackage && module == "providers" {
pkg, module, member = member, "", "Provider"
}
namespaces := g.namespaces[pkg]
namespaceKey := strings.Replace(module, "/", ".", -1)
rootNamespace := namespaceName(namespaces, pkg)
namespace := namespaceName(namespaces, namespaceKey)
namespace := namespaceName(namespaces, module)
if namespace != "" {
namespace = "." + namespace
@ -277,6 +289,29 @@ func (g *generator) resourceTypeName(r *hcl2.Resource) string {
return qualifiedMemberName
}
// resourceArgsTypeName computes the C# arguments class name for the given resource.
func (g *generator) resourceArgsTypeName(r *hcl2.Resource) string {
// Compute the resource type from the Pulumi type token.
pkg, module, member, diags := r.DecomposeToken()
contract.Assert(len(diags) == 0)
if pkg == pulumiPackage && module == "providers" {
pkg, module, member = member, "", "Provider"
}
namespaces := g.namespaces[pkg]
rootNamespace := namespaceName(namespaces, pkg)
namespace := namespaceName(namespaces, module)
if g.compatibilities[pkg] == "kubernetes20" {
namespace = fmt.Sprintf("Types.Inputs.%s", namespace)
}
if namespace != "" {
namespace = "." + namespace
}
return fmt.Sprintf("%s%s.%sArgs", rootNamespace, namespace, Title(member))
}
// functionName computes the C# namespace and class name for the given function token.
func (g *generator) functionName(tokenArg model.Expression) (string, string) {
token := tokenArg.(*model.TemplateExpression).Parts[0].(*model.LiteralValueExpression).Value.AsString()
@ -286,9 +321,8 @@ func (g *generator) functionName(tokenArg model.Expression) (string, string) {
pkg, module, member, diags := hcl2.DecomposeToken(token, tokenRange)
contract.Assert(len(diags) == 0)
namespaces := g.namespaces[pkg]
namespaceKey := strings.Replace(module, "/", ".", -1)
rootNamespace := namespaceName(namespaces, pkg)
namespace := namespaceName(namespaces, namespaceKey)
namespace := namespaceName(namespaces, module)
if namespace != "" {
namespace = "." + namespace
@ -317,19 +351,21 @@ func (g *generator) argumentTypeName(expr model.Expression, destType model.Type)
qualifier = ""
}
pkg, module, member, diags := hcl2.DecomposeToken(token, tokenRange)
pkg, _, member, diags := hcl2.DecomposeToken(token, tokenRange)
contract.Assert(len(diags) == 0)
module := g.tokenToModules[pkg](token)
namespaces := g.namespaces[pkg]
namespaceKey := strings.Split(module, "/")[0]
rootNamespace := namespaceName(namespaces, pkg)
namespace := namespaceName(namespaces, namespaceKey)
namespace := namespaceName(namespaces, module)
if strings.ToLower(namespace) == "index" {
namespace = ""
}
if namespace != "" {
namespace = "." + namespace
}
if qualifier != "" {
if g.compatibilities[pkg] == "kubernetes20" {
namespace = ".Types.Inputs" + namespace
} else if qualifier != "" {
namespace = namespace + "." + qualifier
}
member = member + "Args"
@ -390,6 +426,7 @@ func (g *generator) genResourceOptions(opts *hcl2.ResourceOptions) string {
// genResource handles the generation of instantiations of non-builtin resources.
func (g *generator) genResource(w io.Writer, r *hcl2.Resource) {
qualifiedMemberName := g.resourceTypeName(r)
argsName := g.resourceArgsTypeName(r)
// Add conversions to input properties
for _, input := range r.Inputs {
@ -408,7 +445,7 @@ func (g *generator) genResource(w io.Writer, r *hcl2.Resource) {
g.genTrivia(w, r.Definition.Tokens.GetOpenBrace())
instantiate := func(resName string) {
g.Fgenf(w, "new %s(%s, new %[1]sArgs\n", qualifiedMemberName, resName)
g.Fgenf(w, "new %s(%s, new %s\n", qualifiedMemberName, resName, argsName)
g.Fgenf(w, "%s{\n", g.Indent)
g.Indented(func() {
for _, attr := range r.Inputs {

View file

@ -17,7 +17,6 @@ package dotnet
import (
"bytes"
"fmt"
"github.com/pulumi/pulumi/pkg/v2/codegen/schema"
"io"
"math/big"
"strings"
@ -26,6 +25,7 @@ import (
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/pulumi/pulumi/pkg/v2/codegen/hcl2"
"github.com/pulumi/pulumi/pkg/v2/codegen/hcl2/model"
"github.com/pulumi/pulumi/pkg/v2/codegen/schema"
"github.com/pulumi/pulumi/sdk/v2/go/common/util/contract"
"github.com/zclconf/go-cty/cty"
)
@ -402,6 +402,8 @@ func (g *generator) GenLiteralValueExpression(w io.Writer, expr *model.LiteralVa
switch expr.Type() {
case model.BoolType:
g.Fgenf(w, "%v", expr.Value.True())
case model.NoneType:
g.Fgen(w, "null")
case model.NumberType:
bf := expr.Value.AsBigFloat()
if i, acc := bf.Int64(); acc == big.Exact {

View file

@ -1221,8 +1221,11 @@ func LanguageResources(tool string, pkg *schema.Package) (map[string]LanguageRes
return nil, err
}
goInfo, _ := pkg.Language["go"].(GoPackageInfo)
packages := generatePackageContextMap(tool, pkg, goInfo)
var goPkgInfo GoPackageInfo
if goInfo, ok := pkg.Language["go"].(GoPackageInfo); ok {
goPkgInfo = goInfo
}
packages := generatePackageContextMap(tool, pkg, goPkgInfo)
// emit each package
var pkgMods []string
@ -1238,10 +1241,10 @@ func LanguageResources(tool string, pkg *schema.Package) (map[string]LanguageRes
pkg := packages[mod]
for _, r := range pkg.resources {
packagePath := path.Join(goInfo.ImportBasePath, pkg.mod)
packagePath := path.Join(goPkgInfo.ImportBasePath, pkg.mod)
resources[r.Token] = LanguageResource{
Resource: r,
Alias: goInfo.PackageImportAliases[packagePath],
Alias: goPkgInfo.PackageImportAliases[packagePath],
Name: tokenToName(r.Token),
Package: packagePath,
}
@ -1256,8 +1259,11 @@ func GeneratePackage(tool string, pkg *schema.Package) (map[string][]byte, error
return nil, err
}
goInfo, _ := pkg.Language["go"].(GoPackageInfo)
packages := generatePackageContextMap(tool, pkg, goInfo)
var goPkgInfo GoPackageInfo
if goInfo, ok := pkg.Language["go"].(GoPackageInfo); ok {
goPkgInfo = goInfo
}
packages := generatePackageContextMap(tool, pkg, goPkgInfo)
// emit each package
var pkgMods []string

View file

@ -0,0 +1,55 @@
package gen
import (
"bytes"
"github.com/pkg/errors"
"github.com/pulumi/pulumi/pkg/v2/codegen/schema"
)
// CRDTypes returns a map from each module name to a buffer containing the
// code for its generated types.
func CRDTypes(tool string, pkg *schema.Package) (map[string]*bytes.Buffer, error) {
if err := pkg.ImportLanguages(map[string]schema.Language{"go": Importer}); err != nil {
return map[string]*bytes.Buffer{}, err
}
var goPkgInfo GoPackageInfo
if goInfo, ok := pkg.Language["go"].(GoPackageInfo); ok {
goPkgInfo = goInfo
}
packages := generatePackageContextMap(tool, pkg, goPkgInfo)
var pkgMods []string
for mod := range packages {
pkgMods = append(pkgMods, mod)
}
buffers := map[string]*bytes.Buffer{}
for _, mod := range pkgMods {
pkg := packages[mod]
buffer := &bytes.Buffer{}
for _, r := range pkg.resources {
imports := stringSet{}
pkg.getImports(r, imports)
pkg.genHeader(buffer, []string{"context", "reflect"}, imports)
if err := pkg.genResource(buffer, r); err != nil {
return nil, errors.Wrapf(err, "generating resource %s", mod)
}
}
if len(pkg.types) > 0 {
for _, t := range pkg.types {
pkg.genType(buffer, t)
}
pkg.genTypeRegistrations(buffer, pkg.types)
}
buffers[mod] = buffer
}
return buffers, nil
}

View file

@ -22,6 +22,7 @@ type generator struct {
// The formatter to use when generating code.
*format.Formatter
program *hcl2.Program
packages map[string]*schema.Package
contexts map[string]map[string]*pkgContext
diagnostics hcl.Diagnostics
jsonTempSpiller *jsonSpiller
@ -38,14 +39,14 @@ func GenerateProgram(program *hcl2.Program) (map[string][]byte, hcl.Diagnostics,
// Linearize the nodes into an order appropriate for procedural code generation.
nodes := hcl2.Linearize(program)
contexts := make(map[string]map[string]*pkgContext)
packages, contexts := map[string]*schema.Package{}, map[string]map[string]*pkgContext{}
for _, pkg := range program.Packages() {
contexts[pkg.Name] = getPackages("tool", pkg)
packages[pkg.Name], contexts[pkg.Name] = pkg, getPackages("tool", pkg)
}
g := &generator{
program: program,
packages: packages,
contexts: contexts,
jsonTempSpiller: &jsonSpiller{},
ternaryTempSpiller: &tempSpiller{},
@ -58,18 +59,31 @@ func GenerateProgram(program *hcl2.Program) (map[string][]byte, hcl.Diagnostics,
g.Formatter = format.NewFormatter(g)
var index bytes.Buffer
g.genPreamble(&index, program)
// we must collect imports once before lowering, and once after.
// this allows us to avoid complexity of traversing apply expressions for things like JSON
// but still have access to types provided by __convert intrinsics after lowering.
pulumiImports := codegen.NewStringSet()
stdImports := codegen.NewStringSet()
g.collectImports(program, stdImports, pulumiImports)
var progPostamble bytes.Buffer
for _, n := range nodes {
g.collectScopeRoots(n)
}
for _, n := range nodes {
g.genNode(&index, n)
g.genNode(&progPostamble, n)
}
g.genPostamble(&index, nodes)
g.genPostamble(&progPostamble, nodes)
// We must generate the program first and the preamble second and finally cat the two together.
// This is because nested object/tuple cons expressions can require imports that aren't
// present in resource declarations or invokes alone. Expressions are lowered when the program is generated
// and this must happen first so we can access types via __convert intrinsics.
var index bytes.Buffer
g.genPreamble(&index, program, stdImports, pulumiImports)
index.Write(progPostamble.Bytes())
// Run Go formatter on the code before saving to disk
formattedSource, err := gofmt.Source(index.Bytes())
@ -88,8 +102,11 @@ func getPackages(tool string, pkg *schema.Package) map[string]*pkgContext {
return nil
}
goInfo, _ := pkg.Language["go"].(GoPackageInfo)
return generatePackageContextMap(tool, pkg, goInfo)
var goPkgInfo GoPackageInfo
if goInfo, ok := pkg.Language["go"].(GoPackageInfo); ok {
goPkgInfo = goInfo
}
return generatePackageContextMap(tool, pkg, goPkgInfo)
}
func (g *generator) collectScopeRoots(n hcl2.Node) {
@ -103,11 +120,11 @@ func (g *generator) collectScopeRoots(n hcl2.Node) {
}
// genPreamble generates package decl, imports, and opens the main func
func (g *generator) genPreamble(w io.Writer, program *hcl2.Program) {
func (g *generator) genPreamble(w io.Writer, program *hcl2.Program, stdImports, pulumiImports codegen.StringSet) {
g.Fprint(w, "package main\n\n")
g.Fprintf(w, "import (\n")
stdImports, pulumiImports := g.collectImports(w, program)
g.collectImports(program, stdImports, pulumiImports)
for _, imp := range stdImports.SortedValues() {
g.Fprintf(w, "\"%s\"\n", imp)
}
@ -116,7 +133,7 @@ func (g *generator) genPreamble(w io.Writer, program *hcl2.Program) {
g.Fprintf(w, "\"github.com/pulumi/pulumi/sdk/v2/go/pulumi\"\n")
for _, imp := range pulumiImports.SortedValues() {
g.Fprintf(w, "\"%s\"\n", imp)
g.Fprintf(w, "%s\n", imp)
}
g.Fprintf(w, ")\n")
@ -125,10 +142,11 @@ func (g *generator) genPreamble(w io.Writer, program *hcl2.Program) {
}
// collect Imports returns two sets of packages imported by the program, std lib packages and pulumi packages
func (g *generator) collectImports(w io.Writer, program *hcl2.Program) (codegen.StringSet, codegen.StringSet) {
func (g *generator) collectImports(
program *hcl2.Program,
stdImports,
pulumiImports codegen.StringSet) (codegen.StringSet, codegen.StringSet) {
// Accumulate import statements for the various providers
pulumiImports := codegen.NewStringSet()
stdImports := codegen.NewStringSet()
for _, n := range program.Nodes {
if r, isResource := n.(*hcl2.Resource); isResource {
pkg, mod, name, _ := r.DecomposeToken()
@ -136,27 +154,12 @@ func (g *generator) collectImports(w io.Writer, program *hcl2.Program) (codegen.
pkg = name
}
version := -1
for _, p := range program.Packages() {
if p.Name == pkg {
version = int(p.Version.Major)
break
}
vPath, err := g.getVersionPath(program, pkg)
if err != nil {
panic(err)
}
if version == -1 {
panic(errors.Errorf("could not find package information for resource with type token:\n\n%s", r.Token))
}
var vPath string
if version > 1 {
vPath = fmt.Sprintf("/v%d", version)
}
if mod == "" {
pulumiImports.Add(fmt.Sprintf("github.com/pulumi/pulumi-%s/sdk%s/go/%s", pkg, vPath, pkg))
} else {
pulumiImports.Add(fmt.Sprintf("github.com/pulumi/pulumi-%s/sdk%s/go/%s/%s", pkg, vPath, pkg, mod))
}
pulumiImports.Add(g.getPulumiImport(pkg, vPath, mod))
}
diags := n.VisitExpressions(nil, func(n model.Expression) (model.Expression, hcl.Diagnostics) {
@ -169,28 +172,34 @@ func (g *generator) collectImports(w io.Writer, program *hcl2.Program) (codegen.
contract.Assert(len(diagnostics) == 0)
version := -1
for _, p := range program.Packages() {
if p.Name == pkg {
version = int(p.Version.Major)
break
vPath, err := g.getVersionPath(program, pkg)
if err != nil {
panic(err)
}
pulumiImports.Add(g.getPulumiImport(pkg, vPath, mod))
} else if call.Name == hcl2.IntrinsicConvert {
if schemaType, ok := hcl2.GetSchemaForType(call.Type()); ok {
switch schemaType := schemaType.(type) {
case *schema.ObjectType:
token := schemaType.Token
var tokenRange hcl.Range
pkg, mod, _, _ := hcl2.DecomposeToken(token, tokenRange)
vPath, err := g.getVersionPath(program, pkg)
if err != nil {
panic(err)
}
pulumiImports.Add(g.getPulumiImport(pkg, vPath, mod))
case *schema.ArrayType:
token := schemaType.ElementType.(*schema.ObjectType).Token
var tokenRange hcl.Range
pkg, mod, _, _ := hcl2.DecomposeToken(token, tokenRange)
vPath, err := g.getVersionPath(program, pkg)
if err != nil {
panic(err)
}
pulumiImports.Add(g.getPulumiImport(pkg, vPath, mod))
}
}
if version == -1 {
panic(errors.Errorf("could not find package information for resource with type token:\n\n%s", token))
}
var vPath string
if version > 1 {
vPath = fmt.Sprintf("/v%d", version)
}
// namespaceless invokes "aws:index:..."
if mod == "" {
pulumiImports.Add(fmt.Sprintf("github.com/pulumi/pulumi-%s/sdk%s/go/%s", pkg, vPath, pkg))
} else {
pulumiImports.Add(fmt.Sprintf("github.com/pulumi/pulumi-%s/sdk%s/go/%s/%s", pkg, vPath, pkg, mod))
}
}
}
@ -217,6 +226,73 @@ func (g *generator) collectImports(w io.Writer, program *hcl2.Program) (codegen.
return stdImports, pulumiImports
}
func (g *generator) getVersionPath(program *hcl2.Program, pkg string) (string, error) {
version := -1
for _, p := range program.Packages() {
if p.Name == pkg {
version = int(p.Version.Major)
break
}
}
if version == -1 {
return "", errors.Errorf("could not find package version information for pkg: %s", pkg)
}
var vPath string
if version > 1 {
vPath = fmt.Sprintf("/v%d", version)
}
return vPath, nil
}
func (g *generator) getPkgContext(pkg, mod string) (*pkgContext, bool) {
p, ok := g.contexts[pkg]
if !ok {
return nil, false
}
m, ok := p[mod]
return m, ok
}
func (g *generator) getGoPackageInfo(pkg string) (GoPackageInfo, bool) {
p, ok := g.packages[pkg]
if !ok {
return GoPackageInfo{}, false
}
info, ok := p.Language["go"].(GoPackageInfo)
return info, ok
}
func (g *generator) getPulumiImport(pkg, vPath, mod string) string {
info, _ := g.getGoPackageInfo(pkg)
if m, ok := info.ModuleToPackage[mod]; ok {
mod = m
}
imp := fmt.Sprintf("github.com/pulumi/pulumi-%s/sdk%s/go/%s/%s", pkg, vPath, pkg, mod)
// namespaceless invokes "aws:index:..."
if mod == "" {
imp = fmt.Sprintf("github.com/pulumi/pulumi-%s/sdk%s/go/%s", pkg, vPath, pkg)
}
if alias, ok := info.PackageImportAliases[imp]; ok {
return fmt.Sprintf("%s %q", alias, imp)
}
modSplit := strings.Split(mod, "/")
// account for mods like "eks/ClusterVpcConfig" index...
if len(modSplit) > 1 {
if modSplit[0] == "" || modSplit[0] == "index" {
imp = fmt.Sprintf("github.com/pulumi/pulumi-%s/sdk%s/go/%s", pkg, vPath, pkg)
} else {
imp = fmt.Sprintf("github.com/pulumi/pulumi-%s/sdk%s/go/%s/%s", pkg, vPath, pkg, strings.Split(mod, "/")[0])
}
}
return fmt.Sprintf("%q", imp)
}
// genPostamble closes the method
func (g *generator) genPostamble(w io.Writer, nodes []hcl2.Node) {
@ -326,20 +402,22 @@ func (g *generator) genResource(w io.Writer, r *hcl2.Resource) {
g.genTemps(w, temps)
}
modOrAlias := g.getModOrAlias(pkg, mod)
instantiate := func(varName, resourceName string, w io.Writer) {
if g.scopeTraversalRoots.Has(varName) || strings.HasPrefix(varName, "__") {
g.Fgenf(w, "%s, err := %s.New%s(ctx, %s, ", varName, mod, typ, resourceName)
g.Fgenf(w, "%s, err := %s.New%s(ctx, %s, ", varName, modOrAlias, typ, resourceName)
} else {
assignment := ":="
if g.isErrAssigned {
assignment = "="
}
g.Fgenf(w, "_, err %s %s.New%s(ctx, %s, ", assignment, mod, typ, resourceName)
g.Fgenf(w, "_, err %s %s.New%s(ctx, %s, ", assignment, modOrAlias, typ, resourceName)
}
g.isErrAssigned = true
if len(r.Inputs) > 0 {
g.Fgenf(w, "&%s.%sArgs{\n", mod, typ)
g.Fgenf(w, "&%s.%sArgs{\n", modOrAlias, typ)
for _, attr := range r.Inputs {
g.Fgenf(w, "%s: ", strings.Title(attr.Name))
g.Fgenf(w, "%.v,\n", attr.Value)
@ -361,7 +439,7 @@ func (g *generator) genResource(w io.Writer, r *hcl2.Resource) {
rangeExpr, temps := g.lowerExpression(r.Options.Range, rangeType, false)
g.genTemps(w, temps)
g.Fgenf(w, "var %s []*%s.%s\n", resName, mod, typ)
g.Fgenf(w, "var %s []*%s.%s\n", resName, modOrAlias, typ)
// ahead of range statement declaration generate the resource instantiation
// to detect and removed unused k,v variables
@ -529,3 +607,21 @@ func (g *generator) useLookupInvokeForm(token string) bool {
return false
}
// getModOrAlias attempts to reconstruct the import statement and check if the imported package
// is aliased, returning that alias if available.
func (g *generator) getModOrAlias(pkg, mod string) string {
info, ok := g.getGoPackageInfo(pkg)
if !ok {
return mod
}
if m, ok := info.ModuleToPackage[mod]; ok {
mod = m
}
imp := fmt.Sprintf("%s/%s", info.ImportBasePath, mod)
if alias, ok := info.PackageImportAliases[imp]; ok {
return alias
}
return mod
}

View file

@ -258,6 +258,11 @@ func (g *generator) GenLiteralValueExpression(w io.Writer, expr *model.LiteralVa
}
func (g *generator) genLiteralValueExpression(w io.Writer, expr *model.LiteralValueExpression, destType model.Type) {
if destType == model.NoneType {
g.Fgen(w, "nil")
return
}
argTypeName := g.argumentTypeName(expr, destType, false)
isPulumiType := strings.HasPrefix(argTypeName, "pulumi.")
@ -302,10 +307,15 @@ func (g *generator) genLiteralValueExpression(w io.Writer, expr *model.LiteralVa
}
// handles the __convert intrinsic assuming that the union type will have an opaque type containing the dest type
case *model.UnionType:
var didGenerate bool
for _, t := range destType.ElementTypes {
if didGenerate {
break
}
switch t := t.(type) {
case *model.OpaqueType:
g.genLiteralValueExpression(w, expr, t)
didGenerate = true
break
}
}
@ -572,7 +582,8 @@ func (g *generator) argumentTypeName(expr model.Expression, destType model.Type,
if module == "" || strings.HasPrefix(module, "/") || strings.HasPrefix(module, "index/") {
module = pkg
}
importPrefix := strings.Split(module, "/")[0]
importPrefix := g.getModOrAlias(pkg, module)
importPrefix = strings.Split(importPrefix, "/")[0]
contract.Assert(len(diags) == 0)
fmtString := "[]%s.%s"
if isInput {
@ -593,7 +604,8 @@ func (g *generator) argumentTypeName(expr model.Expression, destType model.Type,
if module == "" || strings.HasPrefix(module, "/") || strings.HasPrefix(module, "index/") {
module = pkg
}
importPrefix := strings.Split(module, "/")[0]
importPrefix := g.getModOrAlias(pkg, module)
importPrefix = strings.Split(importPrefix, "/")[0]
contract.Assert(len(diags) == 0)
member = Title(member)
if strings.HasPrefix(member, "Get") {

View file

@ -68,13 +68,14 @@ func TestGenProgram(t *testing.T) {
func TestCollectImports(t *testing.T) {
g := newTestGenerator(t, "aws-s3-logging.pp")
var index bytes.Buffer
stdImports, pulumiImports := g.collectImports(&index, g.program)
pulumiImports := codegen.NewStringSet()
stdImports := codegen.NewStringSet()
g.collectImports(g.program, stdImports, pulumiImports)
stdVals := stdImports.SortedValues()
pulumiVals := pulumiImports.SortedValues()
assert.Equal(t, 0, len(stdVals))
assert.Equal(t, 1, len(pulumiVals))
assert.Equal(t, "github.com/pulumi/pulumi-aws/sdk/v2/go/aws/s3", pulumiVals[0])
assert.Equal(t, "\"github.com/pulumi/pulumi-aws/sdk/v2/go/aws/s3\"", pulumiVals[0])
}
func newTestGenerator(t *testing.T, testFile string) *generator {

View file

@ -146,7 +146,7 @@ func BindProgram(files []*syntax.File, opts ...BindOption) (*Program, hcl.Diagno
}, diagnostics, nil
}
// declareNodes declares all of the top-level nodes in the given file. This invludes config, resources, outputs, and
// declareNodes declares all of the top-level nodes in the given file. This includes config, resources, outputs, and
// locals.
func (b *binder) declareNodes(file *syntax.File) (hcl.Diagnostics, error) {
var diagnostics hcl.Diagnostics

View file

@ -76,6 +76,7 @@ func (b *binder) bindResourceTypes(node *Resource) hcl.Diagnostics {
if !ok {
return hcl.Diagnostics{unknownResourceType(token, tokenRange)}
}
node.Schema = res
inputProperties, properties = res.InputProperties, res.Properties
} else {
inputProperties, properties = pkgSchema.schema.Config, pkgSchema.schema.Config

View file

@ -211,7 +211,7 @@ var schemaArrayTypes = make(map[schema.Type]*schema.ArrayType)
// GetSchemaForType extracts the schema.Type associated with a model.Type, if any.
//
// The result may be a *schema.UnionType if multiple schema types are associaged with the input type.
// The result may be a *schema.UnionType if multiple schema types are associated with the input type.
func GetSchemaForType(t model.Type) (schema.Type, bool) {
switch t := t.(type) {
case *model.ListType:

View file

@ -19,6 +19,7 @@ import (
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/pulumi/pulumi/pkg/v2/codegen/hcl2/model"
"github.com/pulumi/pulumi/pkg/v2/codegen/hcl2/syntax"
"github.com/pulumi/pulumi/pkg/v2/codegen/schema"
)
// ResourceOptions represents a resource instantiation's options.
@ -52,6 +53,9 @@ type Resource struct {
// Token is the type token for this resource.
Token string
// Schema is the schema definition for this resource, if any.
Schema *schema.Resource
// The type of the resource's inputs. This will always be either Any or an object type.
InputType model.Type
// The type of the resource's outputs. This will always be either Any or an object type.

View file

@ -13,5 +13,8 @@ func NewHost(schemaDirectoryPath string) plugin.Host {
}),
deploytest.NewProviderLoader("random", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
return Random(schemaDirectoryPath)
}),
deploytest.NewProviderLoader("kubernetes", semver.MustParse("1.0.0"), func() (plugin.Provider, error) {
return Kubernetes(schemaDirectoryPath)
}))
}

View file

@ -35,3 +35,15 @@ func Random(schemaDirectoryPath string) (plugin.Provider, error) {
},
}, nil
}
func Kubernetes(schemaDirectoryPath string) (plugin.Provider, error) {
schema, err := GetSchema(schemaDirectoryPath, "kubernetes")
if err != nil {
return nil, err
}
return &deploytest.Provider{
GetSchemaF: func(version int) ([]byte, error) {
return schema, nil
},
}, nil
}

View file

@ -18,10 +18,10 @@ eks_igw = aws.ec2.InternetGateway("eksIgw",
})
eks_route_table = aws.ec2.RouteTable("eksRouteTable",
vpc_id=eks_vpc.id,
routes=[{
"cidr_block": "0.0.0.0/0",
"gateway_id": eks_igw.id,
}],
routes=[aws.ec2.RouteTableRouteArgs(
cidr_block="0.0.0.0/0",
gateway_id=eks_igw.id,
)],
tags={
"Name": "pulumi-vpc-rt",
})
@ -51,20 +51,20 @@ eks_security_group = aws.ec2.SecurityGroup("eksSecurityGroup",
"Name": "pulumi-cluster-sg",
},
ingress=[
{
"cidr_blocks": ["0.0.0.0/0"],
"from_port": 443,
"to_port": 443,
"protocol": "tcp",
"description": "Allow pods to communicate with the cluster API Server.",
},
{
"cidr_blocks": ["0.0.0.0/0"],
"from_port": 80,
"to_port": 80,
"protocol": "tcp",
"description": "Allow internet access to pods",
},
aws.ec2.SecurityGroupIngressArgs(
cidr_blocks=["0.0.0.0/0"],
from_port=443,
to_port=443,
protocol="tcp",
description="Allow pods to communicate with the cluster API Server.",
),
aws.ec2.SecurityGroupIngressArgs(
cidr_blocks=["0.0.0.0/0"],
from_port=80,
to_port=80,
protocol="tcp",
description="Allow internet access to pods",
),
])
# EKS Cluster Role
eks_role = aws.iam.Role("eksRole", assume_role_policy=json.dumps({
@ -111,11 +111,11 @@ eks_cluster = aws.eks.Cluster("eksCluster",
tags={
"Name": "pulumi-eks-cluster",
},
vpc_config={
"publicAccessCidrs": ["0.0.0.0/0"],
"security_group_ids": [eks_security_group.id],
"subnet_ids": subnet_ids,
})
vpc_config=aws.eks.ClusterVpcConfigArgs(
public_access_cidrs=["0.0.0.0/0"],
security_group_ids=[eks_security_group.id],
subnet_ids=subnet_ids,
))
node_group = aws.eks.NodeGroup("nodeGroup",
cluster_name=eks_cluster.name,
node_group_name="pulumi-eks-nodegroup",
@ -124,18 +124,18 @@ node_group = aws.eks.NodeGroup("nodeGroup",
tags={
"Name": "pulumi-cluster-nodeGroup",
},
scaling_config={
"desiredSize": 2,
"max_size": 2,
"min_size": 1,
})
scaling_config=aws.eks.NodeGroupScalingConfigArgs(
desired_size=2,
max_size=2,
min_size=1,
))
pulumi.export("clusterName", eks_cluster.name)
pulumi.export("kubeconfig", pulumi.Output.all(eks_cluster.endpoint, eks_cluster.certificate_authority, eks_cluster.name).apply(lambda endpoint, certificate_authority, name: json.dumps({
"apiVersion": "v1",
"clusters": [{
"cluster": {
"server": endpoint,
"certificate-authority-data": certificate_authority["data"],
"certificate-authority-data": certificate_authority.data,
},
"name": "kubernetes",
}],

View file

@ -7,18 +7,18 @@ subnets = aws.ec2.get_subnet_ids(vpc_id=vpc.id)
# Create a security group that permits HTTP ingress and unrestricted egress.
web_security_group = aws.ec2.SecurityGroup("webSecurityGroup",
vpc_id=vpc.id,
egress=[{
"protocol": "-1",
"from_port": 0,
"to_port": 0,
"cidr_blocks": ["0.0.0.0/0"],
}],
ingress=[{
"protocol": "tcp",
"from_port": 80,
"to_port": 80,
"cidr_blocks": ["0.0.0.0/0"],
}])
egress=[aws.ec2.SecurityGroupEgressArgs(
protocol="-1",
from_port=0,
to_port=0,
cidr_blocks=["0.0.0.0/0"],
)],
ingress=[aws.ec2.SecurityGroupIngressArgs(
protocol="tcp",
from_port=80,
to_port=80,
cidr_blocks=["0.0.0.0/0"],
)])
# Create an ECS cluster to run a container-based service.
cluster = aws.ecs.Cluster("cluster")
# Create an IAM role that can be used by our service's task.
@ -48,10 +48,10 @@ web_target_group = aws.elasticloadbalancingv2.TargetGroup("webTargetGroup",
web_listener = aws.elasticloadbalancingv2.Listener("webListener",
load_balancer_arn=web_load_balancer.arn,
port=80,
default_actions=[{
"type": "forward",
"target_group_arn": web_target_group.arn,
}])
default_actions=[aws.elasticloadbalancingv2.ListenerDefaultActionArgs(
type="forward",
target_group_arn=web_target_group.arn,
)])
# Spin up a load balanced service running NGINX
app_task = aws.ecs.TaskDefinition("appTask",
family="fargate-task-definition",
@ -74,15 +74,15 @@ app_service = aws.ecs.Service("appService",
desired_count=5,
launch_type="FARGATE",
task_definition=app_task.arn,
network_configuration={
"assignPublicIp": True,
"subnets": subnets.ids,
"security_groups": [web_security_group.id],
},
load_balancers=[{
"target_group_arn": web_target_group.arn,
"container_name": "my-app",
"containerPort": 80,
}],
network_configuration=aws.ecs.ServiceNetworkConfigurationArgs(
assign_public_ip=True,
subnets=subnets.ids,
security_groups=[web_security_group.id],
),
load_balancers=[aws.ecs.ServiceLoadBalancerArgs(
target_group_arn=web_target_group.arn,
container_name="my-app",
container_port=80,
)],
opts=ResourceOptions(depends_on=[web_listener]))
pulumi.export("url", web_load_balancer.dns_name)

View file

@ -4,9 +4,9 @@ import os
import pulumi_aws as aws
# Create a bucket and expose a website index document
site_bucket = aws.s3.Bucket("siteBucket", website={
"indexDocument": "index.html",
})
site_bucket = aws.s3.Bucket("siteBucket", website=aws.s3.BucketWebsiteArgs(
index_document="index.html",
))
site_dir = "www"
# For each file in the directory, create an S3 object stored in `siteBucket`
files = []

View file

@ -2,7 +2,7 @@ import pulumi
import pulumi_aws as aws
logs = aws.s3.Bucket("logs")
bucket = aws.s3.Bucket("bucket", loggings=[{
"targetBucket": logs.bucket,
}])
pulumi.export("targetBucket", bucket.loggings[0]["targetBucket"])
bucket = aws.s3.Bucket("bucket", loggings=[aws.s3.BucketLoggingArgs(
target_bucket=logs.bucket,
)])
pulumi.export("targetBucket", bucket.loggings[0].target_bucket)

View file

@ -2,16 +2,16 @@ import pulumi
import pulumi_aws as aws
# Create a new security group for port 80.
security_group = aws.ec2.SecurityGroup("securityGroup", ingress=[{
"protocol": "tcp",
"from_port": 0,
"to_port": 0,
"cidr_blocks": ["0.0.0.0/0"],
}])
ami = aws.get_ami(filters=[{
"name": "name",
"values": ["amzn-ami-hvm-*-x86_64-ebs"],
}],
security_group = aws.ec2.SecurityGroup("securityGroup", ingress=[aws.ec2.SecurityGroupIngressArgs(
protocol="tcp",
from_port=0,
to_port=0,
cidr_blocks=["0.0.0.0/0"],
)])
ami = aws.get_ami(filters=[aws.GetAmiFilterArgs(
name="name",
values=["amzn-ami-hvm-*-x86_64-ebs"],
)],
owners=["137112412989"],
most_recent=True)
# Create a simple web server using the startup script for the instance.

View file

@ -139937,7 +139937,8 @@
"readme": "\u003e This provider is a derived work of the [Terraform Provider](https://github.com/terraform-providers/terraform-provider-aws)\n\u003e distributed under [MPL 2.0](https://www.mozilla.org/en-US/MPL/2.0/). If you encounter a bug or missing feature,\n\u003e first check the [`pulumi/pulumi-aws` repo](https://github.com/pulumi/pulumi-aws/issues); however, if that doesn't turn up anything,\n\u003e please consult the source [`terraform-providers/terraform-provider-aws` repo](https://github.com/terraform-providers/terraform-provider-aws/issues).",
"requires": {
"pulumi": "\u003e=2.0.0,\u003c3.0.0"
}
},
"usesIOClasses": true
}
}
}
}

View file

@ -0,0 +1,214 @@
resource pulumi_kubernetes_operatorDeployment "kubernetes:apps/v1:Deployment" {
apiVersion = "apps/v1"
kind = "Deployment"
metadata = {
name = "pulumi-kubernetes-operator"
}
spec = {
# Currently only 1 replica supported, until leader election: https://github.com/pulumi/pulumi-kubernetes-operator/issues/33
replicas = 1
selector = {
matchLabels = {
name = "pulumi-kubernetes-operator"
}
}
template = {
metadata = {
labels = {
name = "pulumi-kubernetes-operator"
}
}
spec = {
serviceAccountName = "pulumi-kubernetes-operator"
imagePullSecrets = [
{
name = "pulumi-kubernetes-operator"
}
]
containers = [
{
name = "pulumi-kubernetes-operator"
image = "pulumi/pulumi-kubernetes-operator:v0.0.2"
command = [
"pulumi-kubernetes-operator"
]
args = [
"--zap-level=debug"
]
imagePullPolicy = "Always"
env = [
{
name = "WATCH_NAMESPACE"
valueFrom = {
fieldRef = {
fieldPath = "metadata.namespace"
}
}
},
{
name = "POD_NAME"
valueFrom = {
fieldRef = {
fieldPath = "metadata.name"
}
}
},
{
name = "OPERATOR_NAME"
value = "pulumi-kubernetes-operator"
}
]
}
]
}
}
}
}
resource pulumi_kubernetes_operatorRole "kubernetes:rbac.authorization.k8s.io/v1:Role" {
apiVersion = "rbac.authorization.k8s.io/v1"
kind = "Role"
metadata = {
creationTimestamp = null
name = "pulumi-kubernetes-operator"
}
rules = [
{
apiGroups = [
""
]
resources = [
"pods",
"services",
"services/finalizers",
"endpoints",
"persistentvolumeclaims",
"events",
"configmaps",
"secrets"
]
verbs = [
"create",
"delete",
"get",
"list",
"patch",
"update",
"watch"
]
},
{
apiGroups = [
"apps"
]
resources = [
"deployments",
"daemonsets",
"replicasets",
"statefulsets"
]
verbs = [
"create",
"delete",
"get",
"list",
"patch",
"update",
"watch"
]
},
{
apiGroups = [
"monitoring.coreos.com"
]
resources = [
"servicemonitors"
]
verbs = [
"get",
"create"
]
},
{
apiGroups = [
"apps"
]
resourceNames = [
"pulumi-kubernetes-operator"
]
resources = [
"deployments/finalizers"
]
verbs = [
"update"
]
},
{
apiGroups = [
""
]
resources = [
"pods"
]
verbs = [
"get"
]
},
{
apiGroups = [
"apps"
]
resources = [
"replicasets",
"deployments"
]
verbs = [
"get"
]
},
{
apiGroups = [
"pulumi.com"
]
resources = [
"*"
]
verbs = [
"create",
"delete",
"get",
"list",
"patch",
"update",
"watch"
]
}
]
}
resource pulumi_kubernetes_operatorRoleBinding "kubernetes:rbac.authorization.k8s.io/v1:RoleBinding" {
kind = "RoleBinding"
apiVersion = "rbac.authorization.k8s.io/v1"
metadata = {
name = "pulumi-kubernetes-operator"
}
subjects = [
{
kind = "ServiceAccount"
name = "pulumi-kubernetes-operator"
}
]
roleRef = {
kind = "Role"
name = "pulumi-kubernetes-operator"
apiGroup = "rbac.authorization.k8s.io"
}
}
resource pulumi_kubernetes_operatorServiceAccount "kubernetes:core/v1:ServiceAccount" {
apiVersion = "v1"
kind = "ServiceAccount"
metadata = {
name = "pulumi-kubernetes-operator"
}
}

View file

@ -0,0 +1,282 @@
using Pulumi;
using Kubernetes = Pulumi.Kubernetes;
class MyStack : Stack
{
public MyStack()
{
var pulumi_kubernetes_operatorDeployment = new Kubernetes.Apps.V1.Deployment("pulumi_kubernetes_operatorDeployment", new Kubernetes.Types.Inputs.Apps.V1.DeploymentArgs
{
ApiVersion = "apps/v1",
Kind = "Deployment",
Metadata = new Kubernetes.Types.Inputs.Meta.V1.ObjectMetaArgs
{
Name = "pulumi-kubernetes-operator",
},
Spec = new Kubernetes.Types.Inputs.Apps.V1.DeploymentSpecArgs
{
Replicas = 1,
Selector = new Kubernetes.Types.Inputs.Meta.V1.LabelSelectorArgs
{
MatchLabels =
{
{ "name", "pulumi-kubernetes-operator" },
},
},
Template = new Kubernetes.Types.Inputs.Core.V1.PodTemplateSpecArgs
{
Metadata = new Kubernetes.Types.Inputs.Meta.V1.ObjectMetaArgs
{
Labels =
{
{ "name", "pulumi-kubernetes-operator" },
},
},
Spec = new Kubernetes.Types.Inputs.Core.V1.PodSpecArgs
{
ServiceAccountName = "pulumi-kubernetes-operator",
ImagePullSecrets =
{
new Kubernetes.Types.Inputs.Core.V1.LocalObjectReferenceArgs
{
Name = "pulumi-kubernetes-operator",
},
},
Containers =
{
new Kubernetes.Types.Inputs.Core.V1.ContainerArgs
{
Name = "pulumi-kubernetes-operator",
Image = "pulumi/pulumi-kubernetes-operator:v0.0.2",
Command =
{
"pulumi-kubernetes-operator",
},
Args =
{
"--zap-level=debug",
},
ImagePullPolicy = "Always",
Env =
{
new Kubernetes.Types.Inputs.Core.V1.EnvVarArgs
{
Name = "WATCH_NAMESPACE",
ValueFrom = new Kubernetes.Types.Inputs.Core.V1.EnvVarSourceArgs
{
FieldRef = new Kubernetes.Types.Inputs.Core.V1.ObjectFieldSelectorArgs
{
FieldPath = "metadata.namespace",
},
},
},
new Kubernetes.Types.Inputs.Core.V1.EnvVarArgs
{
Name = "POD_NAME",
ValueFrom = new Kubernetes.Types.Inputs.Core.V1.EnvVarSourceArgs
{
FieldRef = new Kubernetes.Types.Inputs.Core.V1.ObjectFieldSelectorArgs
{
FieldPath = "metadata.name",
},
},
},
new Kubernetes.Types.Inputs.Core.V1.EnvVarArgs
{
Name = "OPERATOR_NAME",
Value = "pulumi-kubernetes-operator",
},
},
},
},
},
},
},
});
var pulumi_kubernetes_operatorRole = new Kubernetes.Rbac.V1.Role("pulumi_kubernetes_operatorRole", new Kubernetes.Types.Inputs.Rbac.V1.RoleArgs
{
ApiVersion = "rbac.authorization.k8s.io/v1",
Kind = "Role",
Metadata = new Kubernetes.Types.Inputs.Meta.V1.ObjectMetaArgs
{
CreationTimestamp = null,
Name = "pulumi-kubernetes-operator",
},
Rules =
{
new Kubernetes.Types.Inputs.Rbac.V1.PolicyRuleArgs
{
ApiGroups =
{
"",
},
Resources =
{
"pods",
"services",
"services/finalizers",
"endpoints",
"persistentvolumeclaims",
"events",
"configmaps",
"secrets",
},
Verbs =
{
"create",
"delete",
"get",
"list",
"patch",
"update",
"watch",
},
},
new Kubernetes.Types.Inputs.Rbac.V1.PolicyRuleArgs
{
ApiGroups =
{
"apps",
},
Resources =
{
"deployments",
"daemonsets",
"replicasets",
"statefulsets",
},
Verbs =
{
"create",
"delete",
"get",
"list",
"patch",
"update",
"watch",
},
},
new Kubernetes.Types.Inputs.Rbac.V1.PolicyRuleArgs
{
ApiGroups =
{
"monitoring.coreos.com",
},
Resources =
{
"servicemonitors",
},
Verbs =
{
"get",
"create",
},
},
new Kubernetes.Types.Inputs.Rbac.V1.PolicyRuleArgs
{
ApiGroups =
{
"apps",
},
ResourceNames =
{
"pulumi-kubernetes-operator",
},
Resources =
{
"deployments/finalizers",
},
Verbs =
{
"update",
},
},
new Kubernetes.Types.Inputs.Rbac.V1.PolicyRuleArgs
{
ApiGroups =
{
"",
},
Resources =
{
"pods",
},
Verbs =
{
"get",
},
},
new Kubernetes.Types.Inputs.Rbac.V1.PolicyRuleArgs
{
ApiGroups =
{
"apps",
},
Resources =
{
"replicasets",
"deployments",
},
Verbs =
{
"get",
},
},
new Kubernetes.Types.Inputs.Rbac.V1.PolicyRuleArgs
{
ApiGroups =
{
"pulumi.com",
},
Resources =
{
"*",
},
Verbs =
{
"create",
"delete",
"get",
"list",
"patch",
"update",
"watch",
},
},
},
});
var pulumi_kubernetes_operatorRoleBinding = new Kubernetes.Rbac.V1.RoleBinding("pulumi_kubernetes_operatorRoleBinding", new Kubernetes.Types.Inputs.Rbac.V1.RoleBindingArgs
{
Kind = "RoleBinding",
ApiVersion = "rbac.authorization.k8s.io/v1",
Metadata = new Kubernetes.Types.Inputs.Meta.V1.ObjectMetaArgs
{
Name = "pulumi-kubernetes-operator",
},
Subjects =
{
new Kubernetes.Types.Inputs.Rbac.V1.SubjectArgs
{
Kind = "ServiceAccount",
Name = "pulumi-kubernetes-operator",
},
},
RoleRef = new Kubernetes.Types.Inputs.Rbac.V1.RoleRefArgs
{
Kind = "Role",
Name = "pulumi-kubernetes-operator",
ApiGroup = "rbac.authorization.k8s.io",
},
});
var pulumi_kubernetes_operatorServiceAccount = new Kubernetes.Core.V1.ServiceAccount("pulumi_kubernetes_operatorServiceAccount", new Kubernetes.Types.Inputs.Core.V1.ServiceAccountArgs
{
ApiVersion = "v1",
Kind = "ServiceAccount",
Metadata = new Kubernetes.Types.Inputs.Meta.V1.ObjectMetaArgs
{
Name = "pulumi-kubernetes-operator",
},
});
}
}

View file

@ -0,0 +1,237 @@
package main
import (
appsv1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/apps/v1"
corev1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/core/v1"
metav1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/meta/v1"
rbacv1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/rbac/v1"
"github.com/pulumi/pulumi/sdk/v2/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := appsv1.NewDeployment(ctx, "pulumi_kubernetes_operatorDeployment", &appsv1.DeploymentArgs{
ApiVersion: pulumi.String("apps/v1"),
Kind: pulumi.String("Deployment"),
Metadata: &metav1.ObjectMetaArgs{
Name: pulumi.String("pulumi-kubernetes-operator"),
},
Spec: &appsv1.DeploymentSpecArgs{
Replicas: pulumi.Int(1),
Selector: &metav1.LabelSelectorArgs{
MatchLabels: pulumi.StringMap{
"name": pulumi.String("pulumi-kubernetes-operator"),
},
},
Template: &corev1.PodTemplateSpecArgs{
Metadata: &metav1.ObjectMetaArgs{
Labels: pulumi.StringMap{
"name": pulumi.String("pulumi-kubernetes-operator"),
},
},
Spec: &corev1.PodSpecArgs{
ServiceAccountName: pulumi.String("pulumi-kubernetes-operator"),
ImagePullSecrets: corev1.LocalObjectReferenceArray{
&corev1.LocalObjectReferenceArgs{
Name: pulumi.String("pulumi-kubernetes-operator"),
},
},
Containers: corev1.ContainerArray{
&corev1.ContainerArgs{
Name: pulumi.String("pulumi-kubernetes-operator"),
Image: pulumi.String("pulumi/pulumi-kubernetes-operator:v0.0.2"),
Command: pulumi.StringArray{
pulumi.String("pulumi-kubernetes-operator"),
},
Args: pulumi.StringArray{
pulumi.String("--zap-level=debug"),
},
ImagePullPolicy: pulumi.String("Always"),
Env: corev1.EnvVarArray{
&corev1.EnvVarArgs{
Name: pulumi.String("WATCH_NAMESPACE"),
ValueFrom: &corev1.EnvVarSourceArgs{
FieldRef: &corev1.ObjectFieldSelectorArgs{
FieldPath: pulumi.String("metadata.namespace"),
},
},
},
&corev1.EnvVarArgs{
Name: pulumi.String("POD_NAME"),
ValueFrom: &corev1.EnvVarSourceArgs{
FieldRef: &corev1.ObjectFieldSelectorArgs{
FieldPath: pulumi.String("metadata.name"),
},
},
},
&corev1.EnvVarArgs{
Name: pulumi.String("OPERATOR_NAME"),
Value: pulumi.String("pulumi-kubernetes-operator"),
},
},
},
},
},
},
},
})
if err != nil {
return err
}
_, err = rbacv1.NewRole(ctx, "pulumi_kubernetes_operatorRole", &rbacv1.RoleArgs{
ApiVersion: pulumi.String("rbac.authorization.k8s.io/v1"),
Kind: pulumi.String("Role"),
Metadata: &metav1.ObjectMetaArgs{
CreationTimestamp: nil,
Name: pulumi.String("pulumi-kubernetes-operator"),
},
Rules: rbacv1.PolicyRuleArray{
&rbacv1.PolicyRuleArgs{
ApiGroups: pulumi.StringArray{
pulumi.String(""),
},
Resources: pulumi.StringArray{
pulumi.String("pods"),
pulumi.String("services"),
pulumi.String("services/finalizers"),
pulumi.String("endpoints"),
pulumi.String("persistentvolumeclaims"),
pulumi.String("events"),
pulumi.String("configmaps"),
pulumi.String("secrets"),
},
Verbs: pulumi.StringArray{
pulumi.String("create"),
pulumi.String("delete"),
pulumi.String("get"),
pulumi.String("list"),
pulumi.String("patch"),
pulumi.String("update"),
pulumi.String("watch"),
},
},
&rbacv1.PolicyRuleArgs{
ApiGroups: pulumi.StringArray{
pulumi.String("apps"),
},
Resources: pulumi.StringArray{
pulumi.String("deployments"),
pulumi.String("daemonsets"),
pulumi.String("replicasets"),
pulumi.String("statefulsets"),
},
Verbs: pulumi.StringArray{
pulumi.String("create"),
pulumi.String("delete"),
pulumi.String("get"),
pulumi.String("list"),
pulumi.String("patch"),
pulumi.String("update"),
pulumi.String("watch"),
},
},
&rbacv1.PolicyRuleArgs{
ApiGroups: pulumi.StringArray{
pulumi.String("monitoring.coreos.com"),
},
Resources: pulumi.StringArray{
pulumi.String("servicemonitors"),
},
Verbs: pulumi.StringArray{
pulumi.String("get"),
pulumi.String("create"),
},
},
&rbacv1.PolicyRuleArgs{
ApiGroups: pulumi.StringArray{
pulumi.String("apps"),
},
ResourceNames: pulumi.StringArray{
pulumi.String("pulumi-kubernetes-operator"),
},
Resources: pulumi.StringArray{
pulumi.String("deployments/finalizers"),
},
Verbs: pulumi.StringArray{
pulumi.String("update"),
},
},
&rbacv1.PolicyRuleArgs{
ApiGroups: pulumi.StringArray{
pulumi.String(""),
},
Resources: pulumi.StringArray{
pulumi.String("pods"),
},
Verbs: pulumi.StringArray{
pulumi.String("get"),
},
},
&rbacv1.PolicyRuleArgs{
ApiGroups: pulumi.StringArray{
pulumi.String("apps"),
},
Resources: pulumi.StringArray{
pulumi.String("replicasets"),
pulumi.String("deployments"),
},
Verbs: pulumi.StringArray{
pulumi.String("get"),
},
},
&rbacv1.PolicyRuleArgs{
ApiGroups: pulumi.StringArray{
pulumi.String("pulumi.com"),
},
Resources: pulumi.StringArray{
pulumi.String("*"),
},
Verbs: pulumi.StringArray{
pulumi.String("create"),
pulumi.String("delete"),
pulumi.String("get"),
pulumi.String("list"),
pulumi.String("patch"),
pulumi.String("update"),
pulumi.String("watch"),
},
},
},
})
if err != nil {
return err
}
_, err = rbacv1.NewRoleBinding(ctx, "pulumi_kubernetes_operatorRoleBinding", &rbacv1.RoleBindingArgs{
Kind: pulumi.String("RoleBinding"),
ApiVersion: pulumi.String("rbac.authorization.k8s.io/v1"),
Metadata: &metav1.ObjectMetaArgs{
Name: pulumi.String("pulumi-kubernetes-operator"),
},
Subjects: rbacv1.SubjectArray{
&rbacv1.SubjectArgs{
Kind: pulumi.String("ServiceAccount"),
Name: pulumi.String("pulumi-kubernetes-operator"),
},
},
RoleRef: &rbacv1.RoleRefArgs{
Kind: pulumi.String("Role"),
Name: pulumi.String("pulumi-kubernetes-operator"),
ApiGroup: pulumi.String("rbac.authorization.k8s.io"),
},
})
if err != nil {
return err
}
_, err = corev1.NewServiceAccount(ctx, "pulumi_kubernetes_operatorServiceAccount", &corev1.ServiceAccountArgs{
ApiVersion: pulumi.String("v1"),
Kind: pulumi.String("ServiceAccount"),
Metadata: &metav1.ObjectMetaArgs{
Name: pulumi.String("pulumi-kubernetes-operator"),
},
})
if err != nil {
return err
}
return nil
})
}

View file

@ -0,0 +1,169 @@
import pulumi
import pulumi_kubernetes as kubernetes
pulumi_kubernetes_operator_deployment = kubernetes.apps.v1.Deployment("pulumi_kubernetes_operatorDeployment",
api_version="apps/v1",
kind="Deployment",
metadata={
"name": "pulumi-kubernetes-operator",
},
spec={
"replicas": 1,
"selector": {
"match_labels": {
"name": "pulumi-kubernetes-operator",
},
},
"template": {
"metadata": {
"labels": {
"name": "pulumi-kubernetes-operator",
},
},
"spec": {
"service_account_name": "pulumi-kubernetes-operator",
"image_pull_secrets": [{
"name": "pulumi-kubernetes-operator",
}],
"containers": [{
"name": "pulumi-kubernetes-operator",
"image": "pulumi/pulumi-kubernetes-operator:v0.0.2",
"command": ["pulumi-kubernetes-operator"],
"args": ["--zap-level=debug"],
"image_pull_policy": "Always",
"env": [
{
"name": "WATCH_NAMESPACE",
"value_from": {
"field_ref": {
"field_path": "metadata.namespace",
},
},
},
{
"name": "POD_NAME",
"value_from": {
"field_ref": {
"field_path": "metadata.name",
},
},
},
{
"name": "OPERATOR_NAME",
"value": "pulumi-kubernetes-operator",
},
],
}],
},
},
})
pulumi_kubernetes_operator_role = kubernetes.rbac.v1.Role("pulumi_kubernetes_operatorRole",
api_version="rbac.authorization.k8s.io/v1",
kind="Role",
metadata={
"creation_timestamp": None,
"name": "pulumi-kubernetes-operator",
},
rules=[
{
"api_groups": [""],
"resources": [
"pods",
"services",
"services/finalizers",
"endpoints",
"persistentvolumeclaims",
"events",
"configmaps",
"secrets",
],
"verbs": [
"create",
"delete",
"get",
"list",
"patch",
"update",
"watch",
],
},
{
"api_groups": ["apps"],
"resources": [
"deployments",
"daemonsets",
"replicasets",
"statefulsets",
],
"verbs": [
"create",
"delete",
"get",
"list",
"patch",
"update",
"watch",
],
},
{
"api_groups": ["monitoring.coreos.com"],
"resources": ["servicemonitors"],
"verbs": [
"get",
"create",
],
},
{
"api_groups": ["apps"],
"resource_names": ["pulumi-kubernetes-operator"],
"resources": ["deployments/finalizers"],
"verbs": ["update"],
},
{
"api_groups": [""],
"resources": ["pods"],
"verbs": ["get"],
},
{
"api_groups": ["apps"],
"resources": [
"replicasets",
"deployments",
],
"verbs": ["get"],
},
{
"api_groups": ["pulumi.com"],
"resources": ["*"],
"verbs": [
"create",
"delete",
"get",
"list",
"patch",
"update",
"watch",
],
},
])
pulumi_kubernetes_operator_role_binding = kubernetes.rbac.v1.RoleBinding("pulumi_kubernetes_operatorRoleBinding",
kind="RoleBinding",
api_version="rbac.authorization.k8s.io/v1",
metadata={
"name": "pulumi-kubernetes-operator",
},
subjects=[{
"kind": "ServiceAccount",
"name": "pulumi-kubernetes-operator",
}],
role_ref={
"kind": "Role",
"name": "pulumi-kubernetes-operator",
"api_group": "rbac.authorization.k8s.io",
})
pulumi_kubernetes_operator_service_account = kubernetes.core.v1.ServiceAccount("pulumi_kubernetes_operatorServiceAccount",
api_version="v1",
kind="ServiceAccount",
metadata={
"name": "pulumi-kubernetes-operator",
})

View file

@ -0,0 +1,173 @@
import * as pulumi from "@pulumi/pulumi";
import * as kubernetes from "@pulumi/kubernetes";
const pulumi_kubernetes_operatorDeployment = new kubernetes.apps.v1.Deployment("pulumi_kubernetes_operatorDeployment", {
apiVersion: "apps/v1",
kind: "Deployment",
metadata: {
name: "pulumi-kubernetes-operator",
},
spec: {
replicas: 1,
selector: {
matchLabels: {
name: "pulumi-kubernetes-operator",
},
},
template: {
metadata: {
labels: {
name: "pulumi-kubernetes-operator",
},
},
spec: {
serviceAccountName: "pulumi-kubernetes-operator",
imagePullSecrets: [{
name: "pulumi-kubernetes-operator",
}],
containers: [{
name: "pulumi-kubernetes-operator",
image: "pulumi/pulumi-kubernetes-operator:v0.0.2",
command: ["pulumi-kubernetes-operator"],
args: ["--zap-level=debug"],
imagePullPolicy: "Always",
env: [
{
name: "WATCH_NAMESPACE",
valueFrom: {
fieldRef: {
fieldPath: "metadata.namespace",
},
},
},
{
name: "POD_NAME",
valueFrom: {
fieldRef: {
fieldPath: "metadata.name",
},
},
},
{
name: "OPERATOR_NAME",
value: "pulumi-kubernetes-operator",
},
],
}],
},
},
},
});
const pulumi_kubernetes_operatorRole = new kubernetes.rbac.v1.Role("pulumi_kubernetes_operatorRole", {
apiVersion: "rbac.authorization.k8s.io/v1",
kind: "Role",
metadata: {
creationTimestamp: undefined,
name: "pulumi-kubernetes-operator",
},
rules: [
{
apiGroups: [""],
resources: [
"pods",
"services",
"services/finalizers",
"endpoints",
"persistentvolumeclaims",
"events",
"configmaps",
"secrets",
],
verbs: [
"create",
"delete",
"get",
"list",
"patch",
"update",
"watch",
],
},
{
apiGroups: ["apps"],
resources: [
"deployments",
"daemonsets",
"replicasets",
"statefulsets",
],
verbs: [
"create",
"delete",
"get",
"list",
"patch",
"update",
"watch",
],
},
{
apiGroups: ["monitoring.coreos.com"],
resources: ["servicemonitors"],
verbs: [
"get",
"create",
],
},
{
apiGroups: ["apps"],
resourceNames: ["pulumi-kubernetes-operator"],
resources: ["deployments/finalizers"],
verbs: ["update"],
},
{
apiGroups: [""],
resources: ["pods"],
verbs: ["get"],
},
{
apiGroups: ["apps"],
resources: [
"replicasets",
"deployments",
],
verbs: ["get"],
},
{
apiGroups: ["pulumi.com"],
resources: ["*"],
verbs: [
"create",
"delete",
"get",
"list",
"patch",
"update",
"watch",
],
},
],
});
const pulumi_kubernetes_operatorRoleBinding = new kubernetes.rbac.v1.RoleBinding("pulumi_kubernetes_operatorRoleBinding", {
kind: "RoleBinding",
apiVersion: "rbac.authorization.k8s.io/v1",
metadata: {
name: "pulumi-kubernetes-operator",
},
subjects: [{
kind: "ServiceAccount",
name: "pulumi-kubernetes-operator",
}],
roleRef: {
kind: "Role",
name: "pulumi-kubernetes-operator",
apiGroup: "rbac.authorization.k8s.io",
},
});
const pulumi_kubernetes_operatorServiceAccount = new kubernetes.core.v1.ServiceAccount("pulumi_kubernetes_operatorServiceAccount", {
apiVersion: "v1",
kind: "ServiceAccount",
metadata: {
name: "pulumi-kubernetes-operator",
},
});

View file

@ -0,0 +1,22 @@
resource bar "kubernetes:core/v1:Pod" {
apiVersion = "v1"
kind = "Pod"
metadata = {
namespace = "foo"
name = "bar"
}
spec = {
containers = [
{
name = "nginx"
image = "nginx:1.14-alpine"
resources = {
limits = {
memory = "20Mi"
cpu = 0.2
}
}
}
]
}
}

View file

@ -0,0 +1,39 @@
using Pulumi;
using Kubernetes = Pulumi.Kubernetes;
class MyStack : Stack
{
public MyStack()
{
var bar = new Kubernetes.Core.V1.Pod("bar", new Kubernetes.Types.Inputs.Core.V1.PodArgs
{
ApiVersion = "v1",
Kind = "Pod",
Metadata = new Kubernetes.Types.Inputs.Meta.V1.ObjectMetaArgs
{
Namespace = "foo",
Name = "bar",
},
Spec = new Kubernetes.Types.Inputs.Core.V1.PodSpecArgs
{
Containers =
{
new Kubernetes.Types.Inputs.Core.V1.ContainerArgs
{
Name = "nginx",
Image = "nginx:1.14-alpine",
Resources = new Kubernetes.Types.Inputs.Core.V1.ResourceRequirementsArgs
{
Limits =
{
{ "memory", "20Mi" },
{ "cpu", "0.2" },
},
},
},
},
},
});
}
}

View file

@ -0,0 +1,38 @@
package main
import (
corev1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/core/v1"
metav1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/meta/v1"
"github.com/pulumi/pulumi/sdk/v2/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := corev1.NewPod(ctx, "bar", &corev1.PodArgs{
ApiVersion: pulumi.String("v1"),
Kind: pulumi.String("Pod"),
Metadata: &metav1.ObjectMetaArgs{
Namespace: pulumi.String("foo"),
Name: pulumi.String("bar"),
},
Spec: &corev1.PodSpecArgs{
Containers: corev1.ContainerArray{
&corev1.ContainerArgs{
Name: pulumi.String("nginx"),
Image: pulumi.String("nginx:1.14-alpine"),
Resources: &corev1.ResourceRequirementsArgs{
Limits: pulumi.StringMap{
"memory": pulumi.String("20Mi"),
"cpu": pulumi.String("0.2"),
},
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}

View file

@ -0,0 +1,22 @@
import pulumi
import pulumi_kubernetes as kubernetes
bar = kubernetes.core.v1.Pod("bar",
api_version="v1",
kind="Pod",
metadata={
"namespace": "foo",
"name": "bar",
},
spec={
"containers": [{
"name": "nginx",
"image": "nginx:1.14-alpine",
"resources": {
"limits": {
"memory": "20Mi",
"cpu": "0.2",
},
},
}],
})

View file

@ -0,0 +1,23 @@
import * as pulumi from "@pulumi/pulumi";
import * as kubernetes from "@pulumi/kubernetes";
const bar = new kubernetes.core.v1.Pod("bar", {
apiVersion: "v1",
kind: "Pod",
metadata: {
namespace: "foo",
name: "bar",
},
spec: {
containers: [{
name: "nginx",
image: "nginx:1.14-alpine",
resources: {
limits: {
memory: "20Mi",
cpu: 0.2,
},
},
}],
},
});

View file

@ -0,0 +1,22 @@
resource argocd_serverDeployment "kubernetes:apps/v1:Deployment" {
apiVersion = "apps/v1"
kind = "Deployment"
metadata = {
name = "argocd-server"
}
spec = {
template = {
spec = {
containers = [
{
readinessProbe = {
httpGet = {
port = 8080
}
}
}
]
}
}
}
}

View file

@ -0,0 +1,41 @@
using Pulumi;
using Kubernetes = Pulumi.Kubernetes;
class MyStack : Stack
{
public MyStack()
{
var argocd_serverDeployment = new Kubernetes.Apps.V1.Deployment("argocd_serverDeployment", new Kubernetes.Types.Inputs.Apps.V1.DeploymentArgs
{
ApiVersion = "apps/v1",
Kind = "Deployment",
Metadata = new Kubernetes.Types.Inputs.Meta.V1.ObjectMetaArgs
{
Name = "argocd-server",
},
Spec = new Kubernetes.Types.Inputs.Apps.V1.DeploymentSpecArgs
{
Template = new Kubernetes.Types.Inputs.Core.V1.PodTemplateSpecArgs
{
Spec = new Kubernetes.Types.Inputs.Core.V1.PodSpecArgs
{
Containers =
{
new Kubernetes.Types.Inputs.Core.V1.ContainerArgs
{
ReadinessProbe = new Kubernetes.Types.Inputs.Core.V1.ProbeArgs
{
HttpGet = new Kubernetes.Types.Inputs.Core.V1.HTTPGetActionArgs
{
Port = 8080,
},
},
},
},
},
},
},
});
}
}

View file

@ -0,0 +1,39 @@
package main
import (
appsv1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/apps/v1"
corev1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/core/v1"
metav1 "github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/meta/v1"
"github.com/pulumi/pulumi/sdk/v2/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := appsv1.NewDeployment(ctx, "argocd_serverDeployment", &appsv1.DeploymentArgs{
ApiVersion: pulumi.String("apps/v1"),
Kind: pulumi.String("Deployment"),
Metadata: &metav1.ObjectMetaArgs{
Name: pulumi.String("argocd-server"),
},
Spec: &appsv1.DeploymentSpecArgs{
Template: &corev1.PodTemplateSpecArgs{
Spec: &corev1.PodSpecArgs{
Containers: corev1.ContainerArray{
&corev1.ContainerArgs{
ReadinessProbe: &corev1.ProbeArgs{
HttpGet: &corev1.HTTPGetActionArgs{
Port: pulumi.Int(8080),
},
},
},
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}

View file

@ -0,0 +1,22 @@
import pulumi
import pulumi_kubernetes as kubernetes
argocd_server_deployment = kubernetes.apps.v1.Deployment("argocd_serverDeployment",
api_version="apps/v1",
kind="Deployment",
metadata={
"name": "argocd-server",
},
spec={
"template": {
"spec": {
"containers": [{
"readiness_probe": {
"http_get": {
"port": 8080,
},
},
}],
},
},
})

View file

@ -0,0 +1,23 @@
import * as pulumi from "@pulumi/pulumi";
import * as kubernetes from "@pulumi/kubernetes";
const argocd_serverDeployment = new kubernetes.apps.v1.Deployment("argocd_serverDeployment", {
apiVersion: "apps/v1",
kind: "Deployment",
metadata: {
name: "argocd-server",
},
spec: {
template: {
spec: {
containers: [{
readinessProbe: {
httpGet: {
port: 8080,
},
},
}],
},
},
},
});

File diff suppressed because it is too large Load diff

View file

@ -119,7 +119,7 @@ func (d DocLanguageHelper) GetModuleDocLink(pkg *schema.Package, modName string)
if modName == "" {
displayName = fmt.Sprintf("@pulumi/%s", pkg.Name)
} else {
displayName = fmt.Sprintf("@pulumi/%s/%s", pkg.Name, modName)
displayName = fmt.Sprintf("@pulumi/%s/%s", pkg.Name, strings.ToLower(modName))
}
link = d.GetDocLinkForResourceType(pkg, modName, "")
return displayName, link

View file

@ -26,7 +26,6 @@ import (
"path"
"path/filepath"
"reflect"
"regexp"
"sort"
"strconv"
"strings"
@ -38,9 +37,6 @@ import (
"github.com/pulumi/pulumi/sdk/v2/go/common/util/contract"
)
// Match k8s version suffix. Examples include "/v1beta1" and "/v1alpha2".
var k8sVersionSuffix = regexp.MustCompile(`/(v\d+((alpha|beta)\d+)?)$`)
type typeDetails struct {
outputType bool
inputType bool
@ -953,13 +949,20 @@ func (mod *modContext) genTypes() (string, string) {
mod.genHeader(outputs, mod.sdkImports(true, false), imports)
// Build a namespace tree out of the types, then emit them.
namespaces := mod.getNamespaces()
mod.genNamespace(inputs, namespaces[""], true, 0)
mod.genNamespace(outputs, namespaces[""], false, 0)
type namespace struct {
name string
types []*schema.ObjectType
children []*namespace
}
return inputs.String(), outputs.String()
}
type namespace struct {
name string
types []*schema.ObjectType
children []*namespace
}
func (mod *modContext) getNamespaces() map[string]*namespace {
namespaces := map[string]*namespace{}
var getNamespace func(string) *namespace
getNamespace = func(mod string) *namespace {
@ -994,38 +997,35 @@ func (mod *modContext) genTypes() (string, string) {
ns.types = append(ns.types, t)
}
var genNamespace func(io.Writer, *namespace, bool, int)
genNamespace = func(w io.Writer, ns *namespace, input bool, level int) {
indent := strings.Repeat(" ", level)
return namespaces
}
sort.Slice(ns.types, func(i, j int) bool {
return tokenToName(ns.types[i].Token) < tokenToName(ns.types[j].Token)
})
for i, t := range ns.types {
if input && mod.details(t).inputType || !input && mod.details(t).outputType {
mod.genType(w, t, input, level)
if i != len(ns.types)-1 {
fmt.Fprintf(w, "\n")
}
}
}
func (mod *modContext) genNamespace(w io.Writer, ns *namespace, input bool, level int) {
indent := strings.Repeat(" ", level)
sort.Slice(ns.children, func(i, j int) bool {
return ns.children[i].name < ns.children[j].name
})
for i, ns := range ns.children {
fmt.Fprintf(w, "%sexport namespace %s {\n", indent, ns.name)
genNamespace(w, ns, input, level+1)
fmt.Fprintf(w, "%s}\n", indent)
if i != len(ns.children)-1 {
sort.Slice(ns.types, func(i, j int) bool {
return tokenToName(ns.types[i].Token) < tokenToName(ns.types[j].Token)
})
for i, t := range ns.types {
if input && mod.details(t).inputType || !input && mod.details(t).outputType {
mod.genType(w, t, input, level)
if i != len(ns.types)-1 {
fmt.Fprintf(w, "\n")
}
}
}
genNamespace(inputs, namespaces[""], true, 0)
genNamespace(outputs, namespaces[""], false, 0)
return inputs.String(), outputs.String()
sort.Slice(ns.children, func(i, j int) bool {
return ns.children[i].name < ns.children[j].name
})
for i, ns := range ns.children {
fmt.Fprintf(w, "%sexport namespace %s {\n", indent, ns.name)
mod.genNamespace(w, ns, input, level+1)
fmt.Fprintf(w, "%s}\n", indent)
if i != len(ns.children)-1 {
fmt.Fprintf(w, "\n")
}
}
}
type fs map[string][]byte
@ -1170,12 +1170,11 @@ func (mod *modContext) genIndex(exports []string) string {
for _, mod := range mod.children {
child := strings.ToLower(mod.mod)
if mod.compatibility == kubernetes20 {
// Extract version suffix from child modules. Nested versions will have their own index.ts file.
// Example: apps/v1beta1 -> v1beta1
if match := k8sVersionSuffix.FindStringSubmatchIndex(child); len(match) != 0 {
child = child[match[2]:match[3]]
}
// Extract version suffix from child modules. Nested versions will have their own index.ts file.
// Example: apps/v1beta1 -> v1beta1
parts := strings.SplitN(child, "/", 2)
if len(parts) == 2 {
child = parts[1]
}
children.Add(child)
}

View file

@ -22,6 +22,8 @@ import (
"sort"
"strings"
"github.com/pulumi/pulumi/pkg/v2/codegen/schema"
"github.com/hashicorp/hcl/v2"
"github.com/pulumi/pulumi/pkg/v2/codegen"
"github.com/pulumi/pulumi/pkg/v2/codegen/hcl2"
@ -52,6 +54,12 @@ func GenerateProgram(program *hcl2.Program) (map[string][]byte, hcl.Diagnostics,
}
g.Formatter = format.NewFormatter(g)
for _, p := range program.Packages() {
if err := p.ImportLanguages(map[string]schema.Language{"nodejs": Importer}); err != nil {
return nil, nil, err
}
}
var index bytes.Buffer
g.genPreamble(&index, program)
for _, n := range nodes {
@ -215,6 +223,18 @@ func resourceTypeName(r *hcl2.Resource) (string, string, string, hcl.Diagnostics
if pkg == "pulumi" && module == "providers" {
pkg, module, member = member, "", "Provider"
}
// Normalize module.
if r.Schema != nil {
pkg := r.Schema.Package
if lang, ok := pkg.Language["nodejs"]; ok {
pkgInfo := lang.(NodePackageInfo)
if m, ok := pkgInfo.ModuleToPackage[module]; ok {
module = m
}
}
}
return makeValidIdentifier(pkg), strings.Replace(module, "/", ".", -1), title(member), diagnostics
}

View file

@ -411,6 +411,8 @@ func (g *generator) GenLiteralValueExpression(w io.Writer, expr *model.LiteralVa
switch expr.Type() {
case model.BoolType:
g.Fgenf(w, "%v", expr.Value.True())
case model.NoneType:
g.Fgen(w, "undefined")
case model.NumberType:
bf := expr.Value.AsBigFloat()
if i, acc := bf.Int64(); acc == big.Exact {

View file

@ -19,7 +19,6 @@
package python
import (
"errors"
"fmt"
"strings"
@ -82,6 +81,34 @@ func (d DocLanguageHelper) GetDocLinkForBuiltInType(typeName string) string {
// GetLanguageTypeString returns the Python-specific type given a Pulumi schema type.
func (d DocLanguageHelper) GetLanguageTypeString(pkg *schema.Package, moduleName string, t schema.Type, input, optional bool) string {
// TODO[pulumi/pulumi#5145]: Delete this if check once all providers have UsesIOClasses set to true in their
// schema.
if pythonPkgInfo, ok := pkg.Language["python"].(PackageInfo); !ok || !pythonPkgInfo.UsesIOClasses {
return d.GetLanguageTypeStringLegacy(pkg, moduleName, t, input, optional)
}
typeDetails := map[*schema.ObjectType]*typeDetails{}
mod := &modContext{
pkg: pkg,
mod: moduleName,
typeDetails: typeDetails,
}
typeName := mod.typeString(t, input, false /*wrapInput*/, optional /*optional*/, false /*acceptMapping*/)
// Remove any package qualifiers from the type name.
if !input {
typeName = strings.ReplaceAll(typeName, "outputs.", "")
}
// Remove single quote from type names.
typeName = strings.ReplaceAll(typeName, "'", "")
return typeName
}
// TODO[pulumi/pulumi#5145]: Delete this function once all providers have UsesIOClasses set to true in their schema.
// GetLanguageTypeStringLegacy returns the legacy type strings.
func (d DocLanguageHelper) GetLanguageTypeStringLegacy(pkg *schema.Package, moduleName string, t schema.Type, input, optional bool) string {
name := pyType(t)
// The Python SDK generator will simply return "list" or "dict" for enumerables.
@ -101,13 +128,13 @@ func (d DocLanguageHelper) GetLanguageTypeString(pkg *schema.Package, moduleName
types = append(types, e.String())
continue
}
t := d.GetLanguageTypeString(pkg, moduleName, e, input, optional)
t := d.GetLanguageTypeStringLegacy(pkg, moduleName, e, input, optional)
types = append(types, t)
}
return strings.Join(types, " | ")
case *schema.MapType:
if uTy, ok := dTy.ElementType.(*schema.UnionType); ok {
return d.GetLanguageTypeString(pkg, moduleName, uTy, input, optional)
return d.GetLanguageTypeStringLegacy(pkg, moduleName, uTy, input, optional)
}
elType := dTy.ElementType.String()
@ -125,9 +152,10 @@ func (d DocLanguageHelper) GetFunctionName(modName string, f *schema.Function) s
return PyName(tokenToName(f.Token))
}
// GetResourceFunctionResultName is not implemented for Python and returns an empty string.
// GetResourceFunctionResultName returns the name of the result type when a function is used to lookup
// an existing resource.
func (d DocLanguageHelper) GetResourceFunctionResultName(modName string, f *schema.Function) string {
return ""
return title(tokenToName(f.Token)) + "Result"
}
// GenPropertyCaseMap generates the case maps for a property.
@ -140,10 +168,9 @@ func (d DocLanguageHelper) GenPropertyCaseMap(pkg *schema.Package, modName, tool
recordProperty(prop, snakeCaseToCamelCase, camelCaseToSnakeCase, seenTypes)
}
// GetPropertyName is not implemented for Python because property names in Python must use
// property case maps, which need to be generated at each provider's package-level.
// GetPropertyName returns the property name specific to Python.
func (d DocLanguageHelper) GetPropertyName(p *schema.Property) (string, error) {
return "", errors.New("this method is not supported for the python language")
return PyName(p.Name), nil
}
// elementTypeToName returns the type name from an element type of the form

File diff suppressed because it is too large Load diff

View file

@ -75,6 +75,7 @@ func newGenerator(program *hcl2.Program) (*generator, error) {
if err := p.ImportLanguages(map[string]schema.Language{"python": Importer}); err != nil {
return nil, err
}
info, _ := p.Language["python"].(PackageInfo)
// Build the case mapping table.
camelCaseToSnakeCase := map[string]string{}
@ -82,15 +83,17 @@ func newGenerator(program *hcl2.Program) (*generator, error) {
buildCaseMappingTables(p, nil, camelCaseToSnakeCase, seenTypes)
casingTables[PyName(p.Name)] = camelCaseToSnakeCase
// Annotate nested types to indicate they are dictionaries.
for _, t := range p.Types {
if t, ok := t.(*schema.ObjectType); ok {
if t.Language == nil {
t.Language = map[string]interface{}{}
}
t.Language["python"] = objectTypeInfo{
isDictionary: true,
camelCaseToSnakeCase: camelCaseToSnakeCase,
// If this package does not use Input/Output classes, annotate nested types to indicate they are dictionaries.
if !info.UsesIOClasses {
for _, t := range p.Types {
if t, ok := t.(*schema.ObjectType); ok {
if t.Language == nil {
t.Language = map[string]interface{}{}
}
t.Language["python"] = objectTypeInfo{
isDictionary: true,
camelCaseToSnakeCase: camelCaseToSnakeCase,
}
}
}
}
@ -106,7 +109,7 @@ func newGenerator(program *hcl2.Program) (*generator, error) {
return g, nil
}
// genLeadingTrivia generates the list of leading trivia assicated with a given token.
// genLeadingTrivia generates the list of leading trivia associated with a given token.
func (g *generator) genLeadingTrivia(w io.Writer, token syntax.Token) {
// TODO(pdg): whitespace
for _, t := range token.LeadingTrivia {
@ -116,7 +119,7 @@ func (g *generator) genLeadingTrivia(w io.Writer, token syntax.Token) {
}
}
// genTrailingTrivia generates the list of trailing trivia assicated with a given token.
// genTrailingTrivia generates the list of trailing trivia associated with a given token.
func (g *generator) genTrailingTrivia(w io.Writer, token syntax.Token) {
// TODO(pdg): whitespace
for _, t := range token.TrailingTrivia {
@ -126,7 +129,7 @@ func (g *generator) genTrailingTrivia(w io.Writer, token syntax.Token) {
}
}
// genTrivia generates the list of trivia assicated with a given token.
// genTrivia generates the list of trivia associated with a given token.
func (g *generator) genTrivia(w io.Writer, token syntax.Token) {
g.genLeadingTrivia(w, token)
g.genTrailingTrivia(w, token)
@ -194,19 +197,77 @@ func (g *generator) genNode(w io.Writer, n hcl2.Node) {
}
}
// resourceTypeName computes the python package, module, and type name for the given resource.
// resourceTypeName computes the Python package, module, and type name for the given resource.
func resourceTypeName(r *hcl2.Resource) (string, string, string, hcl.Diagnostics) {
// Compute the resource type from the Pulumi type token.
pkg, module, member, diagnostics := r.DecomposeToken()
components := strings.Split(module, ".")
// Normalize module.
if r.Schema != nil {
pkg := r.Schema.Package
if lang, ok := pkg.Language["python"]; ok {
pkgInfo := lang.(PackageInfo)
if m, ok := pkgInfo.ModuleNameOverrides[module]; ok {
module = m
}
}
}
components := strings.Split(module, "/")
for i, component := range components {
components[i] = PyName(component)
}
return PyName(pkg), strings.Join(components, "."), title(member), diagnostics
}
// argumentTypeName computes the Python argument class name for the given expression and model type.
func (g *generator) argumentTypeName(expr model.Expression, destType model.Type) string {
schemaType, ok := hcl2.GetSchemaForType(destType.(model.Type))
if !ok {
return ""
}
objType, ok := schemaType.(*schema.ObjectType)
if !ok {
return ""
}
if objType.Language != nil {
pyTypeInfo, ok := objType.Language["python"].(objectTypeInfo)
if ok {
if pyTypeInfo.isDictionary {
return ""
}
}
}
token := objType.Token
tokenRange := expr.SyntaxNode().Range()
// Example: aws, s3/BucketLogging, BucketLogging, []Diagnostics
pkgName, module, member, diagnostics := hcl2.DecomposeToken(token, tokenRange)
contract.Assert(len(diagnostics) == 0)
modName := objType.Package.TokenToModule(token)
// Normalize module.
pkg := objType.Package
if lang, ok := pkg.Language["python"]; ok {
pkgInfo := lang.(PackageInfo)
if m, ok := pkgInfo.ModuleNameOverrides[module]; ok {
modName = m
}
}
if modName != "" {
modName = "." + PyName(modName)
}
modName = strings.Replace(modName, "_", ".", -1)
member = member + "Args"
// Example: aws.s3.BucketLoggingArgs
return fmt.Sprintf("%s%s.%s", PyName(pkgName), modName, title(member))
}
// makeResourceName returns the expression that should be emitted for a resource's "name" parameter given its base name
// and the count variable name, if any.
func (g *generator) makeResourceName(baseName, count string) string {
@ -231,7 +292,7 @@ func (g *generator) lowerResourceOptions(opts *hcl2.ResourceOptions) (*model.Blo
}
}
value, valueTemps := g.lowerExpression(value)
value, valueTemps := g.lowerExpression(value, value.Type())
temps = append(temps, valueTemps...)
block.Body.Items = append(block.Body.Items, &model.Attribute{
@ -302,12 +363,14 @@ func (g *generator) genResource(w io.Writer, r *hcl2.Resource) {
g.genTrivia(w, r.Definition.Tokens.GetOpenBrace())
casingTable := g.casingTables[pkg]
for _, attr := range r.Inputs {
g.lowerObjectKeys(attr.Value, casingTable)
for _, input := range r.Inputs {
g.lowerObjectKeys(input.Value, casingTable)
value, valueTemps := g.lowerExpression(attr.Value)
destType, diagnostics := r.InputType.Traverse(hcl.TraverseAttr{Name: input.Name})
g.diagnostics = append(g.diagnostics, diagnostics...)
value, valueTemps := g.lowerExpression(input.Value, destType.(model.Type))
temps = append(temps, valueTemps...)
attr.Value = value
input.Value = value
}
g.genTemps(w, temps)
@ -403,7 +466,7 @@ func (g *generator) genConfigVariable(w io.Writer, v *hcl2.ConfigVariable) {
var defaultValue model.Expression
var temps []*quoteTemp
if v.DefaultValue != nil {
defaultValue, temps = g.lowerExpression(v.DefaultValue)
defaultValue, temps = g.lowerExpression(v.DefaultValue, v.DefaultValue.Type())
}
g.genTemps(w, temps)
@ -418,7 +481,7 @@ func (g *generator) genConfigVariable(w io.Writer, v *hcl2.ConfigVariable) {
}
func (g *generator) genLocalVariable(w io.Writer, v *hcl2.LocalVariable) {
value, temps := g.lowerExpression(v.Definition.Value)
value, temps := g.lowerExpression(v.Definition.Value, v.Type())
g.genTemps(w, temps)
// TODO(pdg): trivia
@ -426,7 +489,7 @@ func (g *generator) genLocalVariable(w io.Writer, v *hcl2.LocalVariable) {
}
func (g *generator) genOutputVariable(w io.Writer, v *hcl2.OutputVariable) {
value, temps := g.lowerExpression(v.Value)
value, temps := g.lowerExpression(v.Value, v.Type())
g.genTemps(w, temps)
// TODO(pdg): trivia

View file

@ -23,13 +23,15 @@ func (nameInfo) Format(name string) string {
return PyName(name)
}
func (g *generator) lowerExpression(expr model.Expression) (model.Expression, []*quoteTemp) {
func (g *generator) lowerExpression(expr model.Expression, typ model.Type) (model.Expression, []*quoteTemp) {
// TODO(pdg): diagnostics
expr = hcl2.RewritePropertyReferences(expr)
expr, _ = hcl2.RewriteApplies(expr, nameInfo(0), false)
expr, _ = g.lowerProxyApplies(expr)
expr = hcl2.RewriteConversions(expr, typ)
expr, quotes, _ := g.rewriteQuotes(expr)
return expr, quotes
}
@ -169,7 +171,7 @@ func (g *generator) genApply(w io.Writer, expr *model.FunctionCallExpression) {
}
}
// functionName computes the NodeJS package, module, and name for the given function token.
// functionName computes the Python package, module, and name for the given function token.
func functionName(tokenArg model.Expression) (string, string, string, hcl.Diagnostics) {
token := tokenArg.(*model.TemplateExpression).Parts[0].(*model.LiteralValueExpression).Value.AsString()
tokenRange := tokenArg.SyntaxNode().Range()
@ -198,6 +200,13 @@ func (g *generator) getFunctionImports(x *model.FunctionCallExpression) string {
func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionCallExpression) {
switch expr.Name {
case hcl2.IntrinsicConvert:
switch arg := expr.Args[0].(type) {
case *model.ObjectConsExpression:
g.genObjectConsExpression(w, arg, expr.Type())
default:
g.Fgenf(w, "%.v", expr.Args[0])
}
case hcl2.IntrinsicApply:
g.genApply(w, expr)
case "element":
@ -226,29 +235,31 @@ func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionC
g.Fgenf(w, "%s(", name)
casingTable := g.casingTables[pkg]
if obj, ok := expr.Args[1].(*model.ObjectConsExpression); ok {
g.lowerObjectKeys(expr.Args[1], casingTable)
if obj, ok := expr.Args[1].(*model.FunctionCallExpression); ok {
if obj, ok := obj.Args[0].(*model.ObjectConsExpression); ok {
g.lowerObjectKeys(expr.Args[1], casingTable)
indenter := func(f func()) { f() }
if len(obj.Items) > 1 {
indenter = g.Indented
}
indenter(func() {
for i, item := range obj.Items {
// Ignore non-literal keys
key, ok := item.Key.(*model.LiteralValueExpression)
if !ok || !key.Value.Type().Equals(cty.String) {
continue
}
keyVal := PyName(key.Value.AsString())
if i == 0 {
g.Fgenf(w, "%s=%.v", keyVal, item.Value)
} else {
g.Fgenf(w, ",\n%s%s=%.v", g.Indent, keyVal, item.Value)
}
indenter := func(f func()) { f() }
if len(obj.Items) > 1 {
indenter = g.Indented
}
})
indenter(func() {
for i, item := range obj.Items {
// Ignore non-literal keys
key, ok := item.Key.(*model.LiteralValueExpression)
if !ok || !key.Value.Type().Equals(cty.String) {
continue
}
keyVal := PyName(key.Value.AsString())
if i == 0 {
g.Fgenf(w, "%s=%.v", keyVal, item.Value)
} else {
g.Fgenf(w, ",\n%s%s=%.v", g.Indent, keyVal, item.Value)
}
}
})
}
}
g.Fgenf(w, "%v)", optionsBag)
@ -338,6 +349,8 @@ func (g *generator) GenLiteralValueExpression(w io.Writer, expr *model.LiteralVa
} else {
g.Fgen(w, "False")
}
case model.NoneType:
g.Fgen(w, "None")
case model.NumberType:
bf := expr.Value.AsBigFloat()
if i, acc := bf.Int64(); acc == big.Exact {
@ -356,16 +369,40 @@ func (g *generator) GenLiteralValueExpression(w io.Writer, expr *model.LiteralVa
}
func (g *generator) GenObjectConsExpression(w io.Writer, expr *model.ObjectConsExpression) {
if len(expr.Items) == 0 {
g.Fgen(w, "{}")
g.genObjectConsExpression(w, expr, expr.Type())
}
func (g *generator) genObjectConsExpression(w io.Writer, expr *model.ObjectConsExpression, destType model.Type) {
typeName := g.argumentTypeName(expr, destType) // Example: aws.s3.BucketLoggingArgs
if typeName != "" {
// If a typeName exists, treat this as an Input Class e.g. aws.s3.BucketLoggingArgs(key="value", foo="bar", ...)
if len(expr.Items) == 0 {
g.Fgenf(w, "%s()", typeName)
} else {
g.Fgenf(w, "%s(\n", typeName)
g.Indented(func() {
for _, item := range expr.Items {
g.Fgenf(w, "%s", g.Indent)
lit := item.Key.(*model.LiteralValueExpression)
g.Fprint(w, PyName(lit.Value.AsString()))
g.Fgenf(w, "=%.v,\n", item.Value)
}
})
g.Fgenf(w, "%s)", g.Indent)
}
} else {
g.Fgen(w, "{")
g.Indented(func() {
for _, item := range expr.Items {
g.Fgenf(w, "\n%s%.v: %.v,", g.Indent, item.Key, item.Value)
}
})
g.Fgenf(w, "\n%s}", g.Indent)
// Otherwise treat this as an untyped dictionary e.g. {"key": "value", "foo": "bar", ...}
if len(expr.Items) == 0 {
g.Fgen(w, "{}")
} else {
g.Fgen(w, "{")
g.Indented(func() {
for _, item := range expr.Items {
g.Fgenf(w, "\n%s%.v: %.v,", g.Indent, item.Key, item.Value)
}
})
g.Fgenf(w, "\n%s}", g.Indent)
}
}
}

View file

@ -45,7 +45,7 @@ resource rta "aws:ec2:RouteTableAssociation" {
prop, ok := rta.Definition.Body.Attribute("subnetId")
assert.True(t, ok)
x, temps := g.lowerExpression(prop.Value)
x, temps := g.lowerExpression(prop.Value, prop.Type())
assert.Len(t, temps, 0)
x.SetLeadingTrivia(nil)

View file

@ -40,6 +40,8 @@ type PackageInfo struct {
ModuleNameOverrides map[string]string `json:"moduleNameOverrides,omitempty"`
// Toggle compatibility mode for a specified target.
Compatibility string `json:"compatibility,omitempty"`
// Indicates whether the package generates input/output classes.
UsesIOClasses bool `json:"usesIOClasses,omitempty"`
}
// Importer implements schema.Language for Python.

View file

@ -15,6 +15,7 @@
package python
import (
"fmt"
"strings"
"unicode"
"unicode/utf8"
@ -22,8 +23,77 @@ import (
"github.com/pulumi/pulumi/pkg/v2/codegen"
)
// useLegacyName are names that should return the result of PyNameLegacy from PyName, for compatibility.
var useLegacyName = codegen.StringSet{
// The following property name of a nested type is a case where the newer algorithm produces an incorrect name
// (`open_xjson_ser_de`). It should be the legacy name of `open_x_json_ser_de`.
// TODO[pulumi/pulumi#5199]: We should see if we can fix this in the algorithm of PyName so it doesn't need to
// be special-cased in this set.
"openXJsonSerDe": struct{}{}, // AWS
// The following function name has already shipped with the legacy name (`get_public_i_ps`).
// TODO[pulumi/pulumi#5200]: Consider emitting two functions: one with the correct name (`get_public_ips`)
// and another function with the legacy name (`get_public_i_ps`) marked as deprecated.
"GetPublicIPs": struct{}{}, // Azure
// The following function name has already shipped with the legacy name (`get_uptime_check_i_ps`).
// TODO[pulumi/pulumi#5200]: Consider emitting two functions: one with the correct name (`get_uptime_check_ips`)
// and another function with the legacy name (`get_uptime_check_i_ps`) marked as deprecated.
"GetUptimeCheckIPs": struct{}{}, // GCP
}
// excludeFromPanic are names that are ok to have different results from PyName and PyNameLegacy.
var excludeFromPanic = codegen.StringSet{
// The following all show up as properties of nested input/output classes only, so it's OK that the current
// and legacy names are different since we haven't previously generated any input/output classes (hence no
// breaking change).
"nonResourceURLs": struct{}{}, // K8s
"targetWWNs": struct{}{}, // K8s
"podCIDRs": struct{}{}, // K8s
"podIPs": struct{}{}, // K8s
"externalIPs": struct{}{}, // K8s
"publicIPs": struct{}{}, // Azure
"effectiveOutboundIPs": struct{}{}, // Azure
"doNotRunExtensionsOnOverprovisionedVMs": struct{}{}, // Azure
"vCPUs": struct{}{}, // Azure
"networkACLs": struct{}{}, // Azure
"allocatableVMs": struct{}{}, // Azure
"publicIPsToAllow": struct{}{}, // Azure
"managedOutboundIPs": struct{}{}, // Azure
"outboundIPs": struct{}{}, // Azure
"staticIPs": struct{}{}, // Azure
"sendMDNAsynchronously": struct{}{}, // Azure
"adminGroupObjectIDs": struct{}{}, // Azure
"GuestConfigurationHCRPAssignment": struct{}{}, // Azure
"GetGuestConfigurationHCRPAssignment": struct{}{}, // Azure
"clusterUsersGroupDNs": struct{}{}, // Azure
}
// PyName turns a variable or function name, normally using camelCase, to an underscore_case name.
// It panics if the result is different from PyNameLegacy, unless name is in excludeFromPanic, to help catch
// unintended breaking changes.
// TODO[pulumi/pulumi#5201]: Once all providers have been updated to use this version of the codegen (or later),
// we can go back and remove the panic.
func PyName(name string) string {
current := pyName(name, useLegacyName.Has(name))
if excludeFromPanic.Has(name) {
return current
}
legacy := PyNameLegacy(name)
if current != legacy {
panic(fmt.Sprintf("PyName(%[1]q) != PyNameLegacy(%[1]q) (%q != %q)", name, current, legacy))
}
return current
}
// Deprecated: Use PyName instead.
// PyNameLegacy is an uncorrected and deprecated version of the PyName algorithm to maintain compatibility and avoid
// a breaking change. See the linked issue for more context: https://github.com/pulumi/pulumi-kubernetes/issues/1179
func PyNameLegacy(name string) string {
return pyName(name, true /*legacy*/)
}
func pyName(name string, legacy bool) string {
// This method is a state machine with four states:
// stateFirst - the initial state.
// stateUpper - The last character we saw was an uppercase letter and the character before it
@ -119,9 +189,9 @@ func PyName(name string) string {
continue
}
// We want to fold digits immediately following an acronym into the same
// component as the acronym.
if unicode.IsDigit(char) {
// We want to fold digits (or the lowercase letter 's' if not the legacy algo) immediately following
// an acronym into the same component as the acronym.
if unicode.IsDigit(char) || (char == 's' && !legacy) {
// stateAcronym -> stateLowerOrNumber
state = stateLowerOrNumber
currentComponent.WriteRune(char)

View file

@ -0,0 +1,55 @@
package python
import (
"testing"
"github.com/stretchr/testify/assert"
)
var pyNameTests = []struct {
input string
expected string
legacy string
}{
{"kubeletConfigKey", "kubelet_config_key", "kubelet_config_key"},
{"podCIDR", "pod_cidr", "pod_cidr"},
{"podCidr", "pod_cidr", "pod_cidr"},
{"podCIDRs", "pod_cidrs", "pod_cid_rs"},
{"podIPs", "pod_ips", "pod_i_ps"},
{"nonResourceURLs", "non_resource_urls", "non_resource_ur_ls"},
{"someTHINGsAREWeird", "some_things_are_weird", "some_thin_gs_are_weird"},
{"podCIDRSet", "pod_cidr_set", "pod_cidr_set"},
{"Sha256Hash", "sha256_hash", "sha256_hash"},
{"SHA256Hash", "sha256_hash", "sha256_hash"},
// PyName should return the legacy name for these:
{"openXJsonSerDe", "open_x_json_ser_de", "open_x_json_ser_de"},
{"GetPublicIPs", "get_public_i_ps", "get_public_i_ps"},
{"GetUptimeCheckIPs", "get_uptime_check_i_ps", "get_uptime_check_i_ps"},
}
func TestPyName(t *testing.T) {
for _, tt := range pyNameTests {
t.Run(tt.input, func(t *testing.T) {
// TODO[pulumi/pulumi#5201]: Once the assertion has been removed, we can remove this `if` block.
// Prevent this input from panic'ing.
if tt.input == "someTHINGsAREWeird" {
result := pyName(tt.input, false /*legacy*/)
assert.Equal(t, tt.expected, result)
return
}
result := PyName(tt.input)
assert.Equal(t, tt.expected, result)
})
}
}
func TestPyNameLegacy(t *testing.T) {
for _, tt := range pyNameTests {
t.Run(tt.input, func(t *testing.T) {
result := PyNameLegacy(tt.input)
assert.Equal(t, tt.legacy, result)
})
}
}

View file

@ -156,6 +156,8 @@ func (*UnionType) isType() {}
// ObjectType represents schematized maps from strings to particular types.
type ObjectType struct {
// Package is the package that defines the resource.
Package *Package
// Token is the type's Pulumi type token.
Token string
// Comment is the description of the type, if any.
@ -245,6 +247,8 @@ type Alias struct {
// Resource describes a Pulumi resource.
type Resource struct {
// Package is the package that defines the resource.
Package *Package
// Token is the resource's Pulumi type token.
Token string
// Comment is the description of the resource, if any.
@ -267,6 +271,8 @@ type Resource struct {
// Function describes a Pulumi function.
type Function struct {
// Package is the package that defines the function.
Package *Package
// Token is the function's Pulumi type token.
Token string
// Comment is the description of the function, if any.
@ -738,7 +744,9 @@ func ImportSpec(spec PackageSpec, languages map[string]Language) (*Package, erro
return nil, errors.Wrap(err, "compiling module format regexp")
}
types, err := bindTypes(spec.Types)
pkg := &Package{}
types, err := bindTypes(pkg, spec.Types)
if err != nil {
return nil, errors.Wrap(err, "binding types")
}
@ -790,7 +798,7 @@ func ImportSpec(spec PackageSpec, languages map[string]Language) (*Package, erro
language[name] = raw
}
pkg := &Package{
*pkg = Package{
moduleFormat: moduleFormatRegexp,
Name: spec.Name,
Version: version,
@ -817,6 +825,8 @@ func ImportSpec(spec PackageSpec, languages map[string]Language) (*Package, erro
}
type types struct {
pkg *Package
objects map[string]*ObjectType
arrays map[Type]*ArrayType
maps map[Type]*MapType
@ -1102,6 +1112,7 @@ func (t *types) bindObjectTypeDetails(obj *ObjectType, token string, spec Object
language[name] = raw
}
obj.Package = t.pkg
obj.Token = token
obj.Comment = spec.Description
obj.Language = language
@ -1118,8 +1129,9 @@ func (t *types) bindObjectType(token string, spec ObjectTypeSpec) (*ObjectType,
return obj, nil
}
func bindTypes(objects map[string]ObjectTypeSpec) (*types, error) {
func bindTypes(pkg *Package, objects map[string]ObjectTypeSpec) (*types, error) {
typs := &types{
pkg: pkg,
objects: map[string]*ObjectType{},
arrays: map[Type]*ArrayType{},
maps: map[Type]*MapType{},
@ -1186,6 +1198,7 @@ func bindResource(token string, spec ResourceSpec, types *types) (*Resource, err
}
return &Resource{
Package: types.pkg,
Token: token,
Comment: spec.Description,
InputProperties: inputProperties,
@ -1250,6 +1263,7 @@ func bindFunction(token string, spec FunctionSpec, types *types) (*Function, err
}
return &Function{
Package: types.pkg,
Token: token,
Comment: spec.Description,
Inputs: inputs,

View file

@ -0,0 +1,46 @@
// 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 schema
import (
"encoding/json"
"io/ioutil"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
)
func TestImportSpec(t *testing.T) {
// Read in, decode, and import the schema.
schemaBytes, err := ioutil.ReadFile(filepath.Join("..", "internal", "test", "testdata", "kubernetes.json"))
if err != nil {
panic(err)
}
var pkgSpec PackageSpec
if err = json.Unmarshal(schemaBytes, &pkgSpec); err != nil {
panic(err)
}
pkg, err := ImportSpec(pkgSpec, nil)
if err != nil {
t.Errorf("ImportSpec() error = %v", err)
}
for _, r := range pkg.Resources {
assert.NotNil(t, r.Package, "expected resource %s to have an associated Package", r.Token)
}
}

View file

@ -10,21 +10,18 @@ replace (
require (
cloud.google.com/go/logging v1.0.0
cloud.google.com/go/storage v1.6.0
cloud.google.com/go/storage v1.9.0
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
github.com/Azure/go-autorest/autorest v0.10.0 // indirect
github.com/Azure/go-autorest/autorest/azure/auth v0.4.2 // indirect
github.com/Azure/go-autorest/autorest/to v0.3.0 // indirect
github.com/Azure/go-autorest/autorest/validation v0.2.0 // indirect
github.com/Sirupsen/logrus v1.0.5 // indirect
github.com/aws/aws-sdk-go v1.30.7
github.com/aws/aws-sdk-go v1.31.13
github.com/blang/semver v3.5.1+incompatible
github.com/djherbis/times v1.2.0
github.com/docker/docker v0.0.0-20170504205632-89658bed64c2
github.com/dustin/go-humanize v1.0.0
github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/golang/protobuf v1.3.5
github.com/golang/protobuf v1.4.2
github.com/google/go-querystring v1.0.0
github.com/gorilla/mux v1.7.4
github.com/hashicorp/go-multierror v1.0.0
@ -46,17 +43,18 @@ require (
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
github.com/spf13/cobra v1.0.0
github.com/stretchr/testify v1.6.1
github.com/tweekmonster/luser v0.0.0-20161003172636-3fa38070dbd7
github.com/xeipuuv/gojsonschema v1.2.0
github.com/zclconf/go-cty v1.3.1
gocloud.dev v0.19.1-0.20200517170643-46480dc2c3dd
gocloud.dev/secrets/hashivault v0.19.1-0.20200517170643-46480dc2c3dd
gocloud.dev v0.20.0
gocloud.dev/secrets/hashivault v0.20.0
golang.org/x/crypto v0.0.0-20200317142112-1b76d66859c6
golang.org/x/net v0.0.0-20200301022130-244492dfa37a
golang.org/x/net v0.0.0-20200602114024-627f9648deb9
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
google.golang.org/api v0.20.0
google.golang.org/genproto v0.0.0-20200318110522-7735f76e9fa5
google.golang.org/grpc v1.28.0
google.golang.org/api v0.26.0
google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482
google.golang.org/grpc v1.29.1
gopkg.in/AlecAivazis/survey.v1 v1.8.9-0.20200217094205-6773bdf39b7f
gopkg.in/src-d/go-git.v4 v4.13.1
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0

View file

@ -13,43 +13,59 @@ cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6T
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0 h1:MZQCQQaRwOrAcuKjiHWHrgKykt4fZyuwF2dtiG3fGW8=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.55.0/go.mod h1:ZHmoY+/lIMNkN2+fBmuTiqZ4inFhvQad8ft7MT8IV5Y=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.58.0 h1:vtAfVc723K3xKq1BQydk/FyCldnaNFhGhpJxaJzgRMQ=
cloud.google.com/go v0.58.0/go.mod h1:W+9FnSUw6nhVwXlFcp1eL+krq5+HQUJeUogSeJZZiWg=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0 h1:xE3CPsOgttP4ACBePh79zTKALtXwn/Edhcr16R5hMWU=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0 h1:PQcPefKFdaIzjQFbiyOgAqyx8q5djaE7x9Sqe712DPA=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.2.0/go.mod h1:iISCjWnTpnoJT1R287xRdjvQHJrxQOpeah4phb5D3h0=
cloud.google.com/go/logging v1.0.0 h1:kaunpnoEh9L4hu6JUsBa8Y20LBfKnCuDhKUgdZp7oK8=
cloud.google.com/go/logging v1.0.0/go.mod h1:V1cc3ogwobYzQq5f2R7DS/GvRIrI4FKj01Gs5glwAls=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0 h1:Lpy6hKgdcl7a3WGSfJIFmxmcdjSpP6OmBEfcOv1Y680=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1 h1:ukjixP1wl0LpnZ6LWtZJ0mX5tBmjp1f8Sqer8Z2OMUU=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0 h1:UDpwYIwla4jHGzZJaEJYx1tOejbgSoNqsAfHAUYe2r8=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.9.0 h1:oXnZyBjHB6hC8TnSle0AWW6pGJ29EuSo5ww+SFmdNBg=
cloud.google.com/go/storage v1.9.0/go.mod h1:m+/etGaqZbylxaNT876QGXqEHp4PR2Rq5GMqICWb9bU=
contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA=
contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0=
contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw=
contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE=
contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/AlecAivazis/survey/v2 v2.0.5/go.mod h1:WYBhg6f0y/fNYUuesWQc0PKbJcEliGcYHB9sNT3Bg74=
github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU=
github.com/Azure/azure-amqp-common-go/v3 v3.0.0/go.mod h1:SY08giD/XbhTz07tJdpw1SoxQXHPN30+DI3Z04SYqyg=
github.com/Azure/azure-pipeline-go v0.2.1 h1:OLBdZJ3yvOn2MezlWvbrBMTEUQC72zAftRZOMdj5HYo=
github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4=
github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v30.1.0+incompatible h1:HyYPft8wXpxMd0kfLtXo6etWcO+XuPbLkcgx9g2cqxU=
github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-service-bus-go v0.9.1/go.mod h1:yzBx6/BUGfjfeqbRZny9AQIbIe3AcV9WZbAdpkoXOa0=
github.com/Azure/azure-storage-blob-go v0.8.0 h1:53qhf0Oxa0nOjgbDeeYPUeyiNmafAFEY95rZLK0Tj6o=
github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0=
github.com/Azure/azure-pipeline-go v0.2.2 h1:6oiIS9yaG6XCCzhgAgKFfIWyo4LLCiDhZot6ltoThhY=
github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc=
github.com/Azure/azure-sdk-for-go v37.1.0+incompatible h1:aFlw3lP7ZHQi4m1kWCpcwYtczhDkGhDoRaMTaxcOf68=
github.com/Azure/azure-sdk-for-go v37.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-service-bus-go v0.10.1/go.mod h1:E/FOceuKAFUfpbIJDKWz/May6guE+eGibfGT6q+n1to=
github.com/Azure/azure-storage-blob-go v0.9.0 h1:kORqvzXP8ORhKbW13FflGUaSE5CMyDWun9UwMxY8gPs=
github.com/Azure/azure-storage-blob-go v0.9.0/go.mod h1:8UBPbiOhrMQ4pLPi3gA1tXnpjrS76UYE/fo5A40vf4g=
github.com/Azure/go-amqp v0.12.6/go.mod h1:qApuH6OFTSKZFmCOxccvAv5rLizBQf4v8pRmG138DPo=
github.com/Azure/go-amqp v0.12.7/go.mod h1:qApuH6OFTSKZFmCOxccvAv5rLizBQf4v8pRmG138DPo=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-autorest v12.4.3+incompatible h1:tCkdkgLZqAk+43nZu3wda9n413Q2g+z7xp1wmjiJTPY=
github.com/Azure/go-autorest v12.4.3+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0=
github.com/Azure/go-autorest/autorest v0.10.0 h1:mvdtztBqcL8se7MdrUweNieTNi4kfNG6GOJuurQJpuY=
@ -59,6 +75,8 @@ github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S
github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
github.com/Azure/go-autorest/autorest/adal v0.8.2 h1:O1X4oexUxnZCaEUGsvMnr8ZGj8HI37tNezwY4npRqA0=
github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
github.com/Azure/go-autorest/autorest/adal v0.8.3 h1:O1AGG9Xig71FxdX9HO5pGNyZ7TbSyHaVg+5eJO/jSGw=
github.com/Azure/go-autorest/autorest/adal v0.8.3/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
github.com/Azure/go-autorest/autorest/azure/auth v0.4.2 h1:iM6UAvjR97ZIeR93qTcwpKNMpV+/FTWjwEbuPD495Tk=
github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM=
github.com/Azure/go-autorest/autorest/azure/cli v0.3.1 h1:LXl088ZQlP0SBppGFsRZonW6hSvwgL5gRByMbvUbx8U=
@ -104,12 +122,10 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.19.45/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.30.7 h1:IaXfqtioP6p9SFAnNfsqdNczbR5UNbYqvcZUSsCAdTY=
github.com/aws/aws-sdk-go v1.30.7/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.31.13 h1:UeWMTRTL0XAKLR7vxDL4/u7KOtz/LtfJr+lXtxN4YEQ=
github.com/aws/aws-sdk-go v1.31.13/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
@ -132,7 +148,6 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7 h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@ -157,16 +172,13 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 h1:Uc+IZ7gYqAf/rSGFplbWBSHaGolEQlNLgMgSE3ccnIQ=
github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813/go.mod h1:P+oSoE9yhSRvsmYyZsshflcR6ePWYLql6UU1amW13IM=
@ -181,7 +193,6 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
@ -190,7 +201,6 @@ github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3a
github.com/gofrs/flock v0.7.1 h1:DP+LD/t0njgoPBvT5MJLeliUIVQR03hiKR6vezdwHlc=
github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
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.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
@ -204,15 +214,25 @@ github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4er
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0 h1:Rd1kQnQu0Hq3qvJppYSG0HtP+f5LPPUiDswTLiEegLg=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@ -222,6 +242,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/go-replayers/grpcreplay v0.1.0 h1:eNb1y9rZFmY4ax45uEEECSa8fsxGRU+8Bil52ASAwic=
@ -236,12 +258,15 @@ github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OI
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/wire v0.3.0 h1:imGQZGEVEHpje5056+K+cgdO72p0LQv2xIIFXNGUf60=
github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s=
github.com/google/wire v0.4.0 h1:kXcsA/rIGzJImVqPdhfnr6q0xsS9gU0515q1EPpJ9fE=
github.com/google/wire v0.4.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
github.com/googleapis/gax-go v2.0.2+incompatible h1:silFMLAnr330+NRuag/VjIGF7TLp/LBrV2CJKFLWEww=
github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
@ -252,9 +277,7 @@ github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU=
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
@ -275,7 +298,6 @@ github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@ -301,7 +323,6 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
@ -323,7 +344,6 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@ -331,7 +351,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
@ -340,15 +359,16 @@ github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LE
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149 h1:HfxbT6/JcvIljmERptWhwa8XzP7H3T+Z2N26gTsaDaA=
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
github.com/mattn/go-ieproxy v0.0.1 h1:qiyop7gCflfhwCzGyeT0gro3sF9AIg9HU98JORTkqfI=
github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
@ -358,7 +378,6 @@ github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mitchellh/cli v1.0.0 h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
@ -368,7 +387,6 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
@ -447,7 +465,6 @@ github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EE
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
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/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
@ -462,19 +479,19 @@ github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/texttheater/golang-levenshtein v0.0.0-20191208221605-eb6844b05fc6 h1:9VTskZOIRf2vKF3UL8TuWElry5pgUpV1tFSe/e/0m/E=
github.com/texttheater/golang-levenshtein v0.0.0-20191208221605-eb6844b05fc6/go.mod h1:XDKHRm5ThF8YJjx001LtgelzsoaEcvnA7lVWz9EeX3g=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tweekmonster/luser v0.0.0-20161003172636-3fa38070dbd7 h1:X9dsIWPuuEJlPX//UmRKophhOKCGXc46RVIGuttks68=
github.com/tweekmonster/luser v0.0.0-20161003172636-3fa38070dbd7/go.mod h1:UxoP3EypF8JfGEjAII8jx1q8rQyDnX8qdTCs/UQBVIE=
github.com/uber/jaeger-client-go v2.22.1+incompatible h1:NHcubEkVbahf9t3p75TOCR83gdUHXjRJvjoBh1yACsM=
github.com/uber/jaeger-client-go v2.22.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw=
@ -491,7 +508,8 @@ github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/zclconf/go-cty v1.2.0 h1:sPHsy7ADcIZQP3vILvTjrh74ZA175TFP5vqiNK1UmlI=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
github.com/zclconf/go-cty v1.3.1 h1:QIOZl+CKKdkv4l2w3lG23nNzXgLoxsWLSEdg1MlX4p0=
github.com/zclconf/go-cty v1.3.1/go.mod h1:YO23e2L18AG+ZYQfSobnY4G65nvwvprPCxBHkufUH1k=
@ -502,17 +520,15 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
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/go.mod h1:SmKwiR8YwIMMJvQBKLsC3fHNyMwXLw3PMDO+VVteJMI=
gocloud.dev v0.19.1-0.20200517170643-46480dc2c3dd h1:XmzP/xO8nwHwO1BK2q+M2iDLYT+br/6oezs/h6ybfTg=
gocloud.dev v0.19.1-0.20200517170643-46480dc2c3dd/go.mod h1:fvG7ZAkwaV3B1N49m64LkHoO/1bhgGBYyuK1egT06I4=
gocloud.dev/secrets/hashivault v0.19.1-0.20200517170643-46480dc2c3dd h1:+WEbmDu8oZdj3+cZfxLn/fisLxBLPYX0R2Ju8xLXmXw=
gocloud.dev/secrets/hashivault v0.19.1-0.20200517170643-46480dc2c3dd/go.mod h1:Us/bsVAl9RPzZR+OXgyY2LyIfyugQoNKJm+7VRZfOi0=
gocloud.dev v0.20.0 h1:mbEKMfnyPV7W1Rj35R1xXfjszs9dXkwSOq2KoFr25g8=
gocloud.dev v0.20.0/go.mod h1:+Y/RpSXrJthIOM8uFNzWp6MRu9pFPNFEEZrQMxpkfIc=
gocloud.dev/secrets/hashivault v0.20.0 h1:919urzRWksXrZNNqqlHvek9IE6lWvYM4m8dvFqXq4HU=
gocloud.dev/secrets/hashivault v0.20.0/go.mod h1:2nNlZ76i4JlT9qrPVKbINB01L8BGgv4wmq2Cqyz22dA=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@ -548,6 +564,8 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl
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/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/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=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
@ -556,6 +574,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
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/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.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-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -573,12 +593,21 @@ golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -613,11 +642,11 @@ golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -626,8 +655,17 @@ golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d h1:62ap6LNOjDU6uGmKXHJbSfciMoV+FeI1sRXx/pLDL44=
golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -673,13 +711,25 @@ golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapK
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/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200317043434-63da46f3035e/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200606014950-c42cb6316fb6/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200608174601-1b747fd94509 h1:MI14dOfl3OG6Zd32w3ugsrvcUO810fDZdWakTq39dH4=
golang.org/x/tools v0.0.0-20200608174601-1b747fd94509/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
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=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@ -688,14 +738,21 @@ google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsb
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0 h1:jz2KixHX7EcCPiQrySzPdnYT7DbINAypCqKZ1Z7GM40=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.26.0 h1:VJZ8h6E8ip82FRpQl848c5vAadxlTXrUh8RzQzSRm08=
google.golang.org/api v0.26.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@ -704,7 +761,6 @@ google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRn
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
@ -719,8 +775,19 @@ google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvx
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200318110522-7735f76e9fa5 h1:Bs8aCQBqwnuSvG/tB3ip/W8JLeuQt1+1ppSHYi4n9RM=
google.golang.org/genproto v0.0.0-20200318110522-7735f76e9fa5/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200317114155-1f3552e48f24/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200325114520-5b2d0af7952b/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200603110839-e855014d5736/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482 h1:i+Aiej6cta/Frzp13/swvwz5O00kYcSe0A/C5Wd7zX8=
google.golang.org/genproto v0.0.0-20200608115520-7c474a2e3482/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@ -734,6 +801,18 @@ google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
gopkg.in/AlecAivazis/survey.v1 v1.8.9-0.20200217094205-6773bdf39b7f h1:AQkMzsSzHWrgZWqGRpuRaRPDmyNibcXlpGcnQJ7HxZw=
gopkg.in/AlecAivazis/survey.v1 v1.8.9-0.20200217094205-6773bdf39b7f/go.mod h1:CaHjv79TCgAvXMSFJSVgonHXYWxnhzI3eoHtnX5UgUo=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
@ -771,7 +850,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
pack.ag/amqp v0.11.2/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4=
honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

BIN
pkg/resource/testdata/test_dir.jar vendored Normal file

Binary file not shown.

View file

@ -21,11 +21,11 @@ import (
"encoding/json"
"flag"
"fmt"
user "github.com/tweekmonster/luser"
"io"
"io/ioutil"
"os"
"os/exec"
"os/user"
"path/filepath"
"regexp"
"runtime"

View file

@ -88,6 +88,7 @@ publish_containers() {
# This publishes the SDK specific containers and uses a dispatch event to trigger a GitHub Action
pulumictl create containers "${CLI_VERSION//v}"
pulumictl create choco-deploy "${CLI_VERSION//v}"
}
echo_header "Building Pulumi containers (${CLI_VERSION})"

View file

@ -148,6 +148,7 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/texttheater/golang-levenshtein v0.0.0-20191208221605-eb6844b05fc6/go.mod h1:XDKHRm5ThF8YJjx001LtgelzsoaEcvnA7lVWz9EeX3g=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tweekmonster/luser v0.0.0-20161003172636-3fa38070dbd7/go.mod h1:UxoP3EypF8JfGEjAII8jx1q8rQyDnX8qdTCs/UQBVIE=
github.com/uber/jaeger-client-go v2.22.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=

View file

@ -28,6 +28,7 @@ require (
github.com/spf13/cobra v1.0.0
github.com/stretchr/testify v1.5.1
github.com/texttheater/golang-levenshtein v0.0.0-20191208221605-eb6844b05fc6
github.com/tweekmonster/luser v0.0.0-20161003172636-3fa38070dbd7
github.com/uber/jaeger-client-go v2.22.1+incompatible
github.com/uber/jaeger-lib v2.2.0+incompatible // indirect
go.uber.org/atomic v1.6.0 // indirect

View file

@ -25,7 +25,6 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
@ -60,7 +59,6 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
github.com/gofrs/flock v0.7.1 h1:DP+LD/t0njgoPBvT5MJLeliUIVQR03hiKR6vezdwHlc=
github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
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.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
@ -103,13 +101,11 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
@ -178,7 +174,6 @@ github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
@ -187,6 +182,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/texttheater/golang-levenshtein v0.0.0-20191208221605-eb6844b05fc6 h1:9VTskZOIRf2vKF3UL8TuWElry5pgUpV1tFSe/e/0m/E=
github.com/texttheater/golang-levenshtein v0.0.0-20191208221605-eb6844b05fc6/go.mod h1:XDKHRm5ThF8YJjx001LtgelzsoaEcvnA7lVWz9EeX3g=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tweekmonster/luser v0.0.0-20161003172636-3fa38070dbd7 h1:X9dsIWPuuEJlPX//UmRKophhOKCGXc46RVIGuttks68=
github.com/tweekmonster/luser v0.0.0-20161003172636-3fa38070dbd7/go.mod h1:UxoP3EypF8JfGEjAII8jx1q8rQyDnX8qdTCs/UQBVIE=
github.com/uber/jaeger-client-go v2.22.1+incompatible h1:NHcubEkVbahf9t3p75TOCR83gdUHXjRJvjoBh1yACsM=
github.com/uber/jaeger-client-go v2.22.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw=
@ -197,7 +194,6 @@ github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0B
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
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=

View file

@ -1130,6 +1130,7 @@ const (
TarArchive // a POSIX tar archive.
TarGZIPArchive // a POSIX tar archive that has been subsequently compressed using GZip.
ZIPArchive // a multi-file ZIP archive.
JARArchive // a Java JAR file
)
// ArchiveExts maps from a file extension and its associated archive and/or compression format.
@ -1138,6 +1139,7 @@ var ArchiveExts = map[string]ArchiveFormat{
".tgz": TarGZIPArchive,
".tar.gz": TarGZIPArchive,
".zip": ZIPArchive,
".jar": JARArchive,
}
// detectArchiveFormat takes a path and infers its archive format based on the file extension.
@ -1159,7 +1161,7 @@ func readArchive(ar io.ReadCloser, format ArchiveFormat) (ArchiveReader, error)
return readTarArchive(ar)
case TarGZIPArchive:
return readTarGZIPArchive(ar)
case ZIPArchive:
case ZIPArchive, JARArchive:
// Unfortunately, the ZIP archive reader requires ReaderAt functionality. If it's a file, we can recover this
// with a simple stat. Otherwise, we will need to go ahead and make a copy in memory.
var ra io.ReaderAt

View file

@ -312,7 +312,7 @@ func TestArchiveDir(t *testing.T) {
// Go 1.10 introduced breaking changes to archive/zip and archive/tar headers
assert.Equal(t, "489e9a9dad271922ecfbda590efc40e48788286a06bd406a357ab8d13f0b6abf", arch.Hash)
}
validateTestDirArchive(t, arch)
validateTestDirArchive(t, arch, 3)
}
func TestArchiveTar(t *testing.T) {
@ -320,7 +320,7 @@ func TestArchiveTar(t *testing.T) {
arch, err := NewPathArchive("../../../../pkg/resource/testdata/test_dir.tar")
assert.Nil(t, err)
assert.Equal(t, "c618d74a40f87de3092ca6a6c4cca834aa5c6a3956c6ceb2054b40d04bb4cd76", arch.Hash)
validateTestDirArchive(t, arch)
validateTestDirArchive(t, arch, 3)
}
func TestArchiveTgz(t *testing.T) {
@ -328,7 +328,7 @@ func TestArchiveTgz(t *testing.T) {
arch, err := NewPathArchive("../../../../pkg/resource/testdata/test_dir.tgz")
assert.Nil(t, err)
assert.Equal(t, "f9b33523b6a3538138aff0769ff9e7d522038e33c5cfe28b258332b3f15790c8", arch.Hash)
validateTestDirArchive(t, arch)
validateTestDirArchive(t, arch, 3)
}
func TestArchiveZip(t *testing.T) {
@ -336,7 +336,14 @@ func TestArchiveZip(t *testing.T) {
arch, err := NewPathArchive("../../../../pkg/resource/testdata/test_dir.zip")
assert.Nil(t, err)
assert.Equal(t, "343da72cec1302441efd4a490d66f861d393fb270afb3ced27f92a0d96abc068", arch.Hash)
validateTestDirArchive(t, arch)
validateTestDirArchive(t, arch, 3)
}
func TestArchiveJar(t *testing.T) {
arch, err := NewPathArchive("../../../../pkg/resource/testdata/test_dir.jar")
assert.Nil(t, err)
assert.Equal(t, "dfb9eb69f433564b07df524068621c5ac65c08868e6094b8fa4ee388a5ee66e7", arch.Hash)
validateTestDirArchive(t, arch, 4)
}
func findRepositoryRoot() (string, error) {
@ -463,6 +470,7 @@ func TestFileExtentionSniffing(t *testing.T) {
assert.Equal(t, ArchiveFormat(TarArchive), detectArchiveFormat("./some/path/my.tar"))
assert.Equal(t, ArchiveFormat(TarGZIPArchive), detectArchiveFormat("./some/path/my.tar.gz"))
assert.Equal(t, ArchiveFormat(TarGZIPArchive), detectArchiveFormat("./some/path/my.tgz"))
assert.Equal(t, ArchiveFormat(JARArchive), detectArchiveFormat("./some/path/my.jar"))
assert.Equal(t, ArchiveFormat(NotArchive), detectArchiveFormat("./some/path/who.knows"))
// In #2589 we had cases where a file would look like it had an longer extension, because the suffix would include
@ -471,6 +479,7 @@ func TestFileExtentionSniffing(t *testing.T) {
assert.Equal(t, ArchiveFormat(TarArchive), detectArchiveFormat("./some/path/my.file.tar"))
assert.Equal(t, ArchiveFormat(TarGZIPArchive), detectArchiveFormat("./some/path/my.file.tar.gz"))
assert.Equal(t, ArchiveFormat(TarGZIPArchive), detectArchiveFormat("./some/path/my.file.tgz"))
assert.Equal(t, ArchiveFormat(JARArchive), detectArchiveFormat("./some/path/my.file.jar"))
assert.Equal(t, ArchiveFormat(NotArchive), detectArchiveFormat("./some/path/who.even.knows"))
}
@ -487,7 +496,7 @@ func TestInvalidPathArchive(t *testing.T) {
assert.Error(t, err)
}
func validateTestDirArchive(t *testing.T, arch *Archive) {
func validateTestDirArchive(t *testing.T, arch *Archive, expected int) {
r, err := arch.Open()
assert.Nil(t, err)
defer func() {
@ -518,7 +527,7 @@ func validateTestDirArchive(t *testing.T, arch *Archive) {
subs[name] = text.String()
}
assert.Equal(t, 3, len(subs))
assert.Equal(t, expected, len(subs))
lorem := subs["Lorem_ipsum.txt"]
assert.Equal(t, lorem,

View file

@ -16,8 +16,8 @@ package tools
import (
"fmt"
user "github.com/tweekmonster/luser"
"os"
"os/user"
"path/filepath"
"time"
)

View file

@ -16,8 +16,8 @@ package workspace
import (
"fmt"
user "github.com/tweekmonster/luser"
"os"
"os/user"
"path/filepath"
"strings"

View file

@ -203,6 +203,18 @@ func makeBuiltins(primitives []*builtin) []*builtin {
elementType: "[]map[string]" + p.Type,
Example: fmt.Sprintf("%sMapArray{%sMap{\"baz\": %s}}", name, name, p.Example),
})
builtins = append(builtins, &builtin{
Name: name + "MapMap",
Type: "map[string]" + name + "MapInput",
elementType: "map[string]map[string]" + p.Type,
Example: fmt.Sprintf("%sMapMap{\"baz\": %sMap{\"baz\": %s}}", name, name, p.Example),
})
builtins = append(builtins, &builtin{
Name: name + "ArrayArray",
Type: "[]" + name + "ArrayInput",
elementType: "[][]" + p.Type,
Example: fmt.Sprintf("%sArrayArray{%sArray{%s}}", name, name, p.Example),
})
}
nameToBuiltin := map[string]*builtin{}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -521,7 +521,7 @@ export function output<T>(val: Input<T | undefined>): Output<Unwrap<T | undefine
}
/**
* [secret] behaves the same as [output] except the resturned output is marked as contating sensitive data.
* [secret] behaves the same as [output] except the returned output is marked as contating sensitive data.
*/
export function secret<T>(val: Input<T>): Output<Unwrap<T>>;
export function secret<T>(val: Input<T> | undefined): Output<Unwrap<T | undefined>>;

View file

@ -15,7 +15,7 @@
// tslint:disable
import * as assert from "assert";
import { all, output, Output, unknown } from "../index";
import { all, output, Output, Resource, unknown } from "../index";
import { asyncTest } from "./util";
function test(val: any, expected: any) {
@ -51,7 +51,7 @@ function testResources(val: any, expected: any, resources: TestResource[], allRe
assert.deepStrictEqual(asyncResources, new Set(allResources));
for (const res of syncResources) {
if (!asyncResources.has(<TestResource>res)) {
if (!asyncResources.has(<Resource><any>res)) {
assert.fail(`async resources did not contain: ${(<TestResource><any>res).name}`)
}
}

View file

@ -178,7 +178,7 @@ func (host *pythonLanguageHost) Run(ctx context.Context, req *pulumirpc.RunReque
virtualenv = filepath.Join(cwd, virtualenv)
}
if !python.IsVirtualEnv(virtualenv) {
return nil, errors.Errorf("%q doesn't appear to be a virtual environment", virtualenv)
return nil, python.NewVirtualEnvError(host.virtualenv, virtualenv)
}
cmd = python.VirtualEnvCommand(virtualenv, "python", args...)
} else {

View file

@ -34,7 +34,16 @@ if [ -n "${virtualenv:-}" ] ; then
# Run python from the virtual environment.
"$virtualenv/bin/python" -u -m pulumi.policy "$1" "$2"
else
echo "\"$virtualenv\" doesn't appear to be a virtual environment"
if [ -d "$virtualenv" ]; then
1>&2 echo "The 'virtualenv' option in PulumiPolicy.yaml is set to \"$virtualenv\", but \"$virtualenv\" doesn't appear to be a virtual environment."
else
1>&2 echo "The 'virtualenv' option in PulumiPolicy.yaml is set to \"$virtualenv\", but \"$virtualenv\" doesn't exist."
fi
1>&2 echo "Run the following commands to create the virtual environment and install dependencies into it:"
1>&2 echo " 1. python3 -m venv $virtualenv"
1>&2 echo " 2. $virtualenv/bin/python -m pip install --upgrade pip setuptools wheel"
1>&2 echo " 3. $virtualenv/bin/python -m pip install -r $PWD/requirements.txt"
1>&2 echo "For more information see: https://www.pulumi.com/docs/intro/languages/python/#virtual-environments"
exit 1
fi
else

View file

@ -28,7 +28,12 @@ if defined pulumi_runtime_python_virtualenv (
"%pulumi_runtime_python_virtualenv%\Scripts\python.exe" -u -m pulumi.policy %pulumi_policy_python_engine_address% %pulumi_policy_python_program%
exit /B
) else (
echo "%pulumi_runtime_python_virtualenv%" doesn't appear to be a virtual environment
echo The 'virtualenv' option in PulumiPolicy.yaml is set to %pulumi_runtime_python_virtualenv%, but %pulumi_runtime_python_virtualenv% doesn't appear to be a virtual environment. 1>&2
echo Run the following commands to create the virtual environment and install dependencies into it: 1>&2
echo 1. python -m venv %pulumi_runtime_python_virtualenv% 1>&2
echo 2. %pulumi_runtime_python_virtualenv%\Scripts\python.exe -m pip install --upgrade pip setuptools wheel 1>&2
echo 3. %pulumi_runtime_python_virtualenv%\Scripts\python.exe -m pip install -r %cd%\requirements.txt 1>&2
echo For more information see: https://www.pulumi.com/docs/intro/languages/python/#virtual-environments 1>&2
exit 1
)
) else (

View file

@ -22,7 +22,16 @@ if [ -n "${PULUMI_RUNTIME_VIRTUALENV:-}" ] ; then
# Run python from the virtual environment.
"$PULUMI_RUNTIME_VIRTUALENV/bin/python" -u -m pulumi.dynamic $@
else
echo "\"$PULUMI_RUNTIME_VIRTUALENV\" doesn't appear to be a virtual environment"
if [ -d "$PULUMI_RUNTIME_VIRTUALENV" ]; then
1>&2 echo "The 'virtualenv' option in Pulumi.yaml is set to \"$PULUMI_RUNTIME_VIRTUALENV\", but \"$PULUMI_RUNTIME_VIRTUALENV\" doesn't appear to be a virtual environment."
else
1>&2 echo "The 'virtualenv' option in Pulumi.yaml is set to \"$PULUMI_RUNTIME_VIRTUALENV\", but \"$PULUMI_RUNTIME_VIRTUALENV\" doesn't exist."
fi
1>&2 echo "Run the following commands to create the virtual environment and install dependencies into it:"
1>&2 echo " 1. python3 -m venv $PULUMI_RUNTIME_VIRTUALENV"
1>&2 echo " 2. $PULUMI_RUNTIME_VIRTUALENV/bin/python -m pip install --upgrade pip setuptools wheel"
1>&2 echo " 3. $PULUMI_RUNTIME_VIRTUALENV/bin/python -m pip install -r $PWD/requirements.txt"
1>&2 echo "For more information see: https://www.pulumi.com/docs/intro/languages/python/#virtual-environments"
exit 1
fi
else

View file

@ -11,7 +11,12 @@ if defined PULUMI_RUNTIME_VIRTUALENV (
"%PULUMI_RUNTIME_VIRTUALENV%\Scripts\python.exe" -u -m pulumi.dynamic %*
exit /B
) else (
echo "%PULUMI_RUNTIME_VIRTUALENV%" doesn't appear to be a virtual environment
echo The 'virtualenv' option in Pulumi.yaml is set to %PULUMI_RUNTIME_VIRTUALENV%, but %PULUMI_RUNTIME_VIRTUALENV% doesn't appear to be a virtual environment. 1>&2
echo Run the following commands to create the virtual environment and install dependencies into it: 1>&2
echo 1. python -m venv %PULUMI_RUNTIME_VIRTUALENV% 1>&2
echo 2. %PULUMI_RUNTIME_VIRTUALENV%\Scripts\python.exe -m pip install --upgrade pip setuptools wheel 1>&2
echo 3. %PULUMI_RUNTIME_VIRTUALENV%\Scripts\python.exe -m pip install -r %cd%\requirements.txt 1>&2
echo For more information see: https://www.pulumi.com/docs/intro/languages/python/#virtual-environments 1>&2
exit 1
)
) else (

Some files were not shown because too many files have changed in this diff Show more