Pipe through the ability to set the external hostname for swagger URLs.

pull/6/head
Brendan Burns 2015-03-24 21:39:19 -07:00
parent 8183a4805e
commit 7c684e4331
3 changed files with 55 additions and 11 deletions

View File

@ -23,6 +23,7 @@ import (
"crypto/tls" "crypto/tls"
"net" "net"
"net/http" "net/http"
"os"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -45,6 +46,7 @@ import (
// APIServer runs a kubernetes api server. // APIServer runs a kubernetes api server.
type APIServer struct { type APIServer struct {
WideOpenPort int WideOpenPort int
ExternalHost string
Address util.IP Address util.IP
PublicAddressOverride util.IP PublicAddressOverride util.IP
ReadOnlyPort int ReadOnlyPort int
@ -151,6 +153,7 @@ func (s *APIServer) AddFlags(fs *pflag.FlagSet) {
client.BindKubeletClientConfigFlags(fs, &s.KubeletConfig) client.BindKubeletClientConfigFlags(fs, &s.KubeletConfig)
fs.StringVar(&s.ClusterName, "cluster_name", s.ClusterName, "The instance prefix for the cluster") 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.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. // 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, ",") admissionControlPluginNames := strings.Split(s.AdmissionControl, ",")
admissionController := admission.NewFromPlugins(client, admissionControlPluginNames, s.AdmissionControlConfigFile) 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{ config := &master.Config{
Cloud: cloud, Cloud: cloud,
EtcdHelper: helper, EtcdHelper: helper,
@ -249,6 +276,7 @@ func (s *APIServer) Run(_ []string) error {
EnableV1Beta3: v1beta3, EnableV1Beta3: v1beta3,
MasterServiceNamespace: s.MasterServiceNamespace, MasterServiceNamespace: s.MasterServiceNamespace,
ClusterName: s.ClusterName, ClusterName: s.ClusterName,
ExternalHost: s.ExternalHost,
} }
m := master.New(config) m := master.New(config)

View File

@ -107,6 +107,9 @@ type Config struct {
// Defaults to 6443 if not set. // Defaults to 6443 if not set.
ReadWritePort int 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. // If nil, the first result from net.InterfaceAddrs will be used.
PublicAddress net.IP PublicAddress net.IP
@ -141,7 +144,10 @@ type Master struct {
v1beta3 bool v1beta3 bool
requestContextMapper api.RequestContextMapper 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 publicReadOnlyPort int
publicReadWritePort int publicReadWritePort int
serviceReadOnlyIP net.IP serviceReadOnlyIP net.IP
@ -277,7 +283,8 @@ func New(c *Config) *Master {
cacheTimeout: c.CacheTimeout, cacheTimeout: c.CacheTimeout,
masterCount: c.MasterCount, masterCount: c.MasterCount,
publicIP: c.PublicAddress, externalHost: c.ExternalHost,
clusterIP: c.PublicAddress,
publicReadOnlyPort: c.ReadOnlyPort, publicReadOnlyPort: c.ReadOnlyPort,
publicReadWritePort: c.ReadWritePort, publicReadWritePort: c.ReadWritePort,
serviceReadOnlyIP: serviceReadOnlyIP, serviceReadOnlyIP: serviceReadOnlyIP,
@ -494,14 +501,23 @@ func (m *Master) init(c *Config) {
// register their own web services into the Kubernetes mux prior to initialization // register their own web services into the Kubernetes mux prior to initialization
// of swagger, so that other resource types show up in the documentation. // of swagger, so that other resource types show up in the documentation.
func (m *Master) InstallSwaggerAPI() { func (m *Master) InstallSwaggerAPI() {
webServicesUrl := "" hostAndPort := m.externalHost
// Use the secure read write port, if available. protocol := "https://"
if m.publicReadWritePort != 0 {
webServicesUrl = "https://" + net.JoinHostPort(m.publicIP.String(), strconv.Itoa(m.publicReadWritePort)) // TODO: this is kind of messed up, we should just pipe in the full URL from the outside, rather
} else { // than guessing at it.
// Use the read only port. if len(m.externalHost) == 0 && m.clusterIP != nil {
webServicesUrl = "http://" + net.JoinHostPort(m.publicIP.String(), strconv.Itoa(m.publicReadOnlyPort)) 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 // Enable swagger UI and discovery API
swaggerConfig := swagger.Config{ swaggerConfig := swagger.Config{
WebServicesUrl: webServicesUrl, WebServicesUrl: webServicesUrl,

View File

@ -40,7 +40,7 @@ func (m *Master) serviceWriterLoop(stop chan struct{}) {
if err := m.createMasterServiceIfNeeded("kubernetes", m.serviceReadWriteIP, m.serviceReadWritePort); err != nil { if err := m.createMasterServiceIfNeeded("kubernetes", m.serviceReadWriteIP, m.serviceReadWritePort); err != nil {
glog.Errorf("Can't create rw service: %v", err) 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) 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 { if err := m.createMasterServiceIfNeeded("kubernetes-ro", m.serviceReadOnlyIP, m.serviceReadOnlyPort); err != nil {
glog.Errorf("Can't create ro service: %v", err) 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) glog.Errorf("Can't create ro endpoints: %v", err)
} }
} }