-
Notifications
You must be signed in to change notification settings - Fork 38.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding hostname to groups discovery information #20626
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -308,6 +308,14 @@ type APIVersions struct { | |
TypeMeta `json:",inline"` | ||
// versions are the api versions that are available. | ||
Versions []string `json:"versions"` | ||
// a map of client CIDR to server address that is serving this group. | ||
// This is to help clients reach servers in the most network-efficient way possible. | ||
// Clients can use the appropriate server address as per the CIDR that they match. | ||
// In case of multiple matches, clients should use the longest matching CIDR. | ||
// The server returns only those CIDRs that it thinks that the client can match. | ||
// For example: the master will return an internal IP CIDR only, if the client reaches the server using an internal IP. | ||
// Server looks at X-Forwarded-For header or X-Real-Ip header or request.RemoteAddr (in that order) to get the client IP. | ||
ServerAddressByClientCIDRs []ServerAddressByClientCIDR `json:"serverAddressByClientCIDRs"` | ||
} | ||
|
||
// APIGroupList is a list of APIGroup, to allow clients to discover the API at | ||
|
@@ -329,6 +337,23 @@ type APIGroup struct { | |
// preferredVersion is the version preferred by the API server, which | ||
// probably is the storage version. | ||
PreferredVersion GroupVersionForDiscovery `json:"preferredVersion,omitempty"` | ||
// a map of client CIDR to server address that is serving this group. | ||
// This is to help clients reach servers in the most network-efficient way possible. | ||
// Clients can use the appropriate server address as per the CIDR that they match. | ||
// In case of multiple matches, clients should use the longest matching CIDR. | ||
// The server returns only those CIDRs that it thinks that the client can match. | ||
// For example: the master will return an internal IP CIDR only, if the client reaches the server using an internal IP. | ||
// Server looks at X-Forwarded-For header or X-Real-Ip header or request.RemoteAddr (in that order) to get the client IP. | ||
ServerAddressByClientCIDRs []ServerAddressByClientCIDR `json:"serverAddressByClientCIDRs"` | ||
} | ||
|
||
// ServerAddressByClientCIDR helps the client to determine the server address that they should use, depending on the clientCIDR that they match. | ||
type ServerAddressByClientCIDR struct { | ||
// The CIDR with which clients can match their IP to figure out the server address that they should use. | ||
ClientCIDR string `json:"clientCIDR"` | ||
// Address of this server, suitable for a client that matches the above CIDR. | ||
// This can be a hostname, hostname:port, IP or IP:port. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will we ever omit the port? I think we have to include it all the time? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess we can omit it if its 80? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Won't it always be https? so 443 :) But yeah, I guess it's not a big deal. |
||
ServerAddress string `json:"serverAddress"` | ||
} | ||
|
||
// GroupVersion contains the "group/version" and "version" string of a version. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -256,9 +256,12 @@ type Config struct { | |
// The range of IPs to be assigned to services with type=ClusterIP or greater | ||
ServiceClusterIPRange *net.IPNet | ||
|
||
// The IP address for the GenericAPIServer service (must be inside ServiceClusterIPRange | ||
// The IP address for the GenericAPIServer service (must be inside ServiceClusterIPRange) | ||
ServiceReadWriteIP net.IP | ||
|
||
// Port for the apiserver service. | ||
ServiceReadWritePort int | ||
|
||
// The range of ports to be assigned to services with type=NodePort or greater | ||
ServiceNodePortRange utilnet.PortRange | ||
|
||
|
@@ -308,8 +311,9 @@ type GenericAPIServer struct { | |
ApiGroupVersionOverrides map[string]APIGroupVersionOverride | ||
RequestContextMapper api.RequestContextMapper | ||
|
||
// External host is the name that should be used in external (public internet) URLs for this GenericAPIServer | ||
externalHost string | ||
// ExternalAddress is the address (hostname or IP and port) that should be used in | ||
// external (public internet) URLs for this GenericAPIServer. | ||
ExternalAddress string | ||
// ClusterIP is the IP address of the GenericAPIServer within the cluster. | ||
ClusterIP net.IP | ||
PublicReadWritePort int | ||
|
@@ -370,6 +374,9 @@ func setDefaults(c *Config) { | |
glog.V(4).Infof("Setting GenericAPIServer service IP to %q (read-write).", serviceReadWriteIP) | ||
c.ServiceReadWriteIP = serviceReadWriteIP | ||
} | ||
if c.ServiceReadWritePort == 0 { | ||
c.ServiceReadWritePort = 443 | ||
} | ||
if c.ServiceNodePortRange.Size == 0 { | ||
// TODO: Currently no way to specify an empty range (do we need to allow this?) | ||
// We should probably allow this for clouds that don't require NodePort to do load-balancing (GCE) | ||
|
@@ -392,6 +399,13 @@ func setDefaults(c *Config) { | |
if c.RequestContextMapper == nil { | ||
c.RequestContextMapper = api.NewRequestContextMapper() | ||
} | ||
if len(c.ExternalHost) == 0 && c.PublicAddress != nil { | ||
hostAndPort := c.PublicAddress.String() | ||
if c.ReadWritePort != 0 { | ||
hostAndPort = net.JoinHostPort(hostAndPort, strconv.Itoa(c.ServiceReadWritePort)) | ||
} | ||
c.ExternalHost = hostAndPort | ||
} | ||
} | ||
|
||
// New returns a new instance of GenericAPIServer from the given config. | ||
|
@@ -444,13 +458,12 @@ func New(c *Config) (*GenericAPIServer, error) { | |
cacheTimeout: c.CacheTimeout, | ||
MinRequestTimeout: time.Duration(c.MinRequestTimeout) * time.Second, | ||
|
||
MasterCount: c.MasterCount, | ||
externalHost: c.ExternalHost, | ||
ClusterIP: c.PublicAddress, | ||
PublicReadWritePort: c.ReadWritePort, | ||
ServiceReadWriteIP: c.ServiceReadWriteIP, | ||
// TODO: ServiceReadWritePort should be passed in as an argument, it may not always be 443 | ||
ServiceReadWritePort: 443, | ||
MasterCount: c.MasterCount, | ||
ExternalAddress: c.ExternalHost, | ||
ClusterIP: c.PublicAddress, | ||
PublicReadWritePort: c.ReadWritePort, | ||
ServiceReadWriteIP: c.ServiceReadWriteIP, | ||
ServiceReadWritePort: c.ServiceReadWritePort, | ||
ExtraServicePorts: c.ExtraServicePorts, | ||
ExtraEndpointPorts: c.ExtraEndpointPorts, | ||
|
||
|
@@ -603,7 +616,7 @@ func (s *GenericAPIServer) InstallAPIGroups(groupsInfo []APIGroupInfo) error { | |
|
||
// Installs handler at /apis to list all group versions for discovery | ||
func (s *GenericAPIServer) installGroupsDiscoveryHandler() { | ||
apiserver.AddApisWebService(s.Serializer, s.HandlerContainer, s.APIGroupPrefix, func() []unversioned.APIGroup { | ||
apiserver.AddApisWebService(s.Serializer, s.HandlerContainer, s.APIGroupPrefix, func(req *restful.Request) []unversioned.APIGroup { | ||
// Return the list of supported groups in sorted order (to have a deterministic order). | ||
groups := []unversioned.APIGroup{} | ||
groupNames := make([]string, len(s.apiGroupsForDiscovery)) | ||
|
@@ -614,7 +627,10 @@ func (s *GenericAPIServer) installGroupsDiscoveryHandler() { | |
} | ||
sort.Strings(groupNames) | ||
for _, groupName := range groupNames { | ||
groups = append(groups, s.apiGroupsForDiscovery[groupName]) | ||
apiGroup := s.apiGroupsForDiscovery[groupName] | ||
// Add ServerAddressByClientCIDRs. | ||
apiGroup.ServerAddressByClientCIDRs = s.getServerAddressByClientCIDRs(req.Request) | ||
groups = append(groups, apiGroup) | ||
} | ||
return groups | ||
}) | ||
|
@@ -738,7 +754,13 @@ func (s *GenericAPIServer) installAPIGroup(apiGroupInfo *APIGroupInfo) error { | |
// Install the version handler. | ||
if apiGroupInfo.IsLegacyGroup { | ||
// Add a handler at /api to enumerate the supported api versions. | ||
apiserver.AddApiWebService(s.Serializer, s.HandlerContainer, apiPrefix, apiVersions) | ||
apiserver.AddApiWebService(s.Serializer, s.HandlerContainer, apiPrefix, func(req *restful.Request) *unversioned.APIVersions { | ||
apiVersionsForDiscovery := unversioned.APIVersions{ | ||
ServerAddressByClientCIDRs: s.getServerAddressByClientCIDRs(req.Request), | ||
Versions: apiVersions, | ||
} | ||
return &apiVersionsForDiscovery | ||
}) | ||
} else { | ||
// Do not register empty group or empty version. Doing so claims /apis/ for the wrong entity to be returned. | ||
// Catching these here places the error much closer to its origin | ||
|
@@ -781,6 +803,27 @@ func (s *GenericAPIServer) RemoveAPIGroupForDiscovery(groupName string) { | |
delete(s.apiGroupsForDiscovery, groupName) | ||
} | ||
|
||
func (s *GenericAPIServer) getServerAddressByClientCIDRs(req *http.Request) []unversioned.ServerAddressByClientCIDR { | ||
addressCIDRMap := []unversioned.ServerAddressByClientCIDR{ | ||
{ | ||
ClientCIDR: "0.0.0.0/0", | ||
|
||
ServerAddress: s.ExternalAddress, | ||
}, | ||
} | ||
|
||
// Add internal CIDR if the request came from internal IP. | ||
clientIP := utilnet.GetClientIP(req) | ||
clusterCIDR := s.ServiceClusterIPRange | ||
if clusterCIDR.Contains(clientIP) { | ||
addressCIDRMap = append(addressCIDRMap, unversioned.ServerAddressByClientCIDR{ | ||
ClientCIDR: clusterCIDR.String(), | ||
ServerAddress: net.JoinHostPort(s.ServiceReadWriteIP.String(), strconv.Itoa(s.ServiceReadWritePort)), | ||
}) | ||
} | ||
return addressCIDRMap | ||
} | ||
|
||
func (s *GenericAPIServer) getAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupVersion unversioned.GroupVersion, apiPrefix string) (*apiserver.APIGroupVersion, error) { | ||
storage := make(map[string]rest.Storage) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think you can just delete this code? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nvm, I see you actually moved it. |
||
for k, v := range apiGroupInfo.VersionedResourcesStorageMap[groupVersion.Version] { | ||
|
@@ -817,17 +860,8 @@ func (s *GenericAPIServer) newAPIGroupVersion(groupMeta apimachinery.GroupMeta, | |
// 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 (s *GenericAPIServer) InstallSwaggerAPI() { | ||
hostAndPort := s.externalHost | ||
hostAndPort := s.ExternalAddress | ||
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(s.externalHost) == 0 && s.ClusterIP != nil { | ||
host := s.ClusterIP.String() | ||
if s.PublicReadWritePort != 0 { | ||
hostAndPort = net.JoinHostPort(host, strconv.Itoa(s.PublicReadWritePort)) | ||
} | ||
} | ||
webServicesUrl := protocol + hostAndPort | ||
|
||
// Enable swagger UI and discovery API | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To help clients reach servers in the most network-efficient way possible, a map of client CIDR to a server address believed reachable and ideal from that CIDR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added