github.com/openshift/installer@v1.4.17/pkg/asset/installconfig/gcp/gcp.go (about) 1 package gcp 2 3 import ( 4 "context" 5 "fmt" 6 "sort" 7 "strings" 8 "time" 9 10 "github.com/AlecAivazis/survey/v2" 11 "github.com/AlecAivazis/survey/v2/core" 12 "github.com/pkg/errors" 13 14 "github.com/openshift/installer/pkg/types/gcp" 15 gcpValidation "github.com/openshift/installer/pkg/types/gcp/validation" 16 ) 17 18 // Platform collects GCP-specific configuration. 19 func Platform() (*gcp.Platform, error) { 20 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute) 21 defer cancel() 22 project, err := selectProject(ctx) 23 if err != nil { 24 return nil, err 25 } 26 27 region, err := selectRegion(ctx, project) 28 if err != nil { 29 return nil, err 30 } 31 32 return &gcp.Platform{ 33 ProjectID: project, 34 Region: region, 35 }, nil 36 } 37 38 func selectProject(ctx context.Context) (string, error) { 39 ssn, err := GetSession(ctx) 40 if err != nil { 41 return "", errors.Wrap(err, "failed to get session") 42 } 43 defaultProject := ssn.Credentials.ProjectID 44 45 client := &Client{ 46 ssn: ssn, 47 } 48 49 projects, err := client.GetProjects(ctx) 50 if err != nil { 51 return "", errors.Wrap(err, "failed to get projects") 52 } else if len(projects) == 0 { 53 return "", fmt.Errorf("failed to get projects for the given service principal, please check your permissions") 54 } 55 56 var options []string 57 ids := make(map[string]string) 58 59 var defaultValue string 60 for id, name := range projects { 61 option := fmt.Sprintf("%s (%s)", name, id) 62 ids[option] = id 63 if id == defaultProject { 64 defaultValue = option 65 } 66 options = append(options, option) 67 } 68 sort.Strings(options) 69 70 var selectedProject string 71 err = survey.Ask([]*survey.Question{ 72 { 73 Prompt: &survey.Select{ 74 Message: "Project ID", 75 Help: "The project id where the cluster will be provisioned. The default is taken from the provided service account.", 76 Default: defaultValue, 77 Options: options, 78 }, 79 }, 80 }, &selectedProject) 81 82 selectedProject = ids[selectedProject] 83 return selectedProject, err 84 } 85 86 func getValidatedRegions(computeRegions []string) map[string]string { 87 validatedRegions := make(map[string]string) 88 for _, region := range computeRegions { 89 // Only add validated regions 90 if value, ok := gcpValidation.Regions[region]; ok { 91 validatedRegions[region] = value 92 } 93 } 94 95 return validatedRegions 96 } 97 98 func selectRegion(ctx context.Context, project string) (string, error) { 99 ssn, err := GetSession(ctx) 100 if err != nil { 101 return "", errors.Wrap(err, "failed to get session") 102 } 103 104 client := &Client{ 105 ssn: ssn, 106 } 107 108 ctx, cancel := context.WithTimeout(ctx, 30*time.Second) 109 defer cancel() 110 computeRegions, err := client.GetRegions(ctx, project) 111 if err != nil || len(computeRegions) == 0 { 112 return "", errors.Wrap(err, "failed to get regions") 113 } 114 115 validRegions := getValidatedRegions(computeRegions) 116 117 defaultRegion := "us-central1" 118 defaultRegionName := "" 119 longRegions := make([]string, 0, len(validRegions)) 120 shortRegions := make([]string, 0, len(validRegions)) 121 for key, value := range validRegions { 122 shortRegions = append(shortRegions, key) 123 regionDesc := fmt.Sprintf("%s (%s)", key, value) 124 longRegions = append(longRegions, regionDesc) 125 126 if defaultRegionName == "" && key == defaultRegion { 127 defaultRegionName = regionDesc 128 } 129 } 130 131 var regionTransform survey.Transformer = func(ans interface{}) interface{} { 132 switch v := ans.(type) { 133 case core.OptionAnswer: 134 return core.OptionAnswer{Value: strings.SplitN(v.Value, " ", 2)[0], Index: v.Index} 135 case string: 136 return strings.SplitN(v, " ", 2)[0] 137 } 138 return "" 139 } 140 141 sort.Strings(longRegions) 142 sort.Strings(shortRegions) 143 144 if defaultRegionName == "" && len(longRegions) > 0 { 145 defaultRegionName = longRegions[0] 146 } 147 148 var selectedRegion string 149 err = survey.Ask([]*survey.Question{ 150 { 151 Prompt: &survey.Select{ 152 Message: "Region", 153 Help: "The GCP region to be used for installation.", 154 Default: defaultRegionName, 155 Options: longRegions, 156 }, 157 Validate: survey.ComposeValidators(survey.Required, func(ans interface{}) error { 158 choice := regionTransform(ans).(core.OptionAnswer).Value 159 i := sort.SearchStrings(shortRegions, choice) 160 if i == len(shortRegions) || shortRegions[i] != choice { 161 return errors.Errorf("invalid region %q", choice) 162 } 163 return nil 164 }), 165 Transform: regionTransform, 166 }, 167 }, &selectedRegion) 168 if err != nil { 169 return "", err 170 } 171 172 return selectedRegion, nil 173 }