github.com/jenkins-x/jx/v2@v2.1.155/pkg/cmd/opts/domain.go (about) 1 package opts 2 3 import ( 4 "fmt" 5 "net" 6 "os" 7 "strings" 8 "time" 9 10 "github.com/jenkins-x/jx-logging/pkg/log" 11 "github.com/jenkins-x/jx/v2/pkg/cloud" 12 "github.com/jenkins-x/jx/v2/pkg/cloud/amazon" 13 "github.com/jenkins-x/jx/v2/pkg/cloud/iks" 14 "github.com/jenkins-x/jx/v2/pkg/surveyutils" 15 "github.com/jenkins-x/jx/v2/pkg/util" 16 "gopkg.in/AlecAivazis/survey.v1" 17 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 18 "k8s.io/client-go/kubernetes" 19 ) 20 21 // GetDomain returns the domain name, trying to infer it either from various Kubernetes resources or cloud provider. If no domain 22 // can be determined, it will prompt to the user for a value. 23 func (o *CommonOptions) GetDomain(client kubernetes.Interface, domain string, provider string, ingressNamespace string, ingressService string, externalIP string) (string, error) { 24 surveyOpts := survey.WithStdio(o.In, o.Out, o.Err) 25 address := externalIP 26 if address == "" { 27 info := util.ColorInfo 28 log.Logger().Infof("Waiting to find the external host name of the ingress controller Service in namespace %s with name %s", 29 info(ingressNamespace), info(ingressService)) 30 if provider == cloud.KUBERNETES { 31 log.Logger().Infof("If you are installing Jenkins X on premise you may want to use the '--on-premise' flag or specify the '--external-ip' flags. See: %s", 32 info("https://jenkins-x.io/getting-started/install-on-cluster/#installing-jenkins-x-on-premise")) 33 } 34 svc, err := client.CoreV1().Services(ingressNamespace).Get(ingressService, metav1.GetOptions{}) 35 if err != nil { 36 return "", err 37 } 38 if svc != nil { 39 for _, v := range svc.Status.LoadBalancer.Ingress { 40 if v.IP != "" { 41 address = v.IP 42 } else if v.Hostname != "" { 43 address = v.Hostname 44 } 45 } 46 } 47 } 48 defaultDomain := address 49 50 if provider == cloud.AWS || provider == cloud.EKS { 51 if domain != "" { 52 err := amazon.RegisterAwsCustomDomain(domain, address) 53 return domain, err 54 } 55 56 // if we are booting, we want to use nip.io directly if a domain is not provided 57 // if one is provided, we'll expose it through external-dns 58 // we also check that we are not in cluster to do this, as the domain gets wiped if we are using .nip/xip.io 59 // and we need to create a new one again 60 if !o.InCluster() && os.Getenv("JX_INTERPRET_PIPELINE") != "true" { 61 log.Logger().Infof("\nOn AWS we recommend using a custom DNS name to access services in your Kubernetes cluster to ensure you can use all of your Availability Zones") 62 log.Logger().Infof("If you do not have a custom DNS name you can use yet, then you can register a new one here: %s\n", 63 util.ColorInfo("https://console.aws.amazon.com/route53/home?#DomainRegistration:")) 64 65 if o.BatchMode { 66 return "", fmt.Errorf("Please specify a custom DNS name via --domain when installing on AWS in batch mode") 67 } 68 for { 69 if answer, err := util.Confirm("Would you like to register a wildcard DNS ALIAS to point at this ELB address? ", true, 70 "When using AWS we need to use a wildcard DNS alias to point at the ELB host name so you can access services inside Jenkins X and in your Environments.", o.GetIOFileHandles()); err != nil { 71 return "", err 72 } else if answer { 73 customDomain := "" 74 prompt := &survey.Input{ 75 Message: "Your custom DNS name: ", 76 Help: "Enter your custom domain that we can use to setup a Route 53 ALIAS record to point at the ELB host: " + address, 77 } 78 err = survey.AskOne(prompt, &customDomain, nil, surveyOpts) 79 if err != nil { 80 return "", err 81 } 82 if customDomain != "" { 83 err := amazon.RegisterAwsCustomDomain(customDomain, address) 84 return customDomain, err 85 } 86 } else { 87 break 88 } 89 } 90 } 91 } 92 93 if provider == cloud.IKS { 94 if domain != "" { 95 log.Logger().Infof("\nIBM Kubernetes Service will use provided domain. Ensure name is registered with DNS (ex. CIS) and pointing the cluster ingress IP: %s", 96 util.ColorInfo(address)) 97 return domain, nil 98 } 99 clusterName, err := iks.GetClusterName() 100 clusterRegion, err := iks.GetKubeClusterRegion(client) 101 if err == nil && clusterName != "" && clusterRegion != "" { 102 customDomain := clusterName + "." + clusterRegion + ".containers.appdomain.cloud" 103 log.Logger().Infof("\nIBM Kubernetes Service will use the default cluster domain: ") 104 log.Logger().Infof("%s", util.ColorInfo(customDomain)) 105 return customDomain, nil 106 } 107 log.Logger().Infof("ERROR getting IBM Kubernetes Service will use the default cluster domain:") 108 log.Logger().Infof(err.Error()) 109 } 110 111 if address != "" { 112 addNip := true 113 aip := net.ParseIP(address) 114 if aip == nil { 115 log.Logger().Infof("The Ingress address %s is not an IP address. We recommend we try resolve it to a public IP address and use that for the domain to access services externally.", 116 util.ColorInfo(address)) 117 118 addressIP := "" 119 resolve := true 120 if !o.BatchMode { 121 answer, err := util.Confirm("Would you like wait and resolve this address to an IP address and use it for the domain?", true, 122 "Should we convert "+address+" to an IP address so we can access resources externally", o.GetIOFileHandles()) 123 if err != nil { 124 return "", err 125 } 126 resolve = answer 127 } 128 if resolve { 129 log.Logger().Infof("Waiting for %s to be resolvable to an IP address...", util.ColorInfo(address)) 130 f := func() error { 131 ips, err := net.LookupIP(address) 132 if err == nil { 133 for _, ip := range ips { 134 t := ip.String() 135 if t != "" && !ip.IsLoopback() { 136 addressIP = t 137 return nil 138 } 139 } 140 } 141 return fmt.Errorf("Address cannot be resolved yet %s", address) 142 } 143 err := o.RetryQuiet(5*6, time.Second*10, f) 144 if err != nil { 145 return "", err 146 } 147 } 148 if addressIP == "" { 149 addNip = false 150 log.Logger().Infof("Still not managed to resolve address %s into an IP address. Please try figure out the domain by hand", address) 151 } else { 152 log.Logger().Infof("%s resolved to IP %s", util.ColorInfo(address), util.ColorInfo(addressIP)) 153 address = addressIP 154 } 155 } 156 if addNip && !strings.HasSuffix(address, ".amazonaws.com") { 157 defaultDomain = fmt.Sprintf("%s.nip.io", address) 158 } 159 } 160 161 if domain == "" { 162 if o.BatchMode { 163 log.Logger().Infof("No domain flag provided so using default %s to generate Ingress rules", defaultDomain) 164 return defaultDomain, nil 165 } 166 log.Logger().Infof("You can now configure a wildcard DNS pointing to the new Load Balancer address %s", util.ColorInfo(address)) 167 log.Logger().Infof("If you don't have a wildcard DNS setup then create a DNS (A) record and point it at: %s, then use the DNS domain in the next input...", util.ColorInfo(address)) 168 169 log.Logger().Info("\nIf you do not have a custom domain setup yet, Ingress rules will be set for magic DNS nip.io.") 170 // Todo: Evaluate mention of this deprecated command 171 log.Logger().Infof("Once you have a custom domain ready, you can update with the command %s", util.ColorInfo("jx upgrade ingress --cluster")) 172 173 if domain == "" { 174 prompt := &survey.Input{ 175 Message: "Domain", 176 Default: defaultDomain, 177 Help: "Enter your custom domain that is used to generate Ingress rules, defaults to the magic DNS nip.io", 178 } 179 err := survey.AskOne(prompt, &domain, 180 survey.ComposeValidators(survey.Required, surveyutils.NoWhiteSpaceValidator()), surveyOpts) 181 if err != nil { 182 return "", err 183 } 184 } 185 if domain == "" { 186 domain = defaultDomain 187 } 188 } else { 189 if domain != defaultDomain { 190 log.Logger().Infof("You can now configure your wildcard DNS %s to point to %s", domain, address) 191 } 192 } 193 194 return domain, nil 195 }