github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/cmd/juju/commands/bootstrap_interactive.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 "bufio" 8 "fmt" 9 "io" 10 "sort" 11 "strings" 12 13 "github.com/juju/errors" 14 jujucloud "github.com/juju/juju/cloud" 15 "github.com/juju/juju/cmd/juju/common" 16 "github.com/juju/juju/cmd/juju/interact" 17 ) 18 19 // assembleClouds 20 func assembleClouds() ([]string, error) { 21 public, _, err := jujucloud.PublicCloudMetadata(jujucloud.JujuPublicCloudsPath()) 22 if err != nil { 23 return nil, errors.Trace(err) 24 } 25 26 personal, err := jujucloud.PersonalCloudMetadata() 27 if err != nil { 28 return nil, errors.Trace(err) 29 } 30 31 return sortClouds(public, common.BuiltInClouds(), personal), nil 32 } 33 34 // queryCloud asks the user to choose a cloud. 35 func queryCloud(clouds []string, defCloud string, scanner *bufio.Scanner, w io.Writer) (string, error) { 36 list := strings.Join(clouds, "\n") 37 if _, err := fmt.Fprint(w, "Clouds\n", list, "\n\n"); err != nil { 38 return "", errors.Trace(err) 39 } 40 41 // add support for a default (empty) selection. 42 clouds = append(clouds, "") 43 44 verify := interact.MatchOptions(clouds, errors.Errorf("Invalid cloud.")) 45 46 query := fmt.Sprintf("Select a cloud [%s]: ", defCloud) 47 cloud, err := interact.QueryVerify([]byte(query), scanner, w, verify) 48 if err != nil { 49 return "", errors.Trace(err) 50 } 51 if cloud == "" { 52 return defCloud, nil 53 } 54 55 cloudName, ok := interact.FindMatch(cloud, clouds) 56 if !ok { 57 // should be impossible 58 return "", errors.Errorf("invalid cloud name chosen: %s", cloud) 59 } 60 61 return cloudName, nil 62 } 63 64 // queryRegion asks the user to pick a region of the ones passed in. The first 65 // region in the list will be the default. 66 func queryRegion(cloud string, regions []jujucloud.Region, scanner *bufio.Scanner, w io.Writer) (string, error) { 67 fmt.Fprintf(w, "Regions in %s:\n", cloud) 68 names := jujucloud.RegionNames(regions) 69 // add an empty string to allow for a default value. Also gives us an extra 70 // line return after the list of names. 71 names = append(names, "") 72 if _, err := fmt.Fprintln(w, strings.Join(names, "\n")); err != nil { 73 return "", errors.Trace(err) 74 } 75 verify := interact.MatchOptions(names, errors.Errorf("Invalid region.")) 76 defaultRegion := regions[0].Name 77 query := fmt.Sprintf("Select a region in %s [%s]: ", cloud, defaultRegion) 78 region, err := interact.QueryVerify([]byte(query), scanner, w, verify) 79 if err != nil { 80 return "", errors.Trace(err) 81 } 82 if region == "" { 83 return defaultRegion, nil 84 } 85 regionName, ok := interact.FindMatch(region, names) 86 if !ok { 87 // should be impossible 88 return "", errors.Errorf("invalid region name chosen: %s", region) 89 } 90 91 return regionName, nil 92 } 93 94 func defaultControllerName(cloudname, region string) string { 95 if region == "" { 96 return cloudname 97 } 98 return cloudname + "-" + region 99 } 100 101 func queryName(defName string, scanner *bufio.Scanner, w io.Writer) (string, error) { 102 query := fmt.Sprintf("Enter a name for the Controller [%s]: ", defName) 103 name, err := interact.QueryVerify([]byte(query), scanner, w, nil) 104 if err != nil { 105 return "", errors.Trace(err) 106 } 107 if name == "" { 108 return defName, nil 109 } 110 return name, nil 111 } 112 113 func sortClouds(maps ...map[string]jujucloud.Cloud) []string { 114 var clouds []string 115 for _, m := range maps { 116 for name := range m { 117 clouds = append(clouds, name) 118 } 119 } 120 sort.Strings(clouds) 121 return clouds 122 }