github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/cloud/show.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package cloud 5 6 import ( 7 "fmt" 8 9 "github.com/juju/cmd" 10 "github.com/juju/errors" 11 "github.com/juju/gnuflag" 12 "gopkg.in/yaml.v2" 13 14 jujucloud "github.com/juju/juju/cloud" 15 jujucmd "github.com/juju/juju/cmd" 16 "github.com/juju/juju/cmd/juju/common" 17 ) 18 19 type showCloudCommand struct { 20 cmd.CommandBase 21 out cmd.Output 22 23 CloudName string 24 25 includeConfig bool 26 } 27 28 var showCloudDoc = ` 29 Provided information includes 'defined' (public, built-in), 'type', 30 'auth-type', 'regions', 'endpoints', and cloud specific configuration 31 options. 32 33 If ‘--include-config’ is used, additional configuration (key, type, and 34 description) specific to the cloud are displayed if available. 35 36 Examples: 37 38 juju show-cloud google 39 juju show-cloud azure-china --output ~/azure_cloud_details.txt 40 41 See also: 42 clouds 43 update-clouds 44 ` 45 46 // NewShowCloudCommand returns a command to list cloud information. 47 func NewShowCloudCommand() cmd.Command { 48 return &showCloudCommand{} 49 } 50 51 func (c *showCloudCommand) SetFlags(f *gnuflag.FlagSet) { 52 c.CommandBase.SetFlags(f) 53 // We only support yaml for display purposes. 54 c.out.AddFlags(f, "yaml", map[string]cmd.Formatter{ 55 "yaml": cmd.FormatYaml, 56 }) 57 f.BoolVar(&c.includeConfig, "include-config", false, "Print available config option details specific to the specified cloud") 58 } 59 60 func (c *showCloudCommand) Init(args []string) error { 61 switch len(args) { 62 case 1: 63 c.CloudName = args[0] 64 default: 65 return errors.New("no cloud specified") 66 } 67 return cmd.CheckEmpty(args[1:]) 68 } 69 70 func (c *showCloudCommand) Info() *cmd.Info { 71 return jujucmd.Info(&cmd.Info{ 72 Name: "show-cloud", 73 Args: "<cloud name>", 74 Purpose: "Shows detailed information on a cloud.", 75 Doc: showCloudDoc, 76 }) 77 } 78 79 func (c *showCloudCommand) Run(ctxt *cmd.Context) error { 80 details, err := GetAllCloudDetails() 81 if err != nil { 82 return err 83 } 84 cloud, ok := details[c.CloudName] 85 if !ok { 86 return errors.NotFoundf("cloud %q", c.CloudName) 87 } 88 if err = c.out.Write(ctxt, cloud); err != nil { 89 return err 90 } 91 if c.includeConfig { 92 config := getCloudConfigDetails(cloud.CloudType) 93 if len(config) > 0 { 94 fmt.Fprintln(ctxt.Stdout, fmt.Sprintf("\nThe available config options specific to %s clouds are:", cloud.CloudType)) 95 return c.out.Write(ctxt, config) 96 } 97 } 98 return nil 99 } 100 101 // RegionDetails holds region details. 102 type RegionDetails struct { 103 Name string `yaml:"-" json:"-"` 104 Endpoint string `yaml:"endpoint,omitempty" json:"endpoint,omitempty"` 105 IdentityEndpoint string `yaml:"identity-endpoint,omitempty" json:"identity-endpoint,omitempty"` 106 StorageEndpoint string `yaml:"storage-endpoint,omitempty" json:"storage-endpoint,omitempty"` 107 } 108 109 // CloudDetails holds cloud details. 110 type CloudDetails struct { 111 Source string `yaml:"defined,omitempty" json:"defined,omitempty"` 112 CloudType string `yaml:"type" json:"type"` 113 CloudDescription string `yaml:"description" json:"description"` 114 AuthTypes []string `yaml:"auth-types,omitempty,flow" json:"auth-types,omitempty"` 115 Endpoint string `yaml:"endpoint,omitempty" json:"endpoint,omitempty"` 116 IdentityEndpoint string `yaml:"identity-endpoint,omitempty" json:"identity-endpoint,omitempty"` 117 StorageEndpoint string `yaml:"storage-endpoint,omitempty" json:"storage-endpoint,omitempty"` 118 // Regions is for when we want to print regions in order for yaml output. 119 Regions yaml.MapSlice `yaml:"regions,omitempty" json:"-"` 120 // Regions map is for json marshalling where format is important but not order. 121 RegionsMap map[string]RegionDetails `yaml:"-" json:"regions,omitempty"` 122 Config map[string]interface{} `yaml:"config,omitempty" json:"config,omitempty"` 123 RegionConfig jujucloud.RegionConfig `yaml:"region-config,omitempty" json:"region-config,omitempty"` 124 CACredentials []string `yaml:"ca-credentials,omitempty" json:"ca-credentials,omitempty"` 125 } 126 127 func makeCloudDetails(cloud jujucloud.Cloud) *CloudDetails { 128 result := &CloudDetails{ 129 Source: "public", 130 CloudType: cloud.Type, 131 Endpoint: cloud.Endpoint, 132 IdentityEndpoint: cloud.IdentityEndpoint, 133 StorageEndpoint: cloud.StorageEndpoint, 134 Config: cloud.Config, 135 RegionConfig: cloud.RegionConfig, 136 CloudDescription: cloud.Description, 137 CACredentials: cloud.CACertificates, 138 } 139 result.AuthTypes = make([]string, len(cloud.AuthTypes)) 140 for i, at := range cloud.AuthTypes { 141 result.AuthTypes[i] = string(at) 142 } 143 result.RegionsMap = make(map[string]RegionDetails) 144 for _, region := range cloud.Regions { 145 r := RegionDetails{Name: region.Name} 146 if region.Endpoint != result.Endpoint { 147 r.Endpoint = region.Endpoint 148 } 149 if region.IdentityEndpoint != result.IdentityEndpoint { 150 r.IdentityEndpoint = region.IdentityEndpoint 151 } 152 if region.StorageEndpoint != result.StorageEndpoint { 153 r.StorageEndpoint = region.StorageEndpoint 154 } 155 result.Regions = append(result.Regions, yaml.MapItem{r.Name, r}) 156 result.RegionsMap[region.Name] = r 157 } 158 return result 159 } 160 161 func getCloudConfigDetails(cloudType string) map[string]interface{} { 162 // providerSchema has all config options, including their descriptions 163 // and types. 164 providerSchema, err := common.CloudSchemaByType(cloudType) 165 if err != nil { 166 // Some providers do not implement the ProviderSchema interface. 167 return nil 168 } 169 specifics := make(map[string]interface{}) 170 ps, err := common.ProviderConfigSchemaSourceByType(cloudType) 171 if err != nil { 172 // Some providers do not implement the ConfigSchema interface. 173 return nil 174 } 175 // ps.ConfigSchema() returns the provider specific config option names, but no 176 // description etc. 177 for attr := range ps.ConfigSchema() { 178 if providerSchema[attr].Secret { 179 continue 180 } 181 specifics[attr] = common.PrintConfigSchema{ 182 Description: providerSchema[attr].Description, 183 Type: fmt.Sprintf("%s", providerSchema[attr].Type), 184 } 185 } 186 return specifics 187 } 188 189 // GetAllCloudDetails returns a list of all cloud details. 190 func GetAllCloudDetails() (map[string]*CloudDetails, error) { 191 result, err := listCloudDetails() 192 if err != nil { 193 return nil, errors.Trace(err) 194 } 195 return result.all(), nil 196 }