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