[CLI] Adding the ability to create a default org for backends that support orgs (#8352)
This commit is contained in:
parent
0a38bc295c
commit
74ba28ad55
|
@ -1,5 +1,9 @@
|
||||||
### Improvements
|
### Improvements
|
||||||
|
|
||||||
|
- [CLI] Adding the ability to use `pulumi org set [name]` to set a default org
|
||||||
|
to use when creating a stacks in the Pulumi Service backend or Self -hosted Service
|
||||||
|
[#8352](https://github.com/pulumi/pulumi/pull/8352)
|
||||||
|
|
||||||
- [schema] Add IsOverlay option to disable codegen for particular types
|
- [schema] Add IsOverlay option to disable codegen for particular types
|
||||||
[#8338](https://github.com/pulumi/pulumi/pull/8338)
|
[#8338](https://github.com/pulumi/pulumi/pull/8338)
|
||||||
|
|
||||||
|
|
|
@ -229,6 +229,10 @@ func loginWithBrowser(ctx context.Context, d diag.Sink, cloudURL string, opts di
|
||||||
return New(d, cloudURL)
|
return New(d, cloudURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetDefaultOrg(url string, orgName string) error {
|
||||||
|
return workspace.SetBackendConfigDefaultOrg(url, orgName)
|
||||||
|
}
|
||||||
|
|
||||||
// Login logs into the target cloud URL and returns the cloud backend for it.
|
// Login logs into the target cloud URL and returns the cloud backend for it.
|
||||||
func Login(ctx context.Context, d diag.Sink, cloudURL string, opts display.Options) (Backend, error) {
|
func Login(ctx context.Context, d diag.Sink, cloudURL string, opts display.Options) (Backend, error) {
|
||||||
cloudURL = ValueOrDefaultURL(cloudURL)
|
cloudURL = ValueOrDefaultURL(cloudURL)
|
||||||
|
|
|
@ -33,6 +33,7 @@ import (
|
||||||
|
|
||||||
func newLoginCmd() *cobra.Command {
|
func newLoginCmd() *cobra.Command {
|
||||||
var cloudURL string
|
var cloudURL string
|
||||||
|
var defaultOrg string
|
||||||
var localMode bool
|
var localMode bool
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
|
@ -55,6 +56,9 @@ func newLoginCmd() *cobra.Command {
|
||||||
"to log in to a self-hosted Pulumi service running at the api.pulumi.acmecorp.com domain.\n" +
|
"to log in to a self-hosted Pulumi service running at the api.pulumi.acmecorp.com domain.\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"For `https://` URLs, the CLI will speak REST to a service that manages state and concurrency control.\n" +
|
"For `https://` URLs, the CLI will speak REST to a service that manages state and concurrency control.\n" +
|
||||||
|
"You can specify a default org to use when logging into the Pulumi service backend or a " +
|
||||||
|
"self-hosted Pulumi service.\n" +
|
||||||
|
"\n" +
|
||||||
"[PREVIEW] If you prefer to operate Pulumi independently of a service, and entirely local to your computer,\n" +
|
"[PREVIEW] If you prefer to operate Pulumi independently of a service, and entirely local to your computer,\n" +
|
||||||
"pass `file://<path>`, where `<path>` will be where state checkpoints will be stored. For instance,\n" +
|
"pass `file://<path>`, where `<path>` will be where state checkpoints will be stored. For instance,\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
|
@ -127,8 +131,21 @@ func newLoginCmd() *cobra.Command {
|
||||||
var err error
|
var err error
|
||||||
if filestate.IsFileStateBackendURL(cloudURL) {
|
if filestate.IsFileStateBackendURL(cloudURL) {
|
||||||
be, err = filestate.Login(cmdutil.Diag(), cloudURL)
|
be, err = filestate.Login(cmdutil.Diag(), cloudURL)
|
||||||
|
if defaultOrg != "" {
|
||||||
|
return fmt.Errorf("unable to set default org for this type of backend")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
be, err = httpstate.Login(commandContext(), cmdutil.Diag(), cloudURL, displayOptions)
|
be, err = httpstate.Login(commandContext(), cmdutil.Diag(), cloudURL, displayOptions)
|
||||||
|
// if the user has specified a default org to associate with the backend
|
||||||
|
if defaultOrg != "" {
|
||||||
|
cloudURL, err := workspace.GetCurrentCloudURL()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := httpstate.SetDefaultOrg(cloudURL, defaultOrg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(err, "problem logging in")
|
return errors.Wrapf(err, "problem logging in")
|
||||||
|
@ -145,6 +162,8 @@ func newLoginCmd() *cobra.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.PersistentFlags().StringVarP(&cloudURL, "cloud-url", "c", "", "A cloud URL to log in to")
|
cmd.PersistentFlags().StringVarP(&cloudURL, "cloud-url", "c", "", "A cloud URL to log in to")
|
||||||
|
cmd.PersistentFlags().StringVar(&defaultOrg, "default-org", "", "A default org to associate with the login. "+
|
||||||
|
"Please note, currently, only the managed and self-hosted backends support organizations")
|
||||||
cmd.PersistentFlags().BoolVarP(&localMode, "local", "l", false, "Use Pulumi in local-only mode")
|
cmd.PersistentFlags().BoolVarP(&localMode, "local", "l", false, "Use Pulumi in local-only mode")
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
|
|
|
@ -172,7 +172,11 @@ func runNew(args newArgs) error {
|
||||||
// created via the web app.
|
// created via the web app.
|
||||||
var s backend.Stack
|
var s backend.Stack
|
||||||
if args.stack != "" && strings.Count(args.stack, "/") == 2 {
|
if args.stack != "" && strings.Count(args.stack, "/") == 2 {
|
||||||
existingStack, existingName, existingDesc, err := getStack(args.stack, opts)
|
stackName, err := buildStackName(args.stack)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
existingStack, existingName, existingDesc, err := getStack(stackName, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -518,7 +522,11 @@ func promptAndCreateStack(prompt promptForValueFunc,
|
||||||
}
|
}
|
||||||
|
|
||||||
if stack != "" {
|
if stack != "" {
|
||||||
s, err := stackInit(b, stack, setCurrent, secretsProvider)
|
stackName, err := buildStackName(stack)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s, err := stackInit(b, stackName, setCurrent, secretsProvider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -536,7 +544,14 @@ func promptAndCreateStack(prompt promptForValueFunc,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
s, err := stackInit(b, stackName, setCurrent, secretsProvider)
|
formattedStackName, err := buildStackName(stackName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s, err := stackInit(b, formattedStackName, setCurrent, secretsProvider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !yes {
|
if !yes {
|
||||||
// Let the user know about the error and loop around to try again.
|
// Let the user know about the error and loop around to try again.
|
||||||
|
|
153
pkg/cmd/pulumi/org.go
Normal file
153
pkg/cmd/pulumi/org.go
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
// Copyright 2016-2021, 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 (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/pulumi/pulumi/pkg/v3/backend/display"
|
||||||
|
"github.com/pulumi/pulumi/pkg/v3/backend/httpstate"
|
||||||
|
"github.com/pulumi/pulumi/sdk/v3/go/common/util/cmdutil"
|
||||||
|
"github.com/pulumi/pulumi/sdk/v3/go/common/workspace"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newOrgCmd() *cobra.Command {
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "org",
|
||||||
|
Short: "Manage Organization configuration",
|
||||||
|
Long: "Manage Organization configuration.\n" +
|
||||||
|
"\n" +
|
||||||
|
"Use this command to manage organization configuration, " +
|
||||||
|
"e.g. setting the default organization for a backend",
|
||||||
|
Args: cmdutil.NoArgs,
|
||||||
|
Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error {
|
||||||
|
cloudURL, err := workspace.GetCurrentCloudURL()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultOrg, err := workspace.GetBackendConfigDefaultOrg()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Current Backend: %s\n", cloudURL)
|
||||||
|
if defaultOrg != "" {
|
||||||
|
fmt.Printf("Default Org: %s", defaultOrg)
|
||||||
|
} else {
|
||||||
|
fmt.Println("No Default Org Specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.AddCommand(newOrgSetDefaultCmd())
|
||||||
|
cmd.AddCommand(newOrgGetDefaultCmd())
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOrgSetDefaultCmd() *cobra.Command {
|
||||||
|
var orgName string
|
||||||
|
|
||||||
|
var cmd = &cobra.Command{
|
||||||
|
Use: "set-default [NAME]",
|
||||||
|
Args: cmdutil.ExactArgs(1),
|
||||||
|
Short: "Set the default organization for the current backend",
|
||||||
|
Long: "Set the default organization for the current backend.\n" +
|
||||||
|
"\n" +
|
||||||
|
"This command is used to set the default organization in which to create \n" +
|
||||||
|
"projects and stacks for the current backend.\n" +
|
||||||
|
"\n" +
|
||||||
|
"Currently, only the managed and self-hosted backends support organizations. " +
|
||||||
|
"If you try and set a default organization for a backend that does not \n" +
|
||||||
|
"support create organizations, then an error will be returned by the CLI",
|
||||||
|
Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error {
|
||||||
|
displayOpts := display.Options{
|
||||||
|
Color: cmdutil.GetGlobalColorization(),
|
||||||
|
}
|
||||||
|
|
||||||
|
orgName = args[0]
|
||||||
|
|
||||||
|
currentBe, err := currentBackend(displayOpts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !currentBe.SupportsOrganizations() {
|
||||||
|
return fmt.Errorf("unable to set a default organization for backend type: %s",
|
||||||
|
currentBe.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := currentBe.(httpstate.Backend); ok {
|
||||||
|
cloudURL, err := workspace.GetCurrentCloudURL()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := httpstate.SetDefaultOrg(cloudURL, orgName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOrgGetDefaultCmd() *cobra.Command {
|
||||||
|
var cmd = &cobra.Command{
|
||||||
|
Use: "get-default",
|
||||||
|
Short: "Get the default org for the current backend",
|
||||||
|
Long: "Get the default org for the current backend.\n" +
|
||||||
|
"\n" +
|
||||||
|
"This command is used to get the default organization for which and stacks are created in " +
|
||||||
|
"the current backend.\n" +
|
||||||
|
"\n" +
|
||||||
|
"Currently, only the managed and self-hosted backends support organizations.",
|
||||||
|
Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error {
|
||||||
|
displayOpts := display.Options{
|
||||||
|
Color: cmdutil.GetGlobalColorization(),
|
||||||
|
}
|
||||||
|
|
||||||
|
currentBe, err := currentBackend(displayOpts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !currentBe.SupportsOrganizations() {
|
||||||
|
return fmt.Errorf("backends of this type %q do not support organizations",
|
||||||
|
currentBe.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultOrg, err := workspace.GetBackendConfigDefaultOrg()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if defaultOrg != "" {
|
||||||
|
fmt.Println(defaultOrg)
|
||||||
|
} else {
|
||||||
|
fmt.Println("No Default Org Specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
|
@ -210,6 +210,7 @@ func NewPulumiCmd() *cobra.Command {
|
||||||
cmd.AddCommand(newConsoleCmd())
|
cmd.AddCommand(newConsoleCmd())
|
||||||
cmd.AddCommand(newAboutCmd())
|
cmd.AddCommand(newAboutCmd())
|
||||||
cmd.AddCommand(newSchemaCmd())
|
cmd.AddCommand(newSchemaCmd())
|
||||||
|
cmd.AddCommand(newOrgCmd())
|
||||||
|
|
||||||
// Less common, and thus hidden, commands:
|
// Less common, and thus hidden, commands:
|
||||||
cmd.AddCommand(newGenCompletionCmd(cmd))
|
cmd.AddCommand(newGenCompletionCmd(cmd))
|
||||||
|
|
|
@ -107,11 +107,15 @@ func newStackInitCmd() *cobra.Command {
|
||||||
return errors.New("missing stack name")
|
return errors.New("missing stack name")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.ValidateStackName(stackName); err != nil {
|
formattedStackName, err := buildStackName(stackName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := b.ValidateStackName(formattedStackName); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
stackRef, err := b.ParseStackReference(stackName)
|
stackRef, err := b.ParseStackReference(formattedStackName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -862,3 +862,20 @@ func getRefreshOption(proj *workspace.Project, refresh string) (bool, error) {
|
||||||
// the default functionality right now is to always skip a refresh
|
// the default functionality right now is to always skip a refresh
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildStackName(stackName string) (string, error) {
|
||||||
|
if strings.Count(stackName, "/") == 2 {
|
||||||
|
return stackName, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultOrg, err := workspace.GetBackendConfigDefaultOrg()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if defaultOrg != "" {
|
||||||
|
return fmt.Sprintf("%s/%s", defaultOrg, stackName), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return stackName, nil
|
||||||
|
}
|
||||||
|
|
|
@ -114,6 +114,8 @@ require (
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect
|
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 // indirect
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1 // indirect
|
||||||
|
github.com/kr/pretty v0.3.0 // indirect
|
||||||
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.6 // indirect
|
github.com/mattn/go-colorable v0.1.6 // indirect
|
||||||
github.com/mattn/go-ieproxy v0.0.1 // indirect
|
github.com/mattn/go-ieproxy v0.0.1 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||||
|
@ -130,6 +132,7 @@ require (
|
||||||
github.com/pierrec/lz4 v2.6.0+incompatible // indirect
|
github.com/pierrec/lz4 v2.6.0+incompatible // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/rivo/uniseg v0.2.0 // indirect
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
|
github.com/rogpeppe/go-internal v1.6.1 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.0.1 // indirect
|
github.com/russross/blackfriday/v2 v2.0.1 // indirect
|
||||||
github.com/ryanuber/go-glob v1.0.0 // indirect
|
github.com/ryanuber/go-glob v1.0.0 // indirect
|
||||||
github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94 // indirect
|
github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94 // indirect
|
||||||
|
|
|
@ -455,6 +455,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
||||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||||
|
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||||
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
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.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI=
|
github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI=
|
||||||
|
@ -580,11 +582,15 @@ github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w
|
||||||
github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM=
|
github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM=
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
|
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
||||||
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
|
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
|
||||||
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
||||||
|
github.com/ryboe/q v1.0.15 h1:atR2S58tRbVv5+t+Kx5qf+VvT2rpXYQPGAn5QtyB5jc=
|
||||||
|
github.com/ryboe/q v1.0.15/go.mod h1:ecdh6eECsYWI/cWgtRaYjWb8fbz5YndR22B+xpAcHY8=
|
||||||
github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94 h1:G04eS0JkAIVZfaJLjla9dNxkJCPiKIGZlw9AfOhzOD0=
|
github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94 h1:G04eS0JkAIVZfaJLjla9dNxkJCPiKIGZlw9AfOhzOD0=
|
||||||
github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94/go.mod h1:b18R55ulyQ/h3RaWyloPyER7fWQVZvimKKhnI5OfrJQ=
|
github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94/go.mod h1:b18R55ulyQ/h3RaWyloPyER7fWQVZvimKKhnI5OfrJQ=
|
||||||
github.com/santhosh-tekuri/jsonschema/v5 v5.0.0 h1:TToq11gyfNlrMFZiYujSekIsPd9AmsA2Bj/iv+s4JHE=
|
github.com/santhosh-tekuri/jsonschema/v5 v5.0.0 h1:TToq11gyfNlrMFZiYujSekIsPd9AmsA2Bj/iv+s4JHE=
|
||||||
|
|
|
@ -251,3 +251,123 @@ func StoreCredentials(creds Credentials) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BackendConfig struct {
|
||||||
|
DefaultOrg string `json:"defaultOrg,omitempty"` // The default org for this backend config.
|
||||||
|
}
|
||||||
|
|
||||||
|
type PulumiConfig struct {
|
||||||
|
BackendConfig map[string]BackendConfig `json:"backends,omitempty"` // a map of arbitrary backends configs.
|
||||||
|
}
|
||||||
|
|
||||||
|
func getConfigFilePath() (string, error) {
|
||||||
|
// Allow the folder we use to store config in to be overridden by tests
|
||||||
|
pulumiFolder := os.Getenv(PulumiCredentialsPathEnvVar)
|
||||||
|
if pulumiFolder == "" {
|
||||||
|
folder, err := GetPulumiHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrapf(err, "failed to get the home path")
|
||||||
|
}
|
||||||
|
pulumiFolder = folder
|
||||||
|
}
|
||||||
|
|
||||||
|
err := os.MkdirAll(pulumiFolder, 0700)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrapf(err, "failed to create '%s'", pulumiFolder)
|
||||||
|
}
|
||||||
|
|
||||||
|
return filepath.Join(pulumiFolder, "config.json"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPulumiConfig() (PulumiConfig, error) {
|
||||||
|
configFile, err := getConfigFilePath()
|
||||||
|
if err != nil {
|
||||||
|
return PulumiConfig{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := ioutil.ReadFile(configFile)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return PulumiConfig{}, nil
|
||||||
|
}
|
||||||
|
return PulumiConfig{}, errors.Wrapf(err, "reading '%s'", configFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
var config PulumiConfig
|
||||||
|
if err = json.Unmarshal(c, &config); err != nil {
|
||||||
|
return PulumiConfig{}, errors.Wrapf(err, "failed to read Pulumi config file")
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func StorePulumiConfig(config PulumiConfig) error {
|
||||||
|
configFile, err := getConfigFilePath()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
raw, err := json.MarshalIndent(config, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "marshalling config object")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use a temporary file and atomic os.Rename to ensure the file contents are
|
||||||
|
// updated atomically to ensure concurrent `pulumi` CLI operations are safe.
|
||||||
|
tempConfigFile, err := ioutil.TempFile(filepath.Dir(configFile), "config-*.json")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = tempConfigFile.Write(raw)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = tempConfigFile.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = os.Rename(tempConfigFile.Name(), configFile)
|
||||||
|
if err != nil {
|
||||||
|
contract.IgnoreError(os.Remove(tempConfigFile.Name()))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetBackendConfigDefaultOrg(backendURL, defaultOrg string) error {
|
||||||
|
config, err := GetPulumiConfig()
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.BackendConfig == nil {
|
||||||
|
config.BackendConfig = make(map[string]BackendConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
config.BackendConfig[backendURL] = BackendConfig{
|
||||||
|
DefaultOrg: defaultOrg,
|
||||||
|
}
|
||||||
|
|
||||||
|
return StorePulumiConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetBackendConfigDefaultOrg() (string, error) {
|
||||||
|
config, err := GetPulumiConfig()
|
||||||
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
backendURL, err := GetCurrentCloudURL()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if beConfig, ok := config.BackendConfig[backendURL]; ok {
|
||||||
|
if beConfig.DefaultOrg != "" {
|
||||||
|
return beConfig.DefaultOrg, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue