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

     1  package aws
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net/http"
     7  	"sort"
     8  	"strings"
     9  
    10  	survey "github.com/AlecAivazis/survey/v2"
    11  	"github.com/AlecAivazis/survey/v2/core"
    12  	"github.com/aws/aws-sdk-go/aws"
    13  	"github.com/aws/aws-sdk-go/aws/awserr"
    14  	"github.com/aws/aws-sdk-go/aws/session"
    15  	"github.com/aws/aws-sdk-go/service/route53"
    16  	"github.com/sirupsen/logrus"
    17  )
    18  
    19  // IsForbidden returns true if and only if the input error is an HTTP
    20  // 403 error from the AWS API.
    21  func IsForbidden(err error) bool {
    22  	var requestError awserr.RequestFailure
    23  	return errors.As(err, &requestError) && requestError.StatusCode() == http.StatusForbidden
    24  }
    25  
    26  // GetBaseDomain returns a base domain chosen from among the account's
    27  // public routes.
    28  func GetBaseDomain() (string, error) {
    29  	session, err := GetSession()
    30  	if err != nil {
    31  		return "", err
    32  	}
    33  
    34  	logrus.Debugf("listing AWS hosted zones")
    35  	client := route53.New(session)
    36  	publicZoneMap := map[string]struct{}{}
    37  	exists := struct{}{}
    38  	if err := client.ListHostedZonesPages(
    39  		&route53.ListHostedZonesInput{},
    40  		func(resp *route53.ListHostedZonesOutput, lastPage bool) (shouldContinue bool) {
    41  			for _, zone := range resp.HostedZones {
    42  				if zone.Config != nil && !aws.BoolValue(zone.Config.PrivateZone) {
    43  					publicZoneMap[strings.TrimSuffix(*zone.Name, ".")] = exists
    44  				}
    45  			}
    46  			return !lastPage
    47  		},
    48  	); err != nil {
    49  		return "", fmt.Errorf("list hosted zones: %w", err)
    50  	}
    51  
    52  	publicZones := make([]string, 0, len(publicZoneMap))
    53  	for name := range publicZoneMap {
    54  		publicZones = append(publicZones, name)
    55  	}
    56  	sort.Strings(publicZones)
    57  	if len(publicZones) == 0 {
    58  		return "", errors.New("no public Route 53 hosted zones found")
    59  	}
    60  
    61  	var domain string
    62  	if err := survey.AskOne(
    63  		&survey.Select{
    64  			Message: "Base Domain",
    65  			Help:    "The base domain of the cluster. All DNS records will be sub-domains of this base and will also include the cluster name.\n\nIf you don't see you intended base-domain listed, create a new public Route53 hosted zone and rerun the installer.",
    66  			Options: publicZones,
    67  		},
    68  		&domain,
    69  		survey.WithValidator(func(ans interface{}) error {
    70  			choice := ans.(core.OptionAnswer).Value
    71  			i := sort.SearchStrings(publicZones, choice)
    72  			if i == len(publicZones) || publicZones[i] != choice {
    73  				return fmt.Errorf("invalid base domain %q", choice)
    74  			}
    75  			return nil
    76  		}),
    77  	); err != nil {
    78  		return "", fmt.Errorf("failed UserInput: %w", err)
    79  	}
    80  
    81  	return domain, nil
    82  }
    83  
    84  // GetPublicZone returns a public route53 zone that matches the name.
    85  func GetPublicZone(sess *session.Session, name string) (*route53.HostedZone, error) {
    86  	var res *route53.HostedZone
    87  	f := func(resp *route53.ListHostedZonesOutput, lastPage bool) (shouldContinue bool) {
    88  		for idx, zone := range resp.HostedZones {
    89  			if zone.Config != nil && !aws.BoolValue(zone.Config.PrivateZone) && strings.TrimSuffix(aws.StringValue(zone.Name), ".") == strings.TrimSuffix(name, ".") {
    90  				res = resp.HostedZones[idx]
    91  				return false
    92  			}
    93  		}
    94  		return !lastPage
    95  	}
    96  
    97  	client := route53.New(sess)
    98  	if err := client.ListHostedZonesPages(&route53.ListHostedZonesInput{}, f); err != nil {
    99  		return nil, fmt.Errorf("listing hosted zones: %w", err)
   100  	}
   101  	if res == nil {
   102  		return nil, fmt.Errorf("no public route53 zone found matching name %q", name)
   103  	}
   104  	return res, nil
   105  }