github.com/openshift/installer@v1.4.17/pkg/asset/installconfig/openstack/openstack.go (about)

     1  // Package openstack collects OpenStack-specific configuration.
     2  package openstack
     3  
     4  import (
     5  	"context"
     6  	"fmt"
     7  	"sort"
     8  	"strings"
     9  
    10  	survey "github.com/AlecAivazis/survey/v2"
    11  	"github.com/AlecAivazis/survey/v2/core"
    12  
    13  	"github.com/openshift/installer/pkg/types/openstack"
    14  )
    15  
    16  const (
    17  	noExtNet = "<none>"
    18  )
    19  
    20  // Platform collects OpenStack-specific configuration.
    21  func Platform(ctx context.Context) (*openstack.Platform, error) {
    22  	cloudNames, err := getCloudNames()
    23  	if err != nil {
    24  		return nil, err
    25  	}
    26  	// Sort cloudNames so we can use sort.SearchStrings
    27  	sort.Strings(cloudNames)
    28  	var cloud string
    29  	err = survey.Ask([]*survey.Question{
    30  		{
    31  			Prompt: &survey.Select{
    32  				Message: "Cloud",
    33  				Help:    "The OpenStack cloud name from clouds.yaml.",
    34  				Options: cloudNames,
    35  			},
    36  			Validate: survey.ComposeValidators(survey.Required, func(ans interface{}) error {
    37  				value := ans.(core.OptionAnswer).Value
    38  				i := sort.SearchStrings(cloudNames, value)
    39  				if i == len(cloudNames) || cloudNames[i] != value {
    40  					return fmt.Errorf("invalid cloud name %q, should be one of %s", value, strings.Join(cloudNames, ", "))
    41  				}
    42  				return nil
    43  			}),
    44  		},
    45  	}, &cloud)
    46  	if err != nil {
    47  		return nil, fmt.Errorf("failed UserInput: %w", err)
    48  	}
    49  
    50  	networkNames, err := getExternalNetworkNames(ctx, cloud)
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  	networkNames = append(networkNames, noExtNet)
    55  	sort.Strings(networkNames)
    56  	var extNet string
    57  	err = survey.Ask([]*survey.Question{
    58  		{
    59  			Prompt: &survey.Select{
    60  				Message: "ExternalNetwork",
    61  				Help:    "The OpenStack external network name to be used for installation.",
    62  				Options: networkNames,
    63  				Default: noExtNet,
    64  			},
    65  			Validate: survey.ComposeValidators(survey.Required, func(ans interface{}) error {
    66  				value := ans.(core.OptionAnswer).Value
    67  				i := sort.SearchStrings(networkNames, value)
    68  				if i == len(networkNames) || networkNames[i] != value {
    69  					return fmt.Errorf("invalid network name %q, should be one of %s", value, strings.Join(networkNames, ", "))
    70  				}
    71  				return nil
    72  			}),
    73  		},
    74  	}, &extNet)
    75  	if extNet == noExtNet {
    76  		extNet = ""
    77  	}
    78  	if err != nil {
    79  		return nil, fmt.Errorf("failed UserInput: %w", err)
    80  	}
    81  
    82  	var apiFloatingIP string
    83  	if extNet != "" {
    84  		floatingIPs, err := getFloatingIPs(ctx, cloud, extNet)
    85  		if err != nil {
    86  			return nil, err
    87  		}
    88  		sort.Sort(floatingIPs)
    89  		err = survey.Ask([]*survey.Question{
    90  			{
    91  				Prompt: &survey.Select{
    92  					Message:     "APIFloatingIPAddress",
    93  					Help:        "The Floating IP address used for external access to the OpenShift API.",
    94  					Options:     floatingIPs.Names(),
    95  					Description: func(_ string, index int) string { return floatingIPs.Description(index) },
    96  				},
    97  				Validate: survey.ComposeValidators(survey.Required, func(ans interface{}) error {
    98  					if value := ans.(core.OptionAnswer).Value; !floatingIPs.Contains(value) {
    99  						return fmt.Errorf("invalid floating IP %q, should be one of %s", value, strings.Join(floatingIPs.Names(), ", "))
   100  					}
   101  					return nil
   102  				}),
   103  			},
   104  		}, &apiFloatingIP)
   105  		if err != nil {
   106  			return nil, fmt.Errorf("failed UserInput: %w", err)
   107  		}
   108  	}
   109  
   110  	flavorNames, err := getFlavorNames(ctx, cloud)
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  	sort.Strings(flavorNames)
   115  	var flavor string
   116  	err = survey.Ask([]*survey.Question{
   117  		{
   118  			Prompt: &survey.Select{
   119  				Message: "FlavorName",
   120  				Help:    "The OpenStack flavor to use for control-plane and compute nodes. A flavor with at least 16 GB RAM is recommended.",
   121  				Options: flavorNames,
   122  			},
   123  			Validate: survey.ComposeValidators(survey.Required, func(ans interface{}) error {
   124  				value := ans.(core.OptionAnswer).Value
   125  				i := sort.SearchStrings(flavorNames, value)
   126  				if i == len(flavorNames) || flavorNames[i] != value {
   127  					return fmt.Errorf("invalid flavor name %q, should be one of %s", value, strings.Join(flavorNames, ", "))
   128  				}
   129  				return nil
   130  			}),
   131  		},
   132  	}, &flavor)
   133  	if err != nil {
   134  		return nil, fmt.Errorf("failed UserInput: %w", err)
   135  	}
   136  
   137  	return &openstack.Platform{
   138  		APIFloatingIP:   apiFloatingIP,
   139  		Cloud:           cloud,
   140  		ExternalNetwork: extNet,
   141  		DefaultMachinePlatform: &openstack.MachinePool{
   142  			FlavorName: flavor,
   143  		},
   144  	}, nil
   145  }