From 7c684e43318300187dc92d96679fc72c08a41d90 Mon Sep 17 00:00:00 2001 From: Brendan Burns Date: Tue, 24 Mar 2015 21:39:19 -0700 Subject: [PATCH] Pipe through the ability to set the external hostname for swagger URLs. --- cmd/kube-apiserver/app/server.go | 28 ++++++++++++++++++++++++++ pkg/master/master.go | 34 +++++++++++++++++++++++--------- pkg/master/publish.go | 4 ++-- 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index 916683192f..9fe43aa539 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -23,6 +23,7 @@ import ( "crypto/tls" "net" "net/http" + "os" "strconv" "strings" "time" @@ -45,6 +46,7 @@ import ( // APIServer runs a kubernetes api server. type APIServer struct { WideOpenPort int + ExternalHost string Address util.IP PublicAddressOverride util.IP ReadOnlyPort int @@ -151,6 +153,7 @@ func (s *APIServer) AddFlags(fs *pflag.FlagSet) { client.BindKubeletClientConfigFlags(fs, &s.KubeletConfig) fs.StringVar(&s.ClusterName, "cluster_name", s.ClusterName, "The instance prefix for the cluster") fs.BoolVar(&s.EnableProfiling, "profiling", false, "Enable profiling via web interface host:port/debug/pprof/") + fs.StringVar(&s.ExternalHost, "external_hostname", "", "The hostname to use when generating externalized URLs for this master (e.g. Swagger API Docs.)") } // TODO: Longer term we should read this from some config store, rather than a flag. @@ -227,6 +230,30 @@ func (s *APIServer) Run(_ []string) error { admissionControlPluginNames := strings.Split(s.AdmissionControl, ",") admissionController := admission.NewFromPlugins(client, admissionControlPluginNames, s.AdmissionControlConfigFile) + if len(s.ExternalHost) == 0 { + // TODO: extend for other providers + if s.CloudProvider == "gce" { + instances, supported := cloud.Instances() + if !supported { + glog.Fatalf("gce cloud provider has no instances. this shouldn't happen. exiting.") + } + name, err := os.Hostname() + if err != nil { + glog.Fatalf("failed to get hostname: %v", err) + } + addrs, err := instances.NodeAddresses(name) + if err != nil { + glog.Warningf("unable to obtain external host address from cloud provider: %v", err) + } else { + for _, addr := range addrs { + if addr.Type == api.NodeExternalIP { + s.ExternalHost = addr.Address + } + } + } + } + } + config := &master.Config{ Cloud: cloud, EtcdHelper: helper, @@ -249,6 +276,7 @@ func (s *APIServer) Run(_ []string) error { EnableV1Beta3: v1beta3, MasterServiceNamespace: s.MasterServiceNamespace, ClusterName: s.ClusterName, + ExternalHost: s.ExternalHost, } m := master.New(config) diff --git a/pkg/master/master.go b/pkg/master/master.go index 81ec2b7ca5..0bc24afcd3 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -107,6 +107,9 @@ type Config struct { // Defaults to 6443 if not set. ReadWritePort int + // ExternalHost is the host name to use for external (public internet) facing URLs (e.g. Swagger) + ExternalHost string + // If nil, the first result from net.InterfaceAddrs will be used. PublicAddress net.IP @@ -141,7 +144,10 @@ type Master struct { v1beta3 bool requestContextMapper api.RequestContextMapper - publicIP net.IP + // External host is the name that should be used in external (public internet) URLs for this master + externalHost string + // clusterIP is the IP address of the master within the cluster. + clusterIP net.IP publicReadOnlyPort int publicReadWritePort int serviceReadOnlyIP net.IP @@ -277,7 +283,8 @@ func New(c *Config) *Master { cacheTimeout: c.CacheTimeout, masterCount: c.MasterCount, - publicIP: c.PublicAddress, + externalHost: c.ExternalHost, + clusterIP: c.PublicAddress, publicReadOnlyPort: c.ReadOnlyPort, publicReadWritePort: c.ReadWritePort, serviceReadOnlyIP: serviceReadOnlyIP, @@ -494,14 +501,23 @@ func (m *Master) init(c *Config) { // register their own web services into the Kubernetes mux prior to initialization // of swagger, so that other resource types show up in the documentation. func (m *Master) InstallSwaggerAPI() { - webServicesUrl := "" - // Use the secure read write port, if available. - if m.publicReadWritePort != 0 { - webServicesUrl = "https://" + net.JoinHostPort(m.publicIP.String(), strconv.Itoa(m.publicReadWritePort)) - } else { - // Use the read only port. - webServicesUrl = "http://" + net.JoinHostPort(m.publicIP.String(), strconv.Itoa(m.publicReadOnlyPort)) + hostAndPort := m.externalHost + protocol := "https://" + + // TODO: this is kind of messed up, we should just pipe in the full URL from the outside, rather + // than guessing at it. + if len(m.externalHost) == 0 && m.clusterIP != nil { + host := m.clusterIP.String() + if m.publicReadWritePort != 0 { + hostAndPort = net.JoinHostPort(host, strconv.Itoa(m.publicReadWritePort)) + } else { + // Use the read only port. + hostAndPort = net.JoinHostPort(host, strconv.Itoa(m.publicReadOnlyPort)) + protocol = "http://" + } } + webServicesUrl := protocol + hostAndPort + // Enable swagger UI and discovery API swaggerConfig := swagger.Config{ WebServicesUrl: webServicesUrl, diff --git a/pkg/master/publish.go b/pkg/master/publish.go index c2f66f8520..1b4d593b4f 100644 --- a/pkg/master/publish.go +++ b/pkg/master/publish.go @@ -40,7 +40,7 @@ func (m *Master) serviceWriterLoop(stop chan struct{}) { if err := m.createMasterServiceIfNeeded("kubernetes", m.serviceReadWriteIP, m.serviceReadWritePort); err != nil { glog.Errorf("Can't create rw service: %v", err) } - if err := m.ensureEndpointsContain("kubernetes", m.publicIP, m.publicReadWritePort); err != nil { + if err := m.ensureEndpointsContain("kubernetes", m.clusterIP, m.publicReadWritePort); err != nil { glog.Errorf("Can't create rw endpoints: %v", err) } } @@ -65,7 +65,7 @@ func (m *Master) roServiceWriterLoop(stop chan struct{}) { if err := m.createMasterServiceIfNeeded("kubernetes-ro", m.serviceReadOnlyIP, m.serviceReadOnlyPort); err != nil { glog.Errorf("Can't create ro service: %v", err) } - if err := m.ensureEndpointsContain("kubernetes-ro", m.publicIP, m.publicReadOnlyPort); err != nil { + if err := m.ensureEndpointsContain("kubernetes-ro", m.clusterIP, m.publicReadOnlyPort); err != nil { glog.Errorf("Can't create ro endpoints: %v", err) } }