github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/cmd/juju/commands/bootstrap_clouds.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package commands 5 6 import ( 7 "bytes" 8 "fmt" 9 "sort" 10 "strings" 11 "text/tabwriter" 12 13 "github.com/juju/cmd" 14 "github.com/juju/errors" 15 16 jujucloud "github.com/juju/juju/cloud" 17 "github.com/juju/juju/cmd/juju/common" 18 "github.com/juju/juju/jujuclient" 19 ) 20 21 type cloudList struct { 22 public []string 23 builtin []string 24 personal []string 25 } 26 27 func formatCloudDetailsTabular(clouds cloudList, credStore jujuclient.CredentialStore) ([]byte, error) { 28 var out bytes.Buffer 29 const ( 30 // To format things into columns. 31 minwidth = 0 32 tabwidth = 1 33 padding = 2 34 padchar = ' ' 35 flags = 0 36 ) 37 tw := tabwriter.NewWriter(&out, minwidth, tabwidth, padding, padchar, flags) 38 p := func(values ...string) { 39 text := strings.Join(values, "\t") 40 fmt.Fprintln(tw, text) 41 } 42 p("Cloud\tCredentials\tDefault Region") 43 printClouds := func(cloudNames []string) error { 44 sort.Strings(cloudNames) 45 for _, name := range cloudNames { 46 cred, err := credStore.CredentialForCloud(name) 47 if err != nil && !errors.IsNotFound(err) { 48 return errors.Annotatef(err, "error loading credential for cloud %q", name) 49 } 50 if err != nil || len(cred.AuthCredentials) == 0 { 51 p(name, "", "") 52 continue 53 } 54 var sortedCredNames []string 55 for credName := range cred.AuthCredentials { 56 sortedCredNames = append(sortedCredNames, credName) 57 } 58 sort.Strings(sortedCredNames) 59 for i, credName := range sortedCredNames { 60 if i == 0 { 61 p(name, credName, cred.DefaultRegion) 62 } else { 63 p("", credName, "") 64 } 65 i++ 66 } 67 } 68 return nil 69 } 70 if err := printClouds(clouds.public); err != nil { 71 return nil, err 72 } 73 if err := printClouds(clouds.builtin); err != nil { 74 return nil, err 75 } 76 if err := printClouds(clouds.personal); err != nil { 77 return nil, err 78 } 79 80 tw.Flush() 81 return out.Bytes(), nil 82 } 83 84 func printClouds(ctx *cmd.Context, credStore jujuclient.CredentialStore) error { 85 publicClouds, _, err := jujucloud.PublicCloudMetadata(jujucloud.JujuPublicCloudsPath()) 86 if err != nil { 87 return err 88 } 89 90 personalClouds, err := jujucloud.PersonalCloudMetadata() 91 if err != nil { 92 return err 93 } 94 95 fmt.Fprintln(ctx.Stdout, "You can bootstrap on these clouds. See ‘--regions <cloud>’ for all regions.") 96 clouds := cloudList{} 97 for name := range publicClouds { 98 clouds.public = append(clouds.public, name) 99 } 100 // Add in built in clouds like localhost (lxd). 101 for name := range common.BuiltInClouds() { 102 clouds.builtin = append(clouds.builtin, name) 103 } 104 for name := range personalClouds { 105 clouds.personal = append(clouds.personal, name) 106 } 107 out, err := formatCloudDetailsTabular(clouds, credStore) 108 if err != nil { 109 return err 110 } 111 fmt.Fprintln(ctx.Stdout, string(out)) 112 credHelpText := ` 113 You will need to have a credential if you want to bootstrap on a cloud, see 114 ‘juju autoload-credentials’ and ‘juju add-credential’. The first credential 115 listed is the default. Add more clouds with ‘juju add-cloud’. 116 ` 117 fmt.Fprintf(ctx.Stdout, credHelpText[1:]) 118 return nil 119 } 120 121 func printCloudRegions(ctx *cmd.Context, cloudName string) error { 122 cloud, err := jujucloud.CloudByName(cloudName) 123 if err != nil { 124 return err 125 } 126 fmt.Fprintf(ctx.Stdout, "Showing regions for %s:\n", cloudName) 127 for _, region := range cloud.Regions { 128 fmt.Fprintln(ctx.Stdout, region.Name) 129 } 130 return nil 131 }