Merge pull request #14459 from bprashanth/l7_ingress_resource_refactor
Auto commit by PR queue bot
This commit is contained in:
@@ -292,6 +292,7 @@ _kubectl_get()
|
|||||||
must_have_one_noun+=("endpoints")
|
must_have_one_noun+=("endpoints")
|
||||||
must_have_one_noun+=("event")
|
must_have_one_noun+=("event")
|
||||||
must_have_one_noun+=("horizontalpodautoscaler")
|
must_have_one_noun+=("horizontalpodautoscaler")
|
||||||
|
must_have_one_noun+=("ingress")
|
||||||
must_have_one_noun+=("job")
|
must_have_one_noun+=("job")
|
||||||
must_have_one_noun+=("limitrange")
|
must_have_one_noun+=("limitrange")
|
||||||
must_have_one_noun+=("namespace")
|
must_have_one_noun+=("namespace")
|
||||||
@@ -462,6 +463,7 @@ _kubectl_delete()
|
|||||||
must_have_one_noun+=("endpoints")
|
must_have_one_noun+=("endpoints")
|
||||||
must_have_one_noun+=("event")
|
must_have_one_noun+=("event")
|
||||||
must_have_one_noun+=("horizontalpodautoscaler")
|
must_have_one_noun+=("horizontalpodautoscaler")
|
||||||
|
must_have_one_noun+=("ingress")
|
||||||
must_have_one_noun+=("job")
|
must_have_one_noun+=("job")
|
||||||
must_have_one_noun+=("limitrange")
|
must_have_one_noun+=("limitrange")
|
||||||
must_have_one_noun+=("namespace")
|
must_have_one_noun+=("namespace")
|
||||||
@@ -864,6 +866,7 @@ _kubectl_label()
|
|||||||
must_have_one_noun+=("endpoints")
|
must_have_one_noun+=("endpoints")
|
||||||
must_have_one_noun+=("event")
|
must_have_one_noun+=("event")
|
||||||
must_have_one_noun+=("horizontalpodautoscaler")
|
must_have_one_noun+=("horizontalpodautoscaler")
|
||||||
|
must_have_one_noun+=("ingress")
|
||||||
must_have_one_noun+=("job")
|
must_have_one_noun+=("job")
|
||||||
must_have_one_noun+=("limitrange")
|
must_have_one_noun+=("limitrange")
|
||||||
must_have_one_noun+=("namespace")
|
must_have_one_noun+=("namespace")
|
||||||
|
@@ -966,6 +966,28 @@ func deepCopy_experimental_DeploymentStrategy(in DeploymentStrategy, out *Deploy
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func deepCopy_experimental_HTTPIngressPath(in HTTPIngressPath, out *HTTPIngressPath, c *conversion.Cloner) error {
|
||||||
|
out.Path = in.Path
|
||||||
|
if err := deepCopy_experimental_IngressBackend(in.Backend, &out.Backend, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deepCopy_experimental_HTTPIngressRuleValue(in HTTPIngressRuleValue, out *HTTPIngressRuleValue, c *conversion.Cloner) error {
|
||||||
|
if in.Paths != nil {
|
||||||
|
out.Paths = make([]HTTPIngressPath, len(in.Paths))
|
||||||
|
for i := range in.Paths {
|
||||||
|
if err := deepCopy_experimental_HTTPIngressPath(in.Paths[i], &out.Paths[i], c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Paths = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func deepCopy_experimental_HorizontalPodAutoscaler(in HorizontalPodAutoscaler, out *HorizontalPodAutoscaler, c *conversion.Cloner) error {
|
func deepCopy_experimental_HorizontalPodAutoscaler(in HorizontalPodAutoscaler, out *HorizontalPodAutoscaler, c *conversion.Cloner) error {
|
||||||
if err := deepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
if err := deepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1058,13 +1080,10 @@ func deepCopy_experimental_Ingress(in Ingress, out *Ingress, c *conversion.Clone
|
|||||||
}
|
}
|
||||||
|
|
||||||
func deepCopy_experimental_IngressBackend(in IngressBackend, out *IngressBackend, c *conversion.Cloner) error {
|
func deepCopy_experimental_IngressBackend(in IngressBackend, out *IngressBackend, c *conversion.Cloner) error {
|
||||||
if err := deepCopy_api_LocalObjectReference(in.ServiceRef, &out.ServiceRef, c); err != nil {
|
out.ServiceName = in.ServiceName
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := deepCopy_util_IntOrString(in.ServicePort, &out.ServicePort, c); err != nil {
|
if err := deepCopy_util_IntOrString(in.ServicePort, &out.ServicePort, c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
out.Protocol = in.Protocol
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1088,30 +1107,35 @@ func deepCopy_experimental_IngressList(in IngressList, out *IngressList, c *conv
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deepCopy_experimental_IngressPath(in IngressPath, out *IngressPath, c *conversion.Cloner) error {
|
func deepCopy_experimental_IngressRule(in IngressRule, out *IngressRule, c *conversion.Cloner) error {
|
||||||
out.Path = in.Path
|
out.Host = in.Host
|
||||||
if err := deepCopy_experimental_IngressBackend(in.Backend, &out.Backend, c); err != nil {
|
if err := deepCopy_experimental_IngressRuleValue(in.IngressRuleValue, &out.IngressRuleValue, c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deepCopy_experimental_IngressRule(in IngressRule, out *IngressRule, c *conversion.Cloner) error {
|
func deepCopy_experimental_IngressRuleValue(in IngressRuleValue, out *IngressRuleValue, c *conversion.Cloner) error {
|
||||||
out.Host = in.Host
|
if in.HTTP != nil {
|
||||||
if in.Paths != nil {
|
out.HTTP = new(HTTPIngressRuleValue)
|
||||||
out.Paths = make([]IngressPath, len(in.Paths))
|
if err := deepCopy_experimental_HTTPIngressRuleValue(*in.HTTP, out.HTTP, c); err != nil {
|
||||||
for i := range in.Paths {
|
return err
|
||||||
if err := deepCopy_experimental_IngressPath(in.Paths[i], &out.Paths[i], c); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
out.Paths = nil
|
out.HTTP = nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deepCopy_experimental_IngressSpec(in IngressSpec, out *IngressSpec, c *conversion.Cloner) error {
|
func deepCopy_experimental_IngressSpec(in IngressSpec, out *IngressSpec, c *conversion.Cloner) error {
|
||||||
|
if in.Backend != nil {
|
||||||
|
out.Backend = new(IngressBackend)
|
||||||
|
if err := deepCopy_experimental_IngressBackend(*in.Backend, out.Backend, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Backend = nil
|
||||||
|
}
|
||||||
if in.Rules != nil {
|
if in.Rules != nil {
|
||||||
out.Rules = make([]IngressRule, len(in.Rules))
|
out.Rules = make([]IngressRule, len(in.Rules))
|
||||||
for i := range in.Rules {
|
for i := range in.Rules {
|
||||||
@@ -1458,6 +1482,8 @@ func init() {
|
|||||||
deepCopy_experimental_DeploymentSpec,
|
deepCopy_experimental_DeploymentSpec,
|
||||||
deepCopy_experimental_DeploymentStatus,
|
deepCopy_experimental_DeploymentStatus,
|
||||||
deepCopy_experimental_DeploymentStrategy,
|
deepCopy_experimental_DeploymentStrategy,
|
||||||
|
deepCopy_experimental_HTTPIngressPath,
|
||||||
|
deepCopy_experimental_HTTPIngressRuleValue,
|
||||||
deepCopy_experimental_HorizontalPodAutoscaler,
|
deepCopy_experimental_HorizontalPodAutoscaler,
|
||||||
deepCopy_experimental_HorizontalPodAutoscalerList,
|
deepCopy_experimental_HorizontalPodAutoscalerList,
|
||||||
deepCopy_experimental_HorizontalPodAutoscalerSpec,
|
deepCopy_experimental_HorizontalPodAutoscalerSpec,
|
||||||
@@ -1465,8 +1491,8 @@ func init() {
|
|||||||
deepCopy_experimental_Ingress,
|
deepCopy_experimental_Ingress,
|
||||||
deepCopy_experimental_IngressBackend,
|
deepCopy_experimental_IngressBackend,
|
||||||
deepCopy_experimental_IngressList,
|
deepCopy_experimental_IngressList,
|
||||||
deepCopy_experimental_IngressPath,
|
|
||||||
deepCopy_experimental_IngressRule,
|
deepCopy_experimental_IngressRule,
|
||||||
|
deepCopy_experimental_IngressRuleValue,
|
||||||
deepCopy_experimental_IngressSpec,
|
deepCopy_experimental_IngressSpec,
|
||||||
deepCopy_experimental_IngressStatus,
|
deepCopy_experimental_IngressStatus,
|
||||||
deepCopy_experimental_Job,
|
deepCopy_experimental_Job,
|
||||||
|
@@ -464,9 +464,10 @@ type JobCondition struct {
|
|||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// An Ingress is a way to give services externally-reachable urls. Each Ingress is a
|
// Ingress is a collection of rules that allow inbound connections to reach the
|
||||||
// collection of rules that allow inbound connections to reach the endpoints defined by
|
// endpoints defined by a backend. An Ingress can be configured to give services
|
||||||
// a backend.
|
// externally-reachable urls, load balance traffic, terminate SSL, offer name
|
||||||
|
// based virtual hosting etc.
|
||||||
type Ingress struct {
|
type Ingress struct {
|
||||||
unversioned.TypeMeta `json:",inline"`
|
unversioned.TypeMeta `json:",inline"`
|
||||||
// Standard object's metadata.
|
// Standard object's metadata.
|
||||||
@@ -495,11 +496,13 @@ type IngressList struct {
|
|||||||
|
|
||||||
// IngressSpec describes the Ingress the user wishes to exist.
|
// IngressSpec describes the Ingress the user wishes to exist.
|
||||||
type IngressSpec struct {
|
type IngressSpec struct {
|
||||||
// TODO: Add the ability to specify load-balancer IP just like what Service has already done?
|
// A default backend capable of servicing requests that don't match any
|
||||||
// A list of rules used to configure the Ingress.
|
// IngressRule. It is optional to allow the loadbalancer controller or
|
||||||
// http://<host>:<port>/<path>?<searchpart> -> IngressBackend
|
// defaulting logic to specify a global default.
|
||||||
// Where parts of the url conform to RFC 1738.
|
Backend *IngressBackend `json:"backend,omitempty"`
|
||||||
|
// A list of host rules used to configure the Ingress.
|
||||||
Rules []IngressRule `json:"rules"`
|
Rules []IngressRule `json:"rules"`
|
||||||
|
// TODO: Add the ability to specify load-balancer IP through claims
|
||||||
}
|
}
|
||||||
|
|
||||||
// IngressStatus describe the current state of the Ingress.
|
// IngressStatus describe the current state of the Ingress.
|
||||||
@@ -508,35 +511,71 @@ type IngressStatus struct {
|
|||||||
LoadBalancer api.LoadBalancerStatus `json:"loadBalancer,omitempty"`
|
LoadBalancer api.LoadBalancerStatus `json:"loadBalancer,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// IngressRule represents the rules mapping the paths under a specified host to the related backend services.
|
// IngressRule represents the rules mapping the paths under a specified host to
|
||||||
|
// the related backend services.
|
||||||
type IngressRule struct {
|
type IngressRule struct {
|
||||||
// Host is the fully qualified domain name of a network host, or its IP
|
// Host is the fully qualified domain name of a network host, as defined
|
||||||
// address as a set of four decimal digit groups separated by ".".
|
// by RFC 3986. Note the following deviations from the "host" part of the
|
||||||
// Conforms to RFC 1738.
|
// URI as defined in the RFC:
|
||||||
|
// 1. IPs are not allowed. Currently an IngressRuleValue can only apply to the
|
||||||
|
// IP in the Spec of the parent Ingress.
|
||||||
|
// 2. The `:` delimiter is not respected because ports are not allowed.
|
||||||
|
// Currently the port of an Ingress is implicitly :80 for http and
|
||||||
|
// :443 for https.
|
||||||
|
// Both these may change in the future.
|
||||||
|
// Incoming requests are matched against the Host before the IngressRuleValue.
|
||||||
Host string `json:"host,omitempty"`
|
Host string `json:"host,omitempty"`
|
||||||
|
// IngressRuleValue represents a rule to route requests for this IngressRule.
|
||||||
|
IngressRuleValue `json:",inline"`
|
||||||
|
}
|
||||||
|
|
||||||
// Paths describe a list of load-balancer rules under the specified host.
|
// IngressRuleValue represents a rule to apply against incoming requests. If the
|
||||||
Paths []IngressPath `json:"paths"`
|
// rule is satisfied, the request is routed to the specified backend.
|
||||||
|
type IngressRuleValue struct {
|
||||||
|
//TODO:
|
||||||
|
// 1. Consider renaming this resource and the associated rules so they
|
||||||
|
// aren't tied to Ingress. They can be used to route intra-cluster traffic.
|
||||||
|
// 2. Consider adding fields for ingress-type specific global options
|
||||||
|
// usable by a loadbalancer, like http keep-alive.
|
||||||
|
|
||||||
|
// Currently mixing different types of rules in a single Ingress is
|
||||||
|
// disallowed, so exactly one of the following must be set.
|
||||||
|
HTTP *HTTPIngressRuleValue `json:"http"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPIngressRuleValue is a list of http selectors pointing to IngressBackends.
|
||||||
|
// In the example: http://<host>/<path>?<searchpart> -> IngressBackend where
|
||||||
|
// where parts of the url correspond to RFC 3986, this resource will be used
|
||||||
|
// to match against everything after the last '/' and before the first '?'
|
||||||
|
// or '#'.
|
||||||
|
type HTTPIngressRuleValue struct {
|
||||||
|
// A collection of paths that map requests to IngressBackends.
|
||||||
|
Paths []HTTPIngressPath `json:"paths"`
|
||||||
|
// TODO: Consider adding fields for ingress-type specific global
|
||||||
|
// options usable by a loadbalancer, like http keep-alive.
|
||||||
}
|
}
|
||||||
|
|
||||||
// IngressPath associates a path regex with an IngressBackend.
|
// IngressPath associates a path regex with an IngressBackend.
|
||||||
// Incoming urls matching the Path are forwarded to the Backend.
|
// Incoming urls matching the Path are forwarded to the Backend.
|
||||||
type IngressPath struct {
|
type HTTPIngressPath struct {
|
||||||
// Path is a regex matched against the url of an incoming request.
|
// Path is a extended POSIX regex as defined by IEEE Std 1003.1,
|
||||||
|
// (i.e this follows the egrep/unix syntax, not the perl syntax)
|
||||||
|
// matched against the path of an incoming request. Currently it can
|
||||||
|
// contain characters disallowed from the conventional "path"
|
||||||
|
// part of a URL as defined by RFC 3986. Paths must begin with
|
||||||
|
// a '/'.
|
||||||
Path string `json:"path,omitempty"`
|
Path string `json:"path,omitempty"`
|
||||||
|
|
||||||
// Define the referenced service endpoint which the traffic will be forwarded to.
|
// Define the referenced service endpoint which the traffic will be
|
||||||
|
// forwarded to.
|
||||||
Backend IngressBackend `json:"backend"`
|
Backend IngressBackend `json:"backend"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// IngressBackend describes all endpoints for a given Service, port and protocol.
|
// IngressBackend describes all endpoints for a given Service and port.
|
||||||
type IngressBackend struct {
|
type IngressBackend struct {
|
||||||
// Specifies the referenced service.
|
// Specifies the name of the referenced service.
|
||||||
ServiceRef api.LocalObjectReference `json:"serviceRef"`
|
ServiceName string `json:"serviceName"`
|
||||||
|
|
||||||
// Specifies the port of the referenced service.
|
// Specifies the port of the referenced service.
|
||||||
ServicePort util.IntOrString `json:"servicePort,omitempty"`
|
ServicePort util.IntOrString `json:"servicePort"`
|
||||||
|
|
||||||
// Specifies the protocol of the referenced service.
|
|
||||||
Protocol api.Protocol `json:"protocol,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
@@ -2296,6 +2296,42 @@ func autoconvert_experimental_DeploymentStrategy_To_v1alpha1_DeploymentStrategy(
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func autoconvert_experimental_HTTPIngressPath_To_v1alpha1_HTTPIngressPath(in *experimental.HTTPIngressPath, out *HTTPIngressPath, s conversion.Scope) error {
|
||||||
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
|
defaulting.(func(*experimental.HTTPIngressPath))(in)
|
||||||
|
}
|
||||||
|
out.Path = in.Path
|
||||||
|
if err := convert_experimental_IngressBackend_To_v1alpha1_IngressBackend(&in.Backend, &out.Backend, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convert_experimental_HTTPIngressPath_To_v1alpha1_HTTPIngressPath(in *experimental.HTTPIngressPath, out *HTTPIngressPath, s conversion.Scope) error {
|
||||||
|
return autoconvert_experimental_HTTPIngressPath_To_v1alpha1_HTTPIngressPath(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoconvert_experimental_HTTPIngressRuleValue_To_v1alpha1_HTTPIngressRuleValue(in *experimental.HTTPIngressRuleValue, out *HTTPIngressRuleValue, s conversion.Scope) error {
|
||||||
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
|
defaulting.(func(*experimental.HTTPIngressRuleValue))(in)
|
||||||
|
}
|
||||||
|
if in.Paths != nil {
|
||||||
|
out.Paths = make([]HTTPIngressPath, len(in.Paths))
|
||||||
|
for i := range in.Paths {
|
||||||
|
if err := convert_experimental_HTTPIngressPath_To_v1alpha1_HTTPIngressPath(&in.Paths[i], &out.Paths[i], s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Paths = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convert_experimental_HTTPIngressRuleValue_To_v1alpha1_HTTPIngressRuleValue(in *experimental.HTTPIngressRuleValue, out *HTTPIngressRuleValue, s conversion.Scope) error {
|
||||||
|
return autoconvert_experimental_HTTPIngressRuleValue_To_v1alpha1_HTTPIngressRuleValue(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
func autoconvert_experimental_HorizontalPodAutoscaler_To_v1alpha1_HorizontalPodAutoscaler(in *experimental.HorizontalPodAutoscaler, out *HorizontalPodAutoscaler, s conversion.Scope) error {
|
func autoconvert_experimental_HorizontalPodAutoscaler_To_v1alpha1_HorizontalPodAutoscaler(in *experimental.HorizontalPodAutoscaler, out *HorizontalPodAutoscaler, s conversion.Scope) error {
|
||||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
defaulting.(func(*experimental.HorizontalPodAutoscaler))(in)
|
defaulting.(func(*experimental.HorizontalPodAutoscaler))(in)
|
||||||
@@ -2425,13 +2461,10 @@ func autoconvert_experimental_IngressBackend_To_v1alpha1_IngressBackend(in *expe
|
|||||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
defaulting.(func(*experimental.IngressBackend))(in)
|
defaulting.(func(*experimental.IngressBackend))(in)
|
||||||
}
|
}
|
||||||
if err := convert_api_LocalObjectReference_To_v1_LocalObjectReference(&in.ServiceRef, &out.ServiceRef, s); err != nil {
|
out.ServiceName = in.ServiceName
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := s.Convert(&in.ServicePort, &out.ServicePort, 0); err != nil {
|
if err := s.Convert(&in.ServicePort, &out.ServicePort, 0); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
out.Protocol = v1.Protocol(in.Protocol)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2466,35 +2499,13 @@ func convert_experimental_IngressList_To_v1alpha1_IngressList(in *experimental.I
|
|||||||
return autoconvert_experimental_IngressList_To_v1alpha1_IngressList(in, out, s)
|
return autoconvert_experimental_IngressList_To_v1alpha1_IngressList(in, out, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func autoconvert_experimental_IngressPath_To_v1alpha1_IngressPath(in *experimental.IngressPath, out *IngressPath, s conversion.Scope) error {
|
|
||||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
|
||||||
defaulting.(func(*experimental.IngressPath))(in)
|
|
||||||
}
|
|
||||||
out.Path = in.Path
|
|
||||||
if err := convert_experimental_IngressBackend_To_v1alpha1_IngressBackend(&in.Backend, &out.Backend, s); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func convert_experimental_IngressPath_To_v1alpha1_IngressPath(in *experimental.IngressPath, out *IngressPath, s conversion.Scope) error {
|
|
||||||
return autoconvert_experimental_IngressPath_To_v1alpha1_IngressPath(in, out, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func autoconvert_experimental_IngressRule_To_v1alpha1_IngressRule(in *experimental.IngressRule, out *IngressRule, s conversion.Scope) error {
|
func autoconvert_experimental_IngressRule_To_v1alpha1_IngressRule(in *experimental.IngressRule, out *IngressRule, s conversion.Scope) error {
|
||||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
defaulting.(func(*experimental.IngressRule))(in)
|
defaulting.(func(*experimental.IngressRule))(in)
|
||||||
}
|
}
|
||||||
out.Host = in.Host
|
out.Host = in.Host
|
||||||
if in.Paths != nil {
|
if err := convert_experimental_IngressRuleValue_To_v1alpha1_IngressRuleValue(&in.IngressRuleValue, &out.IngressRuleValue, s); err != nil {
|
||||||
out.Paths = make([]IngressPath, len(in.Paths))
|
return err
|
||||||
for i := range in.Paths {
|
|
||||||
if err := convert_experimental_IngressPath_To_v1alpha1_IngressPath(&in.Paths[i], &out.Paths[i], s); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
out.Paths = nil
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -2503,10 +2514,37 @@ func convert_experimental_IngressRule_To_v1alpha1_IngressRule(in *experimental.I
|
|||||||
return autoconvert_experimental_IngressRule_To_v1alpha1_IngressRule(in, out, s)
|
return autoconvert_experimental_IngressRule_To_v1alpha1_IngressRule(in, out, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func autoconvert_experimental_IngressRuleValue_To_v1alpha1_IngressRuleValue(in *experimental.IngressRuleValue, out *IngressRuleValue, s conversion.Scope) error {
|
||||||
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
|
defaulting.(func(*experimental.IngressRuleValue))(in)
|
||||||
|
}
|
||||||
|
if in.HTTP != nil {
|
||||||
|
out.HTTP = new(HTTPIngressRuleValue)
|
||||||
|
if err := convert_experimental_HTTPIngressRuleValue_To_v1alpha1_HTTPIngressRuleValue(in.HTTP, out.HTTP, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.HTTP = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convert_experimental_IngressRuleValue_To_v1alpha1_IngressRuleValue(in *experimental.IngressRuleValue, out *IngressRuleValue, s conversion.Scope) error {
|
||||||
|
return autoconvert_experimental_IngressRuleValue_To_v1alpha1_IngressRuleValue(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
func autoconvert_experimental_IngressSpec_To_v1alpha1_IngressSpec(in *experimental.IngressSpec, out *IngressSpec, s conversion.Scope) error {
|
func autoconvert_experimental_IngressSpec_To_v1alpha1_IngressSpec(in *experimental.IngressSpec, out *IngressSpec, s conversion.Scope) error {
|
||||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
defaulting.(func(*experimental.IngressSpec))(in)
|
defaulting.(func(*experimental.IngressSpec))(in)
|
||||||
}
|
}
|
||||||
|
if in.Backend != nil {
|
||||||
|
out.Backend = new(IngressBackend)
|
||||||
|
if err := convert_experimental_IngressBackend_To_v1alpha1_IngressBackend(in.Backend, out.Backend, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Backend = nil
|
||||||
|
}
|
||||||
if in.Rules != nil {
|
if in.Rules != nil {
|
||||||
out.Rules = make([]IngressRule, len(in.Rules))
|
out.Rules = make([]IngressRule, len(in.Rules))
|
||||||
for i := range in.Rules {
|
for i := range in.Rules {
|
||||||
@@ -3097,6 +3135,42 @@ func convert_v1alpha1_DeploymentStatus_To_experimental_DeploymentStatus(in *Depl
|
|||||||
return autoconvert_v1alpha1_DeploymentStatus_To_experimental_DeploymentStatus(in, out, s)
|
return autoconvert_v1alpha1_DeploymentStatus_To_experimental_DeploymentStatus(in, out, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func autoconvert_v1alpha1_HTTPIngressPath_To_experimental_HTTPIngressPath(in *HTTPIngressPath, out *experimental.HTTPIngressPath, s conversion.Scope) error {
|
||||||
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
|
defaulting.(func(*HTTPIngressPath))(in)
|
||||||
|
}
|
||||||
|
out.Path = in.Path
|
||||||
|
if err := convert_v1alpha1_IngressBackend_To_experimental_IngressBackend(&in.Backend, &out.Backend, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convert_v1alpha1_HTTPIngressPath_To_experimental_HTTPIngressPath(in *HTTPIngressPath, out *experimental.HTTPIngressPath, s conversion.Scope) error {
|
||||||
|
return autoconvert_v1alpha1_HTTPIngressPath_To_experimental_HTTPIngressPath(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func autoconvert_v1alpha1_HTTPIngressRuleValue_To_experimental_HTTPIngressRuleValue(in *HTTPIngressRuleValue, out *experimental.HTTPIngressRuleValue, s conversion.Scope) error {
|
||||||
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
|
defaulting.(func(*HTTPIngressRuleValue))(in)
|
||||||
|
}
|
||||||
|
if in.Paths != nil {
|
||||||
|
out.Paths = make([]experimental.HTTPIngressPath, len(in.Paths))
|
||||||
|
for i := range in.Paths {
|
||||||
|
if err := convert_v1alpha1_HTTPIngressPath_To_experimental_HTTPIngressPath(&in.Paths[i], &out.Paths[i], s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Paths = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convert_v1alpha1_HTTPIngressRuleValue_To_experimental_HTTPIngressRuleValue(in *HTTPIngressRuleValue, out *experimental.HTTPIngressRuleValue, s conversion.Scope) error {
|
||||||
|
return autoconvert_v1alpha1_HTTPIngressRuleValue_To_experimental_HTTPIngressRuleValue(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
func autoconvert_v1alpha1_HorizontalPodAutoscaler_To_experimental_HorizontalPodAutoscaler(in *HorizontalPodAutoscaler, out *experimental.HorizontalPodAutoscaler, s conversion.Scope) error {
|
func autoconvert_v1alpha1_HorizontalPodAutoscaler_To_experimental_HorizontalPodAutoscaler(in *HorizontalPodAutoscaler, out *experimental.HorizontalPodAutoscaler, s conversion.Scope) error {
|
||||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
defaulting.(func(*HorizontalPodAutoscaler))(in)
|
defaulting.(func(*HorizontalPodAutoscaler))(in)
|
||||||
@@ -3226,13 +3300,10 @@ func autoconvert_v1alpha1_IngressBackend_To_experimental_IngressBackend(in *Ingr
|
|||||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
defaulting.(func(*IngressBackend))(in)
|
defaulting.(func(*IngressBackend))(in)
|
||||||
}
|
}
|
||||||
if err := convert_v1_LocalObjectReference_To_api_LocalObjectReference(&in.ServiceRef, &out.ServiceRef, s); err != nil {
|
out.ServiceName = in.ServiceName
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := s.Convert(&in.ServicePort, &out.ServicePort, 0); err != nil {
|
if err := s.Convert(&in.ServicePort, &out.ServicePort, 0); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
out.Protocol = api.Protocol(in.Protocol)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3267,35 +3338,13 @@ func convert_v1alpha1_IngressList_To_experimental_IngressList(in *IngressList, o
|
|||||||
return autoconvert_v1alpha1_IngressList_To_experimental_IngressList(in, out, s)
|
return autoconvert_v1alpha1_IngressList_To_experimental_IngressList(in, out, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
func autoconvert_v1alpha1_IngressPath_To_experimental_IngressPath(in *IngressPath, out *experimental.IngressPath, s conversion.Scope) error {
|
|
||||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
|
||||||
defaulting.(func(*IngressPath))(in)
|
|
||||||
}
|
|
||||||
out.Path = in.Path
|
|
||||||
if err := convert_v1alpha1_IngressBackend_To_experimental_IngressBackend(&in.Backend, &out.Backend, s); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func convert_v1alpha1_IngressPath_To_experimental_IngressPath(in *IngressPath, out *experimental.IngressPath, s conversion.Scope) error {
|
|
||||||
return autoconvert_v1alpha1_IngressPath_To_experimental_IngressPath(in, out, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func autoconvert_v1alpha1_IngressRule_To_experimental_IngressRule(in *IngressRule, out *experimental.IngressRule, s conversion.Scope) error {
|
func autoconvert_v1alpha1_IngressRule_To_experimental_IngressRule(in *IngressRule, out *experimental.IngressRule, s conversion.Scope) error {
|
||||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
defaulting.(func(*IngressRule))(in)
|
defaulting.(func(*IngressRule))(in)
|
||||||
}
|
}
|
||||||
out.Host = in.Host
|
out.Host = in.Host
|
||||||
if in.Paths != nil {
|
if err := convert_v1alpha1_IngressRuleValue_To_experimental_IngressRuleValue(&in.IngressRuleValue, &out.IngressRuleValue, s); err != nil {
|
||||||
out.Paths = make([]experimental.IngressPath, len(in.Paths))
|
return err
|
||||||
for i := range in.Paths {
|
|
||||||
if err := convert_v1alpha1_IngressPath_To_experimental_IngressPath(&in.Paths[i], &out.Paths[i], s); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
out.Paths = nil
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -3304,10 +3353,37 @@ func convert_v1alpha1_IngressRule_To_experimental_IngressRule(in *IngressRule, o
|
|||||||
return autoconvert_v1alpha1_IngressRule_To_experimental_IngressRule(in, out, s)
|
return autoconvert_v1alpha1_IngressRule_To_experimental_IngressRule(in, out, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func autoconvert_v1alpha1_IngressRuleValue_To_experimental_IngressRuleValue(in *IngressRuleValue, out *experimental.IngressRuleValue, s conversion.Scope) error {
|
||||||
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
|
defaulting.(func(*IngressRuleValue))(in)
|
||||||
|
}
|
||||||
|
if in.HTTP != nil {
|
||||||
|
out.HTTP = new(experimental.HTTPIngressRuleValue)
|
||||||
|
if err := convert_v1alpha1_HTTPIngressRuleValue_To_experimental_HTTPIngressRuleValue(in.HTTP, out.HTTP, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.HTTP = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convert_v1alpha1_IngressRuleValue_To_experimental_IngressRuleValue(in *IngressRuleValue, out *experimental.IngressRuleValue, s conversion.Scope) error {
|
||||||
|
return autoconvert_v1alpha1_IngressRuleValue_To_experimental_IngressRuleValue(in, out, s)
|
||||||
|
}
|
||||||
|
|
||||||
func autoconvert_v1alpha1_IngressSpec_To_experimental_IngressSpec(in *IngressSpec, out *experimental.IngressSpec, s conversion.Scope) error {
|
func autoconvert_v1alpha1_IngressSpec_To_experimental_IngressSpec(in *IngressSpec, out *experimental.IngressSpec, s conversion.Scope) error {
|
||||||
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
|
||||||
defaulting.(func(*IngressSpec))(in)
|
defaulting.(func(*IngressSpec))(in)
|
||||||
}
|
}
|
||||||
|
if in.Backend != nil {
|
||||||
|
out.Backend = new(experimental.IngressBackend)
|
||||||
|
if err := convert_v1alpha1_IngressBackend_To_experimental_IngressBackend(in.Backend, out.Backend, s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Backend = nil
|
||||||
|
}
|
||||||
if in.Rules != nil {
|
if in.Rules != nil {
|
||||||
out.Rules = make([]experimental.IngressRule, len(in.Rules))
|
out.Rules = make([]experimental.IngressRule, len(in.Rules))
|
||||||
for i := range in.Rules {
|
for i := range in.Rules {
|
||||||
@@ -3751,13 +3827,15 @@ func init() {
|
|||||||
autoconvert_experimental_DeploymentStatus_To_v1alpha1_DeploymentStatus,
|
autoconvert_experimental_DeploymentStatus_To_v1alpha1_DeploymentStatus,
|
||||||
autoconvert_experimental_DeploymentStrategy_To_v1alpha1_DeploymentStrategy,
|
autoconvert_experimental_DeploymentStrategy_To_v1alpha1_DeploymentStrategy,
|
||||||
autoconvert_experimental_Deployment_To_v1alpha1_Deployment,
|
autoconvert_experimental_Deployment_To_v1alpha1_Deployment,
|
||||||
|
autoconvert_experimental_HTTPIngressPath_To_v1alpha1_HTTPIngressPath,
|
||||||
|
autoconvert_experimental_HTTPIngressRuleValue_To_v1alpha1_HTTPIngressRuleValue,
|
||||||
autoconvert_experimental_HorizontalPodAutoscalerList_To_v1alpha1_HorizontalPodAutoscalerList,
|
autoconvert_experimental_HorizontalPodAutoscalerList_To_v1alpha1_HorizontalPodAutoscalerList,
|
||||||
autoconvert_experimental_HorizontalPodAutoscalerSpec_To_v1alpha1_HorizontalPodAutoscalerSpec,
|
autoconvert_experimental_HorizontalPodAutoscalerSpec_To_v1alpha1_HorizontalPodAutoscalerSpec,
|
||||||
autoconvert_experimental_HorizontalPodAutoscalerStatus_To_v1alpha1_HorizontalPodAutoscalerStatus,
|
autoconvert_experimental_HorizontalPodAutoscalerStatus_To_v1alpha1_HorizontalPodAutoscalerStatus,
|
||||||
autoconvert_experimental_HorizontalPodAutoscaler_To_v1alpha1_HorizontalPodAutoscaler,
|
autoconvert_experimental_HorizontalPodAutoscaler_To_v1alpha1_HorizontalPodAutoscaler,
|
||||||
autoconvert_experimental_IngressBackend_To_v1alpha1_IngressBackend,
|
autoconvert_experimental_IngressBackend_To_v1alpha1_IngressBackend,
|
||||||
autoconvert_experimental_IngressList_To_v1alpha1_IngressList,
|
autoconvert_experimental_IngressList_To_v1alpha1_IngressList,
|
||||||
autoconvert_experimental_IngressPath_To_v1alpha1_IngressPath,
|
autoconvert_experimental_IngressRuleValue_To_v1alpha1_IngressRuleValue,
|
||||||
autoconvert_experimental_IngressRule_To_v1alpha1_IngressRule,
|
autoconvert_experimental_IngressRule_To_v1alpha1_IngressRule,
|
||||||
autoconvert_experimental_IngressSpec_To_v1alpha1_IngressSpec,
|
autoconvert_experimental_IngressSpec_To_v1alpha1_IngressSpec,
|
||||||
autoconvert_experimental_IngressStatus_To_v1alpha1_IngressStatus,
|
autoconvert_experimental_IngressStatus_To_v1alpha1_IngressStatus,
|
||||||
@@ -3827,13 +3905,15 @@ func init() {
|
|||||||
autoconvert_v1alpha1_DeploymentSpec_To_experimental_DeploymentSpec,
|
autoconvert_v1alpha1_DeploymentSpec_To_experimental_DeploymentSpec,
|
||||||
autoconvert_v1alpha1_DeploymentStatus_To_experimental_DeploymentStatus,
|
autoconvert_v1alpha1_DeploymentStatus_To_experimental_DeploymentStatus,
|
||||||
autoconvert_v1alpha1_Deployment_To_experimental_Deployment,
|
autoconvert_v1alpha1_Deployment_To_experimental_Deployment,
|
||||||
|
autoconvert_v1alpha1_HTTPIngressPath_To_experimental_HTTPIngressPath,
|
||||||
|
autoconvert_v1alpha1_HTTPIngressRuleValue_To_experimental_HTTPIngressRuleValue,
|
||||||
autoconvert_v1alpha1_HorizontalPodAutoscalerList_To_experimental_HorizontalPodAutoscalerList,
|
autoconvert_v1alpha1_HorizontalPodAutoscalerList_To_experimental_HorizontalPodAutoscalerList,
|
||||||
autoconvert_v1alpha1_HorizontalPodAutoscalerSpec_To_experimental_HorizontalPodAutoscalerSpec,
|
autoconvert_v1alpha1_HorizontalPodAutoscalerSpec_To_experimental_HorizontalPodAutoscalerSpec,
|
||||||
autoconvert_v1alpha1_HorizontalPodAutoscalerStatus_To_experimental_HorizontalPodAutoscalerStatus,
|
autoconvert_v1alpha1_HorizontalPodAutoscalerStatus_To_experimental_HorizontalPodAutoscalerStatus,
|
||||||
autoconvert_v1alpha1_HorizontalPodAutoscaler_To_experimental_HorizontalPodAutoscaler,
|
autoconvert_v1alpha1_HorizontalPodAutoscaler_To_experimental_HorizontalPodAutoscaler,
|
||||||
autoconvert_v1alpha1_IngressBackend_To_experimental_IngressBackend,
|
autoconvert_v1alpha1_IngressBackend_To_experimental_IngressBackend,
|
||||||
autoconvert_v1alpha1_IngressList_To_experimental_IngressList,
|
autoconvert_v1alpha1_IngressList_To_experimental_IngressList,
|
||||||
autoconvert_v1alpha1_IngressPath_To_experimental_IngressPath,
|
autoconvert_v1alpha1_IngressRuleValue_To_experimental_IngressRuleValue,
|
||||||
autoconvert_v1alpha1_IngressRule_To_experimental_IngressRule,
|
autoconvert_v1alpha1_IngressRule_To_experimental_IngressRule,
|
||||||
autoconvert_v1alpha1_IngressSpec_To_experimental_IngressSpec,
|
autoconvert_v1alpha1_IngressSpec_To_experimental_IngressSpec,
|
||||||
autoconvert_v1alpha1_IngressStatus_To_experimental_IngressStatus,
|
autoconvert_v1alpha1_IngressStatus_To_experimental_IngressStatus,
|
||||||
|
@@ -978,6 +978,28 @@ func deepCopy_v1alpha1_DeploymentStrategy(in DeploymentStrategy, out *Deployment
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func deepCopy_v1alpha1_HTTPIngressPath(in HTTPIngressPath, out *HTTPIngressPath, c *conversion.Cloner) error {
|
||||||
|
out.Path = in.Path
|
||||||
|
if err := deepCopy_v1alpha1_IngressBackend(in.Backend, &out.Backend, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deepCopy_v1alpha1_HTTPIngressRuleValue(in HTTPIngressRuleValue, out *HTTPIngressRuleValue, c *conversion.Cloner) error {
|
||||||
|
if in.Paths != nil {
|
||||||
|
out.Paths = make([]HTTPIngressPath, len(in.Paths))
|
||||||
|
for i := range in.Paths {
|
||||||
|
if err := deepCopy_v1alpha1_HTTPIngressPath(in.Paths[i], &out.Paths[i], c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Paths = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func deepCopy_v1alpha1_HorizontalPodAutoscaler(in HorizontalPodAutoscaler, out *HorizontalPodAutoscaler, c *conversion.Cloner) error {
|
func deepCopy_v1alpha1_HorizontalPodAutoscaler(in HorizontalPodAutoscaler, out *HorizontalPodAutoscaler, c *conversion.Cloner) error {
|
||||||
if err := deepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
if err := deepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1070,13 +1092,10 @@ func deepCopy_v1alpha1_Ingress(in Ingress, out *Ingress, c *conversion.Cloner) e
|
|||||||
}
|
}
|
||||||
|
|
||||||
func deepCopy_v1alpha1_IngressBackend(in IngressBackend, out *IngressBackend, c *conversion.Cloner) error {
|
func deepCopy_v1alpha1_IngressBackend(in IngressBackend, out *IngressBackend, c *conversion.Cloner) error {
|
||||||
if err := deepCopy_v1_LocalObjectReference(in.ServiceRef, &out.ServiceRef, c); err != nil {
|
out.ServiceName = in.ServiceName
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := deepCopy_util_IntOrString(in.ServicePort, &out.ServicePort, c); err != nil {
|
if err := deepCopy_util_IntOrString(in.ServicePort, &out.ServicePort, c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
out.Protocol = in.Protocol
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1100,30 +1119,35 @@ func deepCopy_v1alpha1_IngressList(in IngressList, out *IngressList, c *conversi
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deepCopy_v1alpha1_IngressPath(in IngressPath, out *IngressPath, c *conversion.Cloner) error {
|
func deepCopy_v1alpha1_IngressRule(in IngressRule, out *IngressRule, c *conversion.Cloner) error {
|
||||||
out.Path = in.Path
|
out.Host = in.Host
|
||||||
if err := deepCopy_v1alpha1_IngressBackend(in.Backend, &out.Backend, c); err != nil {
|
if err := deepCopy_v1alpha1_IngressRuleValue(in.IngressRuleValue, &out.IngressRuleValue, c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deepCopy_v1alpha1_IngressRule(in IngressRule, out *IngressRule, c *conversion.Cloner) error {
|
func deepCopy_v1alpha1_IngressRuleValue(in IngressRuleValue, out *IngressRuleValue, c *conversion.Cloner) error {
|
||||||
out.Host = in.Host
|
if in.HTTP != nil {
|
||||||
if in.Paths != nil {
|
out.HTTP = new(HTTPIngressRuleValue)
|
||||||
out.Paths = make([]IngressPath, len(in.Paths))
|
if err := deepCopy_v1alpha1_HTTPIngressRuleValue(*in.HTTP, out.HTTP, c); err != nil {
|
||||||
for i := range in.Paths {
|
return err
|
||||||
if err := deepCopy_v1alpha1_IngressPath(in.Paths[i], &out.Paths[i], c); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
out.Paths = nil
|
out.HTTP = nil
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func deepCopy_v1alpha1_IngressSpec(in IngressSpec, out *IngressSpec, c *conversion.Cloner) error {
|
func deepCopy_v1alpha1_IngressSpec(in IngressSpec, out *IngressSpec, c *conversion.Cloner) error {
|
||||||
|
if in.Backend != nil {
|
||||||
|
out.Backend = new(IngressBackend)
|
||||||
|
if err := deepCopy_v1alpha1_IngressBackend(*in.Backend, out.Backend, c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out.Backend = nil
|
||||||
|
}
|
||||||
if in.Rules != nil {
|
if in.Rules != nil {
|
||||||
out.Rules = make([]IngressRule, len(in.Rules))
|
out.Rules = make([]IngressRule, len(in.Rules))
|
||||||
for i := range in.Rules {
|
for i := range in.Rules {
|
||||||
@@ -1480,6 +1504,8 @@ func init() {
|
|||||||
deepCopy_v1alpha1_DeploymentSpec,
|
deepCopy_v1alpha1_DeploymentSpec,
|
||||||
deepCopy_v1alpha1_DeploymentStatus,
|
deepCopy_v1alpha1_DeploymentStatus,
|
||||||
deepCopy_v1alpha1_DeploymentStrategy,
|
deepCopy_v1alpha1_DeploymentStrategy,
|
||||||
|
deepCopy_v1alpha1_HTTPIngressPath,
|
||||||
|
deepCopy_v1alpha1_HTTPIngressRuleValue,
|
||||||
deepCopy_v1alpha1_HorizontalPodAutoscaler,
|
deepCopy_v1alpha1_HorizontalPodAutoscaler,
|
||||||
deepCopy_v1alpha1_HorizontalPodAutoscalerList,
|
deepCopy_v1alpha1_HorizontalPodAutoscalerList,
|
||||||
deepCopy_v1alpha1_HorizontalPodAutoscalerSpec,
|
deepCopy_v1alpha1_HorizontalPodAutoscalerSpec,
|
||||||
@@ -1487,8 +1513,8 @@ func init() {
|
|||||||
deepCopy_v1alpha1_Ingress,
|
deepCopy_v1alpha1_Ingress,
|
||||||
deepCopy_v1alpha1_IngressBackend,
|
deepCopy_v1alpha1_IngressBackend,
|
||||||
deepCopy_v1alpha1_IngressList,
|
deepCopy_v1alpha1_IngressList,
|
||||||
deepCopy_v1alpha1_IngressPath,
|
|
||||||
deepCopy_v1alpha1_IngressRule,
|
deepCopy_v1alpha1_IngressRule,
|
||||||
|
deepCopy_v1alpha1_IngressRuleValue,
|
||||||
deepCopy_v1alpha1_IngressSpec,
|
deepCopy_v1alpha1_IngressSpec,
|
||||||
deepCopy_v1alpha1_IngressStatus,
|
deepCopy_v1alpha1_IngressStatus,
|
||||||
deepCopy_v1alpha1_Job,
|
deepCopy_v1alpha1_Job,
|
||||||
|
@@ -473,9 +473,10 @@ type JobCondition struct {
|
|||||||
Message string `json:"message,omitempty"`
|
Message string `json:"message,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// An Ingress is a way to give services externally-reachable urls. Each Ingress is a
|
// Ingress is a collection of rules that allow inbound connections to reach the
|
||||||
// collection of rules that allow inbound connections to reach the endpoints defined by
|
// endpoints defined by a backend. An Ingress can be configured to give services
|
||||||
// a backend.
|
// externally-reachable urls, load balance traffic, terminate SSL, offer name
|
||||||
|
// based virtual hosting etc.
|
||||||
type Ingress struct {
|
type Ingress struct {
|
||||||
unversioned.TypeMeta `json:",inline"`
|
unversioned.TypeMeta `json:",inline"`
|
||||||
// Standard object's metadata.
|
// Standard object's metadata.
|
||||||
@@ -504,11 +505,13 @@ type IngressList struct {
|
|||||||
|
|
||||||
// IngressSpec describes the Ingress the user wishes to exist.
|
// IngressSpec describes the Ingress the user wishes to exist.
|
||||||
type IngressSpec struct {
|
type IngressSpec struct {
|
||||||
// TODO: Add the ability to specify load-balancer IP just like what Service has already done?
|
// A default backend capable of servicing requests that don't match any
|
||||||
// A list of rules used to configure the Ingress.
|
// IngressRule. It is optional to allow the loadbalancer controller or
|
||||||
// http://<host>:<port>/<path>?<searchpart> -> IngressBackend
|
// defaulting logic to specify a global default.
|
||||||
// Where parts of the url conform to RFC 1738.
|
Backend *IngressBackend `json:"backend,omitempty"`
|
||||||
|
// A list of host rules used to configure the Ingress.
|
||||||
Rules []IngressRule `json:"rules"`
|
Rules []IngressRule `json:"rules"`
|
||||||
|
// TODO: Add the ability to specify load-balancer IP through claims
|
||||||
}
|
}
|
||||||
|
|
||||||
// IngressStatus describe the current state of the Ingress.
|
// IngressStatus describe the current state of the Ingress.
|
||||||
@@ -517,35 +520,64 @@ type IngressStatus struct {
|
|||||||
LoadBalancer v1.LoadBalancerStatus `json:"loadBalancer,omitempty"`
|
LoadBalancer v1.LoadBalancerStatus `json:"loadBalancer,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// IngressRule represents the rules mapping the paths under a specified host to the related backend services.
|
// IngressRule represents the rules mapping the paths under a specified host to
|
||||||
|
// the related backend services.
|
||||||
type IngressRule struct {
|
type IngressRule struct {
|
||||||
// Host is the fully qualified domain name of a network host, or its IP
|
// Host is the fully qualified domain name of a network host, as defined
|
||||||
// address as a set of four decimal digit groups separated by ".".
|
// by RFC 3986. Note the following deviations from the "host" part of the
|
||||||
// Conforms to RFC 1738.
|
// URI as defined in the RFC:
|
||||||
|
// 1. IPs are not allowed. Currently an IngressRuleValue can only apply to the
|
||||||
|
// IP in the Spec of the parent Ingress.
|
||||||
|
// 2. The `:` delimiter is not respected because ports are not allowed.
|
||||||
|
// Currently the port of an Ingress is implicitly :80 for http and
|
||||||
|
// :443 for https.
|
||||||
|
// Both these may change in the future.
|
||||||
|
// Incoming requests are matched against the Host before the IngressRuleValue.
|
||||||
Host string `json:"host,omitempty"`
|
Host string `json:"host,omitempty"`
|
||||||
|
// IngressRuleValue represents a rule to route requests for this IngressRule.
|
||||||
|
IngressRuleValue `json:",inline"`
|
||||||
|
}
|
||||||
|
|
||||||
// Paths describe a list of load-balancer rules under the specified host.
|
// IngressRuleValue represents a rule to apply against incoming requests. If the
|
||||||
Paths []IngressPath `json:"paths"`
|
// rule is satisfied, the request is routed to the specified backend.
|
||||||
|
type IngressRuleValue struct {
|
||||||
|
//TODO:
|
||||||
|
// 1. Consider renaming this resource and the associated rules so they
|
||||||
|
// aren't tied to Ingress. They can be used to route intra-cluster traffic.
|
||||||
|
// 2. Consider adding fields for ingress-type specific global options
|
||||||
|
// usable by a loadbalancer, like http keep-alive.
|
||||||
|
|
||||||
|
// Currently mixing different types of rules in a single Ingress is
|
||||||
|
// disallowed, so exactly one of the following must be set.
|
||||||
|
HTTP *HTTPIngressRuleValue `json:"http"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTTPIngressRuleValue is a list of http selectors pointing to IngressBackends.
|
||||||
|
// In the example: http://<host>/<path>?<searchpart> -> IngressBackend where
|
||||||
|
// parts of the url correspond to RFC 3986, this resource will be used to
|
||||||
|
// to match against everything after the last '/' and before the first '?'
|
||||||
|
// or '#'.
|
||||||
|
type HTTPIngressRuleValue struct {
|
||||||
|
// A collection of paths that map requests to IngressBackends.
|
||||||
|
Paths []HTTPIngressPath `json:"paths"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// IngressPath associates a path regex with an IngressBackend.
|
// IngressPath associates a path regex with an IngressBackend.
|
||||||
// Incoming urls matching the Path are forwarded to the Backend.
|
// Incoming urls matching the Path are forwarded to the Backend.
|
||||||
type IngressPath struct {
|
type HTTPIngressPath struct {
|
||||||
// Path is a regex matched against the url of an incoming request.
|
// Path is a regex matched against the url of an incoming request.
|
||||||
Path string `json:"path,omitempty"`
|
Path string `json:"path,omitempty"`
|
||||||
|
|
||||||
// Define the referenced service endpoint which the traffic will be forwarded to.
|
// Define the referenced service endpoint which the traffic will be
|
||||||
|
// forwarded to.
|
||||||
Backend IngressBackend `json:"backend"`
|
Backend IngressBackend `json:"backend"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// IngressBackend describes all endpoints for a given Service, port and protocol.
|
// IngressBackend describes all endpoints for a given Service and port.
|
||||||
type IngressBackend struct {
|
type IngressBackend struct {
|
||||||
// Specifies the referenced service.
|
// Specifies the name of the referenced service.
|
||||||
ServiceRef v1.LocalObjectReference `json:"serviceRef"`
|
ServiceName string `json:"serviceName"`
|
||||||
|
|
||||||
// Specifies the port of the referenced service.
|
// Specifies the port of the referenced service.
|
||||||
ServicePort util.IntOrString `json:"servicePort,omitempty"`
|
ServicePort util.IntOrString `json:"servicePort"`
|
||||||
|
|
||||||
// Specifies the protocol of the referenced service.
|
|
||||||
Protocol v1.Protocol `json:"protocol,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
@@ -133,6 +133,25 @@ func (DeploymentStrategy) SwaggerDoc() map[string]string {
|
|||||||
return map_DeploymentStrategy
|
return map_DeploymentStrategy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var map_HTTPIngressPath = map[string]string{
|
||||||
|
"": "IngressPath associates a path regex with an IngressBackend. Incoming urls matching the Path are forwarded to the Backend.",
|
||||||
|
"path": "Path is a regex matched against the url of an incoming request.",
|
||||||
|
"backend": "Define the referenced service endpoint which the traffic will be forwarded to.",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (HTTPIngressPath) SwaggerDoc() map[string]string {
|
||||||
|
return map_HTTPIngressPath
|
||||||
|
}
|
||||||
|
|
||||||
|
var map_HTTPIngressRuleValue = map[string]string{
|
||||||
|
"": "HTTPIngressRuleValue is a list of http selectors pointing to IngressBackends. In the example: http://<host>/<path>?<searchpart> -> IngressBackend where parts of the url correspond to RFC 3986, this resource will be used to to match against everything after the last '/' and before the first '?' or '#'.",
|
||||||
|
"paths": "A collection of paths that map requests to IngressBackends.",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (HTTPIngressRuleValue) SwaggerDoc() map[string]string {
|
||||||
|
return map_HTTPIngressRuleValue
|
||||||
|
}
|
||||||
|
|
||||||
var map_HorizontalPodAutoscaler = map[string]string{
|
var map_HorizontalPodAutoscaler = map[string]string{
|
||||||
"": "HorizontalPodAutoscaler represents the configuration of a horizontal pod autoscaler.",
|
"": "HorizontalPodAutoscaler represents the configuration of a horizontal pod autoscaler.",
|
||||||
"metadata": "Standard object metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
|
"metadata": "Standard object metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
|
||||||
@@ -179,7 +198,7 @@ func (HorizontalPodAutoscalerStatus) SwaggerDoc() map[string]string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var map_Ingress = map[string]string{
|
var map_Ingress = map[string]string{
|
||||||
"": "An Ingress is a way to give services externally-reachable urls. Each Ingress is a collection of rules that allow inbound connections to reach the endpoints defined by a backend.",
|
"": "Ingress is a collection of rules that allow inbound connections to reach the endpoints defined by a backend. An Ingress can be configured to give services externally-reachable urls, load balance traffic, terminate SSL, offer name based virtual hosting etc.",
|
||||||
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
|
"metadata": "Standard object's metadata. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata",
|
||||||
"spec": "Spec is the desired state of the Ingress. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
|
"spec": "Spec is the desired state of the Ingress. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
|
||||||
"status": "Status is the current state of the Ingress. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
|
"status": "Status is the current state of the Ingress. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status",
|
||||||
@@ -190,10 +209,9 @@ func (Ingress) SwaggerDoc() map[string]string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var map_IngressBackend = map[string]string{
|
var map_IngressBackend = map[string]string{
|
||||||
"": "IngressBackend describes all endpoints for a given Service, port and protocol.",
|
"": "IngressBackend describes all endpoints for a given Service and port.",
|
||||||
"serviceRef": "Specifies the referenced service.",
|
"serviceName": "Specifies the name of the referenced service.",
|
||||||
"servicePort": "Specifies the port of the referenced service.",
|
"servicePort": "Specifies the port of the referenced service.",
|
||||||
"protocol": "Specifies the protocol of the referenced service.",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (IngressBackend) SwaggerDoc() map[string]string {
|
func (IngressBackend) SwaggerDoc() map[string]string {
|
||||||
@@ -210,29 +228,28 @@ func (IngressList) SwaggerDoc() map[string]string {
|
|||||||
return map_IngressList
|
return map_IngressList
|
||||||
}
|
}
|
||||||
|
|
||||||
var map_IngressPath = map[string]string{
|
|
||||||
"": "IngressPath associates a path regex with an IngressBackend. Incoming urls matching the Path are forwarded to the Backend.",
|
|
||||||
"path": "Path is a regex matched against the url of an incoming request.",
|
|
||||||
"backend": "Define the referenced service endpoint which the traffic will be forwarded to.",
|
|
||||||
}
|
|
||||||
|
|
||||||
func (IngressPath) SwaggerDoc() map[string]string {
|
|
||||||
return map_IngressPath
|
|
||||||
}
|
|
||||||
|
|
||||||
var map_IngressRule = map[string]string{
|
var map_IngressRule = map[string]string{
|
||||||
"": "IngressRule represents the rules mapping the paths under a specified host to the related backend services.",
|
"": "IngressRule represents the rules mapping the paths under a specified host to the related backend services.",
|
||||||
"host": "Host is the fully qualified domain name of a network host, or its IP address as a set of four decimal digit groups separated by \".\". Conforms to RFC 1738.",
|
"host": "Host is the fully qualified domain name of a network host, as defined by RFC 3986. Note the following deviations from the \"host\" part of the URI as defined in the RFC: 1. IPs are not allowed. Currently an IngressRuleValue can only apply to the\n\t IP in the Spec of the parent Ingress.\n2. The `:` delimiter is not respected because ports are not allowed.\n\t Currently the port of an Ingress is implicitly :80 for http and\n\t :443 for https.\nBoth these may change in the future. Incoming requests are matched against the Host before the IngressRuleValue.",
|
||||||
"paths": "Paths describe a list of load-balancer rules under the specified host.",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (IngressRule) SwaggerDoc() map[string]string {
|
func (IngressRule) SwaggerDoc() map[string]string {
|
||||||
return map_IngressRule
|
return map_IngressRule
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var map_IngressRuleValue = map[string]string{
|
||||||
|
"": "IngressRuleValue represents a rule to apply against incoming requests. If the rule is satisfied, the request is routed to the specified backend.",
|
||||||
|
"http": "Currently mixing different types of rules in a single Ingress is disallowed, so exactly one of the following must be set.",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (IngressRuleValue) SwaggerDoc() map[string]string {
|
||||||
|
return map_IngressRuleValue
|
||||||
|
}
|
||||||
|
|
||||||
var map_IngressSpec = map[string]string{
|
var map_IngressSpec = map[string]string{
|
||||||
"": "IngressSpec describes the Ingress the user wishes to exist.",
|
"": "IngressSpec describes the Ingress the user wishes to exist.",
|
||||||
"rules": "A list of rules used to configure the Ingress. http://<host>:<port>/<path>?<searchpart> -> IngressBackend Where parts of the url conform to RFC 1738.",
|
"backend": "A default backend capable of servicing requests that don't match any IngressRule. It is optional to allow the loadbalancer controller or defaulting logic to specify a global default.",
|
||||||
|
"rules": "A list of host rules used to configure the Ingress.",
|
||||||
}
|
}
|
||||||
|
|
||||||
func (IngressSpec) SwaggerDoc() map[string]string {
|
func (IngressSpec) SwaggerDoc() map[string]string {
|
||||||
|
@@ -17,7 +17,11 @@ limitations under the License.
|
|||||||
package validation
|
package validation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
apivalidation "k8s.io/kubernetes/pkg/api/validation"
|
apivalidation "k8s.io/kubernetes/pkg/api/validation"
|
||||||
@@ -27,10 +31,19 @@ import (
|
|||||||
errs "k8s.io/kubernetes/pkg/util/fielderrors"
|
errs "k8s.io/kubernetes/pkg/util/fielderrors"
|
||||||
"k8s.io/kubernetes/pkg/util/sets"
|
"k8s.io/kubernetes/pkg/util/sets"
|
||||||
"k8s.io/kubernetes/pkg/util/validation"
|
"k8s.io/kubernetes/pkg/util/validation"
|
||||||
|
utilvalidation "k8s.io/kubernetes/pkg/util/validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
const isNegativeErrorMsg string = `must be non-negative`
|
const isNegativeErrorMsg string = `must be non-negative`
|
||||||
|
|
||||||
|
// TODO: Expose from apivalidation instead of duplicating.
|
||||||
|
func intervalErrorMsg(lo, hi int) string {
|
||||||
|
return fmt.Sprintf(`must be greater than %d and less than %d`, lo, hi)
|
||||||
|
}
|
||||||
|
|
||||||
|
var portRangeErrorMsg string = intervalErrorMsg(0, 65536)
|
||||||
|
var portNameErrorMsg string = fmt.Sprintf(`must be an IANA_SVC_NAME (at most 15 characters, matching regex %s, it must contain at least one letter [a-z], and hyphens cannot be adjacent to other hyphens): e.g. "http"`, validation.IdentifierNoHyphensBeginEndFmt)
|
||||||
|
|
||||||
// ValidateHorizontalPodAutoscaler can be used to check whether the given autoscaler name is valid.
|
// ValidateHorizontalPodAutoscaler can be used to check whether the given autoscaler name is valid.
|
||||||
// Prefix indicates this name will be used as part of generation, in which case trailing dashes are allowed.
|
// Prefix indicates this name will be used as part of generation, in which case trailing dashes are allowed.
|
||||||
func ValidateHorizontalPodAutoscalerName(name string, prefix bool) (bool, string) {
|
func ValidateHorizontalPodAutoscalerName(name string, prefix bool) (bool, string) {
|
||||||
@@ -371,3 +384,120 @@ func ValidateJobStatusUpdate(oldStatus, status experimental.JobStatus) errs.Vali
|
|||||||
allErrs = append(allErrs, ValidateJobStatus(&status)...)
|
allErrs = append(allErrs, ValidateJobStatus(&status)...)
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidateIngress tests if required fields in the Ingress are set.
|
||||||
|
func ValidateIngress(ingress *experimental.Ingress) errs.ValidationErrorList {
|
||||||
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&ingress.ObjectMeta, true, ValidateIngressName).Prefix("metadata")...)
|
||||||
|
allErrs = append(allErrs, ValidateIngressSpec(&ingress.Spec).Prefix("spec")...)
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateIngressName validates that the given name can be used as an Ingress name.
|
||||||
|
func ValidateIngressName(name string, prefix bool) (bool, string) {
|
||||||
|
return apivalidation.NameIsDNSSubdomain(name, prefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateIngressSpec tests if required fields in the IngressSpec are set.
|
||||||
|
func ValidateIngressSpec(spec *experimental.IngressSpec) errs.ValidationErrorList {
|
||||||
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
// TODO: Is a default backend mandatory?
|
||||||
|
if spec.Backend != nil {
|
||||||
|
allErrs = append(allErrs, validateIngressBackend(spec.Backend).Prefix("backend")...)
|
||||||
|
} else if len(spec.Rules) == 0 {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldInvalid("rules", spec.Rules, "Either a default backend or a set of host rules are required for ingress."))
|
||||||
|
}
|
||||||
|
if len(spec.Rules) > 0 {
|
||||||
|
allErrs = append(allErrs, validateIngressRules(spec.Rules).Prefix("rules")...)
|
||||||
|
}
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateIngressUpdate tests if required fields in the Ingress are set.
|
||||||
|
func ValidateIngressUpdate(oldIngress, ingress *experimental.Ingress) errs.ValidationErrorList {
|
||||||
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&ingress.ObjectMeta, &oldIngress.ObjectMeta).Prefix("metadata")...)
|
||||||
|
allErrs = append(allErrs, ValidateIngressSpec(&ingress.Spec).Prefix("spec")...)
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateIngressRules(IngressRules []experimental.IngressRule) errs.ValidationErrorList {
|
||||||
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
if len(IngressRules) == 0 {
|
||||||
|
return append(allErrs, errs.NewFieldRequired("IngressRules"))
|
||||||
|
}
|
||||||
|
for _, ih := range IngressRules {
|
||||||
|
if len(ih.Host) > 0 {
|
||||||
|
// TODO: Ports and ips are allowed in the host part of a url
|
||||||
|
// according to RFC 3986, consider allowing them.
|
||||||
|
if valid, errMsg := apivalidation.NameIsDNSSubdomain(ih.Host, false); !valid {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldInvalid("host", ih.Host, errMsg))
|
||||||
|
}
|
||||||
|
if isIP := (net.ParseIP(ih.Host) != nil); isIP {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldInvalid("host", ih.Host, "Host must be a DNS name, not ip address"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
allErrs = append(allErrs, validateIngressRuleValue(&ih.IngressRuleValue).Prefix("ingressRule")...)
|
||||||
|
}
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateIngressRuleValue(ingressRule *experimental.IngressRuleValue) errs.ValidationErrorList {
|
||||||
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
if ingressRule.HTTP != nil {
|
||||||
|
allErrs = append(allErrs, validateHTTPIngressRuleValue(ingressRule.HTTP).Prefix("http")...)
|
||||||
|
}
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateHTTPIngressRuleValue(httpIngressRuleValue *experimental.HTTPIngressRuleValue) errs.ValidationErrorList {
|
||||||
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
if len(httpIngressRuleValue.Paths) == 0 {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldRequired("paths"))
|
||||||
|
}
|
||||||
|
for _, rule := range httpIngressRuleValue.Paths {
|
||||||
|
if len(rule.Path) > 0 {
|
||||||
|
if !strings.HasPrefix(rule.Path, "/") {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldInvalid("path", rule.Path, "path must begin with /"))
|
||||||
|
}
|
||||||
|
// TODO: More draconian path regex validation.
|
||||||
|
// Path must be a valid regex. This is the basic requirement.
|
||||||
|
// In addition to this any characters not allowed in a path per
|
||||||
|
// RFC 3986 section-3.3 cannot appear as a literal in the regex.
|
||||||
|
// Consider the example: http://host/valid?#bar, everything after
|
||||||
|
// the last '/' is a valid regex that matches valid#bar, which
|
||||||
|
// isn't a valid path, because the path terminates at the first ?
|
||||||
|
// or #. A more sophisticated form of validation would detect that
|
||||||
|
// the user is confusing url regexes with path regexes.
|
||||||
|
_, err := regexp.CompilePOSIX(rule.Path)
|
||||||
|
if err != nil {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldInvalid("path", rule.Path, "httpIngressRuleValue.path must be a valid regex."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
allErrs = append(allErrs, validateIngressBackend(&rule.Backend).Prefix("backend")...)
|
||||||
|
}
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
|
// validateIngressBackend tests if a given backend is valid.
|
||||||
|
func validateIngressBackend(backend *experimental.IngressBackend) errs.ValidationErrorList {
|
||||||
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
|
||||||
|
// All backends must reference a single local service by name, and a single service port by name or number.
|
||||||
|
if len(backend.ServiceName) == 0 {
|
||||||
|
return append(allErrs, errs.NewFieldRequired("serviceName"))
|
||||||
|
} else if ok, errMsg := apivalidation.ValidateServiceName(backend.ServiceName, false); !ok {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldInvalid("serviceName", backend.ServiceName, errMsg))
|
||||||
|
}
|
||||||
|
if backend.ServicePort.Kind == util.IntstrString {
|
||||||
|
if !utilvalidation.IsDNS1123Label(backend.ServicePort.StrVal) {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldInvalid("servicePort", backend.ServicePort.StrVal, apivalidation.DNS1123LabelErrorMsg))
|
||||||
|
}
|
||||||
|
if !utilvalidation.IsValidPortName(backend.ServicePort.StrVal) {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldInvalid("servicePort", backend.ServicePort.StrVal, portNameErrorMsg))
|
||||||
|
}
|
||||||
|
} else if !utilvalidation.IsValidPortNum(backend.ServicePort.IntVal) {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldInvalid("servicePort", backend.ServicePort, portRangeErrorMsg))
|
||||||
|
}
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
@@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package validation
|
package validation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -848,3 +849,104 @@ func TestValidateJob(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ingressRules map[string]string
|
||||||
|
|
||||||
|
func TestValidateIngress(t *testing.T) {
|
||||||
|
defaultBackend := experimental.IngressBackend{
|
||||||
|
ServiceName: "default-backend",
|
||||||
|
ServicePort: util.IntOrString{Kind: util.IntstrInt, IntVal: 80},
|
||||||
|
}
|
||||||
|
|
||||||
|
newValid := func() experimental.Ingress {
|
||||||
|
return experimental.Ingress{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Namespace: api.NamespaceDefault,
|
||||||
|
},
|
||||||
|
Spec: experimental.IngressSpec{
|
||||||
|
Backend: &experimental.IngressBackend{
|
||||||
|
ServiceName: "default-backend",
|
||||||
|
ServicePort: util.IntOrString{Kind: util.IntstrInt, IntVal: 80},
|
||||||
|
},
|
||||||
|
Rules: []experimental.IngressRule{
|
||||||
|
{
|
||||||
|
Host: "foo.bar.com",
|
||||||
|
IngressRuleValue: experimental.IngressRuleValue{
|
||||||
|
HTTP: &experimental.HTTPIngressRuleValue{
|
||||||
|
Paths: []experimental.HTTPIngressPath{
|
||||||
|
{
|
||||||
|
Path: "/foo",
|
||||||
|
Backend: defaultBackend,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Status: experimental.IngressStatus{
|
||||||
|
LoadBalancer: api.LoadBalancerStatus{
|
||||||
|
Ingress: []api.LoadBalancerIngress{
|
||||||
|
{IP: "127.0.0.1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
servicelessBackend := newValid()
|
||||||
|
servicelessBackend.Spec.Backend.ServiceName = ""
|
||||||
|
invalidNameBackend := newValid()
|
||||||
|
invalidNameBackend.Spec.Backend.ServiceName = "defaultBackend"
|
||||||
|
noPortBackend := newValid()
|
||||||
|
noPortBackend.Spec.Backend = &experimental.IngressBackend{ServiceName: defaultBackend.ServiceName}
|
||||||
|
noForwardSlashPath := newValid()
|
||||||
|
noForwardSlashPath.Spec.Rules[0].IngressRuleValue.HTTP.Paths = []experimental.HTTPIngressPath{
|
||||||
|
{
|
||||||
|
Path: "invalid",
|
||||||
|
Backend: defaultBackend,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
noPaths := newValid()
|
||||||
|
noPaths.Spec.Rules[0].IngressRuleValue.HTTP.Paths = []experimental.HTTPIngressPath{}
|
||||||
|
badHost := newValid()
|
||||||
|
badHost.Spec.Rules[0].Host = "foobar:80"
|
||||||
|
badRegexPath := newValid()
|
||||||
|
badPathExpr := "/invalid["
|
||||||
|
badRegexPath.Spec.Rules[0].IngressRuleValue.HTTP.Paths = []experimental.HTTPIngressPath{
|
||||||
|
{
|
||||||
|
Path: badPathExpr,
|
||||||
|
Backend: defaultBackend,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
badPathErr := fmt.Sprintf("spec.rules.ingressRule.http.path: invalid value '%v'",
|
||||||
|
badPathExpr)
|
||||||
|
hostIP := "127.0.0.1"
|
||||||
|
badHostIP := newValid()
|
||||||
|
badHostIP.Spec.Rules[0].Host = hostIP
|
||||||
|
badHostIPErr := fmt.Sprintf("spec.rules.host: invalid value '%v'", hostIP)
|
||||||
|
|
||||||
|
errorCases := map[string]experimental.Ingress{
|
||||||
|
"spec.backend.serviceName: required value": servicelessBackend,
|
||||||
|
"spec.backend.serviceName: invalid value": invalidNameBackend,
|
||||||
|
"spec.backend.servicePort: invalid value": noPortBackend,
|
||||||
|
"spec.rules.host: invalid value": badHost,
|
||||||
|
"spec.rules.ingressRule.http.paths: required value": noPaths,
|
||||||
|
"spec.rules.ingressRule.http.path: invalid value": noForwardSlashPath,
|
||||||
|
}
|
||||||
|
errorCases[badPathErr] = badRegexPath
|
||||||
|
errorCases[badHostIPErr] = badHostIP
|
||||||
|
|
||||||
|
for k, v := range errorCases {
|
||||||
|
errs := ValidateIngress(&v)
|
||||||
|
if len(errs) == 0 {
|
||||||
|
t.Errorf("expected failure for %s", k)
|
||||||
|
} else {
|
||||||
|
s := strings.Split(k, ":")
|
||||||
|
err := errs[0].(*errors.ValidationError)
|
||||||
|
if err.Field != s[0] || !strings.Contains(err.Error(), s[1]) {
|
||||||
|
t.Errorf("unexpected error: %v, expected: %s", errs[0], k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -37,6 +37,7 @@ type ExperimentalInterface interface {
|
|||||||
DaemonSetsNamespacer
|
DaemonSetsNamespacer
|
||||||
DeploymentsNamespacer
|
DeploymentsNamespacer
|
||||||
JobsNamespacer
|
JobsNamespacer
|
||||||
|
IngressNamespacer
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExperimentalClient is used to interact with experimental Kubernetes features.
|
// ExperimentalClient is used to interact with experimental Kubernetes features.
|
||||||
@@ -95,6 +96,10 @@ func (c *ExperimentalClient) Jobs(namespace string) JobInterface {
|
|||||||
return newJobs(c, namespace)
|
return newJobs(c, namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *ExperimentalClient) Ingress(namespace string) IngressInterface {
|
||||||
|
return newIngress(c, namespace)
|
||||||
|
}
|
||||||
|
|
||||||
// NewExperimental creates a new ExperimentalClient for the given config. This client
|
// NewExperimental creates a new ExperimentalClient for the given config. This client
|
||||||
// provides access to experimental Kubernetes features.
|
// provides access to experimental Kubernetes features.
|
||||||
// Experimental features are not supported and may be changed or removed in
|
// Experimental features are not supported and may be changed or removed in
|
||||||
|
112
pkg/client/unversioned/ingress.go
Normal file
112
pkg/client/unversioned/ingress.go
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package unversioned
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/experimental"
|
||||||
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
|
"k8s.io/kubernetes/pkg/watch"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IngressNamespacer has methods to work with Ingress resources in a namespace
|
||||||
|
type IngressNamespacer interface {
|
||||||
|
Ingress(namespace string) IngressInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
// IngressInterface exposes methods to work on Ingress resources.
|
||||||
|
type IngressInterface interface {
|
||||||
|
List(label labels.Selector, field fields.Selector) (*experimental.IngressList, error)
|
||||||
|
Get(name string) (*experimental.Ingress, error)
|
||||||
|
Create(ingress *experimental.Ingress) (*experimental.Ingress, error)
|
||||||
|
Update(ingress *experimental.Ingress) (*experimental.Ingress, error)
|
||||||
|
Delete(name string, options *api.DeleteOptions) error
|
||||||
|
Watch(label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error)
|
||||||
|
UpdateStatus(ingress *experimental.Ingress) (*experimental.Ingress, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ingress implements IngressNamespacer interface
|
||||||
|
type ingress struct {
|
||||||
|
r *ExperimentalClient
|
||||||
|
ns string
|
||||||
|
}
|
||||||
|
|
||||||
|
// newIngress returns a ingress
|
||||||
|
func newIngress(c *ExperimentalClient, namespace string) *ingress {
|
||||||
|
return &ingress{c, namespace}
|
||||||
|
}
|
||||||
|
|
||||||
|
// List returns a list of ingress that match the label and field selectors.
|
||||||
|
func (c *ingress) List(label labels.Selector, field fields.Selector) (result *experimental.IngressList, err error) {
|
||||||
|
result = &experimental.IngressList{}
|
||||||
|
err = c.r.Get().Namespace(c.ns).Resource("ingress").LabelsSelectorParam(label).FieldsSelectorParam(field).Do().Into(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns information about a particular ingress.
|
||||||
|
func (c *ingress) Get(name string) (result *experimental.Ingress, err error) {
|
||||||
|
result = &experimental.Ingress{}
|
||||||
|
err = c.r.Get().Namespace(c.ns).Resource("ingress").Name(name).Do().Into(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create creates a new ingress.
|
||||||
|
func (c *ingress) Create(ingress *experimental.Ingress) (result *experimental.Ingress, err error) {
|
||||||
|
result = &experimental.Ingress{}
|
||||||
|
err = c.r.Post().Namespace(c.ns).Resource("ingress").Body(ingress).Do().Into(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update updates an existing ingress.
|
||||||
|
func (c *ingress) Update(ingress *experimental.Ingress) (result *experimental.Ingress, err error) {
|
||||||
|
result = &experimental.Ingress{}
|
||||||
|
err = c.r.Put().Namespace(c.ns).Resource("ingress").Name(ingress.Name).Body(ingress).Do().Into(result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete deletes a ingress, returns error if one occurs.
|
||||||
|
func (c *ingress) Delete(name string, options *api.DeleteOptions) (err error) {
|
||||||
|
if options == nil {
|
||||||
|
return c.r.Delete().Namespace(c.ns).Resource("ingress").Name(name).Do().Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := api.Scheme.EncodeToVersion(options, c.r.APIVersion())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return c.r.Delete().Namespace(c.ns).Resource("ingress").Name(name).Body(body).Do().Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch returns a watch.Interface that watches the requested ingress.
|
||||||
|
func (c *ingress) Watch(label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) {
|
||||||
|
return c.r.Get().
|
||||||
|
Prefix("watch").
|
||||||
|
Namespace(c.ns).
|
||||||
|
Resource("ingress").
|
||||||
|
Param("resourceVersion", resourceVersion).
|
||||||
|
LabelsSelectorParam(label).
|
||||||
|
FieldsSelectorParam(field).
|
||||||
|
Watch()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateStatus takes the name of the ingress and the new status. Returns the server's representation of the ingress, and an error, if it occurs.
|
||||||
|
func (c *ingress) UpdateStatus(ingress *experimental.Ingress) (result *experimental.Ingress, err error) {
|
||||||
|
result = &experimental.Ingress{}
|
||||||
|
err = c.r.Put().Namespace(c.ns).Resource("ingress").Name(ingress.Name).SubResource("status").Body(ingress).Do().Into(result)
|
||||||
|
return
|
||||||
|
}
|
230
pkg/client/unversioned/ingress_test.go
Normal file
230
pkg/client/unversioned/ingress_test.go
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package unversioned
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/api/testapi"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/experimental"
|
||||||
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getIngressResourceName() string {
|
||||||
|
return "ingress"
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListIngress(t *testing.T) {
|
||||||
|
ns := api.NamespaceAll
|
||||||
|
c := &testClient{
|
||||||
|
Request: testRequest{
|
||||||
|
Method: "GET",
|
||||||
|
Path: testapi.Experimental.ResourcePath(getIngressResourceName(), ns, ""),
|
||||||
|
},
|
||||||
|
Response: Response{StatusCode: 200,
|
||||||
|
Body: &experimental.IngressList{
|
||||||
|
Items: []experimental.Ingress{
|
||||||
|
{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"name": "baz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: experimental.IngressSpec{
|
||||||
|
Rules: []experimental.IngressRule{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
receivedIngressList, err := c.Setup(t).Experimental().Ingress(ns).List(labels.Everything(), fields.Everything())
|
||||||
|
c.Validate(t, receivedIngressList, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetIngress(t *testing.T) {
|
||||||
|
ns := api.NamespaceDefault
|
||||||
|
c := &testClient{
|
||||||
|
Request: testRequest{
|
||||||
|
Method: "GET",
|
||||||
|
Path: testapi.Experimental.ResourcePath(getIngressResourceName(), ns, "foo"),
|
||||||
|
Query: buildQueryValues(nil),
|
||||||
|
},
|
||||||
|
Response: Response{
|
||||||
|
StatusCode: 200,
|
||||||
|
Body: &experimental.Ingress{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"name": "baz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: experimental.IngressSpec{
|
||||||
|
Rules: []experimental.IngressRule{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
receivedIngress, err := c.Setup(t).Experimental().Ingress(ns).Get("foo")
|
||||||
|
c.Validate(t, receivedIngress, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetIngressWithNoName(t *testing.T) {
|
||||||
|
ns := api.NamespaceDefault
|
||||||
|
c := &testClient{Error: true}
|
||||||
|
receivedIngress, err := c.Setup(t).Experimental().Ingress(ns).Get("")
|
||||||
|
if (err != nil) && (err.Error() != nameRequiredError) {
|
||||||
|
t.Errorf("Expected error: %v, but got %v", nameRequiredError, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Validate(t, receivedIngress, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateIngress(t *testing.T) {
|
||||||
|
ns := api.NamespaceDefault
|
||||||
|
requestIngress := &experimental.Ingress{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Namespace: ns,
|
||||||
|
ResourceVersion: "1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
c := &testClient{
|
||||||
|
Request: testRequest{
|
||||||
|
Method: "PUT",
|
||||||
|
Path: testapi.Experimental.ResourcePath(getIngressResourceName(), ns, "foo"),
|
||||||
|
Query: buildQueryValues(nil),
|
||||||
|
},
|
||||||
|
Response: Response{
|
||||||
|
StatusCode: 200,
|
||||||
|
Body: &experimental.Ingress{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"name": "baz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: experimental.IngressSpec{
|
||||||
|
Rules: []experimental.IngressRule{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
receivedIngress, err := c.Setup(t).Experimental().Ingress(ns).Update(requestIngress)
|
||||||
|
c.Validate(t, receivedIngress, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateIngressStatus(t *testing.T) {
|
||||||
|
ns := api.NamespaceDefault
|
||||||
|
lbStatus := api.LoadBalancerStatus{
|
||||||
|
Ingress: []api.LoadBalancerIngress{
|
||||||
|
{IP: "127.0.0.1"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
requestIngress := &experimental.Ingress{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Namespace: ns,
|
||||||
|
ResourceVersion: "1",
|
||||||
|
},
|
||||||
|
Status: experimental.IngressStatus{
|
||||||
|
LoadBalancer: lbStatus,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
c := &testClient{
|
||||||
|
Request: testRequest{
|
||||||
|
Method: "PUT",
|
||||||
|
Path: testapi.Experimental.ResourcePath(getIngressResourceName(), ns, "foo") + "/status",
|
||||||
|
Query: buildQueryValues(nil),
|
||||||
|
},
|
||||||
|
Response: Response{
|
||||||
|
StatusCode: 200,
|
||||||
|
Body: &experimental.Ingress{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"name": "baz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: experimental.IngressSpec{
|
||||||
|
Rules: []experimental.IngressRule{},
|
||||||
|
},
|
||||||
|
Status: experimental.IngressStatus{
|
||||||
|
LoadBalancer: lbStatus,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
receivedIngress, err := c.Setup(t).Experimental().Ingress(ns).UpdateStatus(requestIngress)
|
||||||
|
c.Validate(t, receivedIngress, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeleteIngress(t *testing.T) {
|
||||||
|
ns := api.NamespaceDefault
|
||||||
|
c := &testClient{
|
||||||
|
Request: testRequest{
|
||||||
|
Method: "DELETE",
|
||||||
|
Path: testapi.Experimental.ResourcePath(getIngressResourceName(), ns, "foo"),
|
||||||
|
Query: buildQueryValues(nil),
|
||||||
|
},
|
||||||
|
Response: Response{StatusCode: 200},
|
||||||
|
}
|
||||||
|
err := c.Setup(t).Experimental().Ingress(ns).Delete("foo", nil)
|
||||||
|
c.Validate(t, nil, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateIngress(t *testing.T) {
|
||||||
|
ns := api.NamespaceDefault
|
||||||
|
requestIngress := &experimental.Ingress{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Namespace: ns,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
c := &testClient{
|
||||||
|
Request: testRequest{
|
||||||
|
Method: "POST",
|
||||||
|
Path: testapi.Experimental.ResourcePath(getIngressResourceName(), ns, ""),
|
||||||
|
Body: requestIngress,
|
||||||
|
Query: buildQueryValues(nil),
|
||||||
|
},
|
||||||
|
Response: Response{
|
||||||
|
StatusCode: 200,
|
||||||
|
Body: &experimental.Ingress{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: "foo",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
"name": "baz",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: experimental.IngressSpec{
|
||||||
|
Rules: []experimental.IngressRule{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
receivedIngress, err := c.Setup(t).Experimental().Ingress(ns).Create(requestIngress)
|
||||||
|
c.Validate(t, receivedIngress, err)
|
||||||
|
}
|
86
pkg/client/unversioned/testclient/fake_ingress.go
Normal file
86
pkg/client/unversioned/testclient/fake_ingress.go
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package testclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/experimental"
|
||||||
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
|
"k8s.io/kubernetes/pkg/watch"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FakeIngress implements IngressInterface. Meant to be embedded into a struct to get a default
|
||||||
|
// implementation. This makes faking out just the method you want to test easier.
|
||||||
|
type FakeIngress struct {
|
||||||
|
Fake *FakeExperimental
|
||||||
|
Namespace string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeIngress) Get(name string) (*experimental.Ingress, error) {
|
||||||
|
obj, err := c.Fake.Invokes(NewGetAction("ingress", c.Namespace, name), &experimental.Ingress{})
|
||||||
|
if obj == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj.(*experimental.Ingress), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeIngress) List(label labels.Selector, fields fields.Selector) (*experimental.IngressList, error) {
|
||||||
|
obj, err := c.Fake.Invokes(NewListAction("ingress", c.Namespace, label, nil), &experimental.IngressList{})
|
||||||
|
if obj == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj.(*experimental.IngressList), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeIngress) Create(ingress *experimental.Ingress) (*experimental.Ingress, error) {
|
||||||
|
obj, err := c.Fake.Invokes(NewCreateAction("ingress", c.Namespace, ingress), ingress)
|
||||||
|
if obj == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj.(*experimental.Ingress), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeIngress) Update(ingress *experimental.Ingress) (*experimental.Ingress, error) {
|
||||||
|
obj, err := c.Fake.Invokes(NewUpdateAction("ingress", c.Namespace, ingress), ingress)
|
||||||
|
if obj == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj.(*experimental.Ingress), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeIngress) Delete(name string, options *api.DeleteOptions) error {
|
||||||
|
_, err := c.Fake.Invokes(NewDeleteAction("ingress", c.Namespace, name), &experimental.Ingress{})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeIngress) Watch(label labels.Selector, field fields.Selector, resourceVersion string) (watch.Interface, error) {
|
||||||
|
return c.Fake.InvokesWatch(NewWatchAction("ingress", c.Namespace, label, field, resourceVersion))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeIngress) UpdateStatus(ingress *experimental.Ingress) (result *experimental.Ingress, err error) {
|
||||||
|
obj, err := c.Fake.Invokes(NewUpdateSubresourceAction("ingress", "status", c.Namespace, ingress), ingress)
|
||||||
|
if obj == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj.(*experimental.Ingress), err
|
||||||
|
}
|
@@ -327,3 +327,7 @@ func (c *FakeExperimental) Scales(namespace string) client.ScaleInterface {
|
|||||||
func (c *FakeExperimental) Jobs(namespace string) client.JobInterface {
|
func (c *FakeExperimental) Jobs(namespace string) client.JobInterface {
|
||||||
return &FakeJobs{Fake: c, Namespace: namespace}
|
return &FakeJobs{Fake: c, Namespace: namespace}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *FakeExperimental) Ingress(namespace string) client.IngressInterface {
|
||||||
|
return &FakeIngress{Fake: c, Namespace: namespace}
|
||||||
|
}
|
||||||
|
@@ -209,6 +209,10 @@ func deleteAllContent(kubeClient client.Interface, experimentalMode bool, namesp
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return estimate, err
|
return estimate, err
|
||||||
}
|
}
|
||||||
|
err = deleteIngress(kubeClient.Experimental(), namespace)
|
||||||
|
if err != nil {
|
||||||
|
return estimate, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return estimate, nil
|
return estimate, nil
|
||||||
}
|
}
|
||||||
@@ -496,3 +500,17 @@ func deleteDeployments(expClient client.ExperimentalInterface, ns string) error
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func deleteIngress(expClient client.ExperimentalInterface, ns string) error {
|
||||||
|
items, err := expClient.Ingress(ns).List(labels.Everything(), fields.Everything())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i := range items.Items {
|
||||||
|
err := expClient.Ingress(ns).Delete(items.Items[i].Name, nil)
|
||||||
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@@ -114,6 +114,7 @@ func testSyncNamespaceThatIsTerminating(t *testing.T, experimentalMode bool) {
|
|||||||
strings.Join([]string{"list", "daemonsets", ""}, "-"),
|
strings.Join([]string{"list", "daemonsets", ""}, "-"),
|
||||||
strings.Join([]string{"list", "deployments", ""}, "-"),
|
strings.Join([]string{"list", "deployments", ""}, "-"),
|
||||||
strings.Join([]string{"list", "jobs", ""}, "-"),
|
strings.Join([]string{"list", "jobs", ""}, "-"),
|
||||||
|
strings.Join([]string{"list", "ingress", ""}, "-"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -102,6 +102,7 @@ func expandResourceShortcut(resource string) string {
|
|||||||
"rc": "replicationcontrollers",
|
"rc": "replicationcontrollers",
|
||||||
"ds": "daemonsets",
|
"ds": "daemonsets",
|
||||||
"svc": "services",
|
"svc": "services",
|
||||||
|
"ing": "ingress",
|
||||||
}
|
}
|
||||||
if expanded, ok := shortForms[resource]; ok {
|
if expanded, ok := shortForms[resource]; ok {
|
||||||
return expanded
|
return expanded
|
||||||
|
@@ -45,6 +45,14 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/util/sets"
|
"k8s.io/kubernetes/pkg/util/sets"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
tabwriterMinWidth = 10
|
||||||
|
tabwriterWidth = 4
|
||||||
|
tabwriterPadding = 3
|
||||||
|
tabwriterPadChar = ' '
|
||||||
|
tabwriterFlags = 0
|
||||||
|
)
|
||||||
|
|
||||||
// GetPrinter takes a format type, an optional format argument. It will return true
|
// GetPrinter takes a format type, an optional format argument. It will return true
|
||||||
// if the format is generic (untyped), otherwise it will return false. The printer
|
// if the format is generic (untyped), otherwise it will return false. The printer
|
||||||
// is agnostic to schema versions, so you must send arguments to PrintObj in the
|
// is agnostic to schema versions, so you must send arguments to PrintObj in the
|
||||||
@@ -382,6 +390,7 @@ var podTemplateColumns = []string{"TEMPLATE", "CONTAINER(S)", "IMAGE(S)", "PODLA
|
|||||||
var replicationControllerColumns = []string{"CONTROLLER", "CONTAINER(S)", "IMAGE(S)", "SELECTOR", "REPLICAS", "AGE"}
|
var replicationControllerColumns = []string{"CONTROLLER", "CONTAINER(S)", "IMAGE(S)", "SELECTOR", "REPLICAS", "AGE"}
|
||||||
var jobColumns = []string{"JOB", "CONTAINER(S)", "IMAGE(S)", "SELECTOR", "SUCCESSFUL"}
|
var jobColumns = []string{"JOB", "CONTAINER(S)", "IMAGE(S)", "SELECTOR", "SUCCESSFUL"}
|
||||||
var serviceColumns = []string{"NAME", "CLUSTER_IP", "EXTERNAL_IP", "PORT(S)", "SELECTOR", "AGE"}
|
var serviceColumns = []string{"NAME", "CLUSTER_IP", "EXTERNAL_IP", "PORT(S)", "SELECTOR", "AGE"}
|
||||||
|
var ingressColumns = []string{"NAME", "RULE", "BACKEND", "ADDRESS"}
|
||||||
var endpointColumns = []string{"NAME", "ENDPOINTS", "AGE"}
|
var endpointColumns = []string{"NAME", "ENDPOINTS", "AGE"}
|
||||||
var nodeColumns = []string{"NAME", "LABELS", "STATUS", "AGE"}
|
var nodeColumns = []string{"NAME", "LABELS", "STATUS", "AGE"}
|
||||||
var daemonSetColumns = []string{"NAME", "CONTAINER(S)", "IMAGE(S)", "SELECTOR", "NODE-SELECTOR"}
|
var daemonSetColumns = []string{"NAME", "CONTAINER(S)", "IMAGE(S)", "SELECTOR", "NODE-SELECTOR"}
|
||||||
@@ -413,6 +422,8 @@ func (h *HumanReadablePrinter) addDefaultHandlers() {
|
|||||||
h.Handler(jobColumns, printJobList)
|
h.Handler(jobColumns, printJobList)
|
||||||
h.Handler(serviceColumns, printService)
|
h.Handler(serviceColumns, printService)
|
||||||
h.Handler(serviceColumns, printServiceList)
|
h.Handler(serviceColumns, printServiceList)
|
||||||
|
h.Handler(ingressColumns, printIngress)
|
||||||
|
h.Handler(ingressColumns, printIngressList)
|
||||||
h.Handler(endpointColumns, printEndpoints)
|
h.Handler(endpointColumns, printEndpoints)
|
||||||
h.Handler(endpointColumns, printEndpointsList)
|
h.Handler(endpointColumns, printEndpointsList)
|
||||||
h.Handler(nodeColumns, printNode)
|
h.Handler(nodeColumns, printNode)
|
||||||
@@ -739,6 +750,18 @@ func printJobList(list *experimental.JobList, w io.Writer, withNamespace bool, w
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// loadBalancerStatusStringer behaves just like a string interface and converts the given status to a string.
|
||||||
|
func loadBalancerStatusStringer(s api.LoadBalancerStatus) string {
|
||||||
|
ingress := s.Ingress
|
||||||
|
result := []string{}
|
||||||
|
for i := range ingress {
|
||||||
|
if ingress[i].IP != "" {
|
||||||
|
result = append(result, ingress[i].IP)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Join(result, ",")
|
||||||
|
}
|
||||||
|
|
||||||
func getServiceExternalIP(svc *api.Service) string {
|
func getServiceExternalIP(svc *api.Service) string {
|
||||||
switch svc.Spec.Type {
|
switch svc.Spec.Type {
|
||||||
case api.ServiceTypeClusterIP:
|
case api.ServiceTypeClusterIP:
|
||||||
@@ -752,17 +775,12 @@ func getServiceExternalIP(svc *api.Service) string {
|
|||||||
}
|
}
|
||||||
return "nodes"
|
return "nodes"
|
||||||
case api.ServiceTypeLoadBalancer:
|
case api.ServiceTypeLoadBalancer:
|
||||||
ingress := svc.Status.LoadBalancer.Ingress
|
lbIps := loadBalancerStatusStringer(svc.Status.LoadBalancer)
|
||||||
result := []string{}
|
|
||||||
for i := range ingress {
|
|
||||||
if ingress[i].IP != "" {
|
|
||||||
result = append(result, ingress[i].IP)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(svc.Spec.ExternalIPs) > 0 {
|
if len(svc.Spec.ExternalIPs) > 0 {
|
||||||
result = append(result, svc.Spec.ExternalIPs...)
|
result := append(strings.Split(lbIps, ","), svc.Spec.ExternalIPs...)
|
||||||
|
return strings.Join(result, ",")
|
||||||
}
|
}
|
||||||
return strings.Join(result, ",")
|
return lbIps
|
||||||
}
|
}
|
||||||
return "unknown"
|
return "unknown"
|
||||||
}
|
}
|
||||||
@@ -813,6 +831,71 @@ func printServiceList(list *api.ServiceList, w io.Writer, withNamespace bool, wi
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// backendStringer behaves just like a string interface and converts the given backend to a string.
|
||||||
|
func backendStringer(backend *experimental.IngressBackend) string {
|
||||||
|
if backend == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%v:%v", backend.ServiceName, backend.ServicePort.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func printIngress(ingress *experimental.Ingress, w io.Writer, withNamespace, wide bool, showAll bool, columnLabels []string) error {
|
||||||
|
name := ingress.Name
|
||||||
|
namespace := ingress.Namespace
|
||||||
|
|
||||||
|
hostRules := ingress.Spec.Rules
|
||||||
|
if withNamespace {
|
||||||
|
if _, err := fmt.Fprintf(w, "%s\t", namespace); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := fmt.Fprintf(w, "%s\t%v\t%v\t%v\n",
|
||||||
|
name,
|
||||||
|
"-",
|
||||||
|
backendStringer(ingress.Spec.Backend),
|
||||||
|
loadBalancerStatusStringer(ingress.Status.LoadBalancer)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lay out all the rules on separate lines.
|
||||||
|
extraLinePrefix := ""
|
||||||
|
if withNamespace {
|
||||||
|
extraLinePrefix = "\t"
|
||||||
|
}
|
||||||
|
for _, rules := range hostRules {
|
||||||
|
if rules.HTTP == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_, err := fmt.Fprintf(w, "%s\t%v\t", extraLinePrefix, rules.Host)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := fmt.Fprint(w, appendLabelTabs(columnLabels)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, rule := range rules.HTTP.Paths {
|
||||||
|
_, err := fmt.Fprintf(w, "%s\t%v\t%v", extraLinePrefix, rule.Path, backendStringer(&rule.Backend))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := fmt.Fprint(w, appendLabelTabs(columnLabels)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func printIngressList(ingressList *experimental.IngressList, w io.Writer, withNamespace, wide bool, showAll bool, columnLabels []string) error {
|
||||||
|
for _, ingress := range ingressList.Items {
|
||||||
|
if err := printIngress(&ingress, w, withNamespace, wide, true, columnLabels); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func printDaemonSet(ds *experimental.DaemonSet, w io.Writer, withNamespace bool, wide bool, showAll bool, columnLabels []string) error {
|
func printDaemonSet(ds *experimental.DaemonSet, w io.Writer, withNamespace bool, wide bool, showAll bool, columnLabels []string) error {
|
||||||
name := ds.Name
|
name := ds.Name
|
||||||
namespace := ds.Namespace
|
namespace := ds.Namespace
|
||||||
@@ -1369,7 +1452,7 @@ func formatWideHeaders(wide bool, t reflect.Type) []string {
|
|||||||
|
|
||||||
// PrintObj prints the obj in a human-friendly format according to the type of the obj.
|
// PrintObj prints the obj in a human-friendly format according to the type of the obj.
|
||||||
func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) error {
|
func (h *HumanReadablePrinter) PrintObj(obj runtime.Object, output io.Writer) error {
|
||||||
w := tabwriter.NewWriter(output, 10, 4, 3, ' ', 0)
|
w := tabwriter.NewWriter(output, tabwriterMinWidth, tabwriterWidth, tabwriterPadding, tabwriterPadChar, tabwriterFlags)
|
||||||
defer w.Flush()
|
defer w.Flush()
|
||||||
t := reflect.TypeOf(obj)
|
t := reflect.TypeOf(obj)
|
||||||
if handler := h.handlerMap[t]; handler != nil {
|
if handler := h.handlerMap[t]; handler != nil {
|
||||||
|
@@ -55,6 +55,7 @@ import (
|
|||||||
endpointsetcd "k8s.io/kubernetes/pkg/registry/endpoint/etcd"
|
endpointsetcd "k8s.io/kubernetes/pkg/registry/endpoint/etcd"
|
||||||
eventetcd "k8s.io/kubernetes/pkg/registry/event/etcd"
|
eventetcd "k8s.io/kubernetes/pkg/registry/event/etcd"
|
||||||
expcontrolleretcd "k8s.io/kubernetes/pkg/registry/experimental/controller/etcd"
|
expcontrolleretcd "k8s.io/kubernetes/pkg/registry/experimental/controller/etcd"
|
||||||
|
ingressetcd "k8s.io/kubernetes/pkg/registry/ingress/etcd"
|
||||||
jobetcd "k8s.io/kubernetes/pkg/registry/job/etcd"
|
jobetcd "k8s.io/kubernetes/pkg/registry/job/etcd"
|
||||||
limitrangeetcd "k8s.io/kubernetes/pkg/registry/limitrange/etcd"
|
limitrangeetcd "k8s.io/kubernetes/pkg/registry/limitrange/etcd"
|
||||||
"k8s.io/kubernetes/pkg/registry/namespace"
|
"k8s.io/kubernetes/pkg/registry/namespace"
|
||||||
@@ -967,6 +968,7 @@ func (m *Master) experimental(c *Config) *apiserver.APIGroupVersion {
|
|||||||
daemonSetStorage, daemonSetStatusStorage := daemonetcd.NewREST(c.ExpDatabaseStorage)
|
daemonSetStorage, daemonSetStatusStorage := daemonetcd.NewREST(c.ExpDatabaseStorage)
|
||||||
deploymentStorage := deploymentetcd.NewStorage(c.ExpDatabaseStorage)
|
deploymentStorage := deploymentetcd.NewStorage(c.ExpDatabaseStorage)
|
||||||
jobStorage, jobStatusStorage := jobetcd.NewREST(c.ExpDatabaseStorage)
|
jobStorage, jobStatusStorage := jobetcd.NewREST(c.ExpDatabaseStorage)
|
||||||
|
ingressStorage := ingressetcd.NewREST(c.ExpDatabaseStorage)
|
||||||
|
|
||||||
thirdPartyControl := ThirdPartyController{
|
thirdPartyControl := ThirdPartyController{
|
||||||
master: m,
|
master: m,
|
||||||
@@ -990,6 +992,7 @@ func (m *Master) experimental(c *Config) *apiserver.APIGroupVersion {
|
|||||||
strings.ToLower("deployments/scale"): deploymentStorage.Scale,
|
strings.ToLower("deployments/scale"): deploymentStorage.Scale,
|
||||||
strings.ToLower("jobs"): jobStorage,
|
strings.ToLower("jobs"): jobStorage,
|
||||||
strings.ToLower("jobs/status"): jobStatusStorage,
|
strings.ToLower("jobs/status"): jobStatusStorage,
|
||||||
|
strings.ToLower("ingress"): ingressStorage,
|
||||||
}
|
}
|
||||||
|
|
||||||
expMeta := latest.GroupOrDie("experimental")
|
expMeta := latest.GroupOrDie("experimental")
|
||||||
|
17
pkg/registry/ingress/doc.go
Normal file
17
pkg/registry/ingress/doc.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ingress
|
77
pkg/registry/ingress/etcd/etcd.go
Normal file
77
pkg/registry/ingress/etcd/etcd.go
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package etcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/experimental"
|
||||||
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
|
"k8s.io/kubernetes/pkg/registry/generic"
|
||||||
|
etcdgeneric "k8s.io/kubernetes/pkg/registry/generic/etcd"
|
||||||
|
ingress "k8s.io/kubernetes/pkg/registry/ingress"
|
||||||
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
|
"k8s.io/kubernetes/pkg/storage"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
IngressPath string = "/ingress"
|
||||||
|
)
|
||||||
|
|
||||||
|
// rest implements a RESTStorage for replication controllers against etcd
|
||||||
|
type REST struct {
|
||||||
|
*etcdgeneric.Etcd
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewREST returns a RESTStorage object that will work against replication controllers.
|
||||||
|
func NewREST(s storage.Interface) *REST {
|
||||||
|
store := &etcdgeneric.Etcd{
|
||||||
|
NewFunc: func() runtime.Object { return &experimental.Ingress{} },
|
||||||
|
|
||||||
|
// NewListFunc returns an object capable of storing results of an etcd list.
|
||||||
|
NewListFunc: func() runtime.Object { return &experimental.IngressList{} },
|
||||||
|
// Produces a ingress that etcd understands, to the root of the resource
|
||||||
|
// by combining the namespace in the context with the given prefix
|
||||||
|
KeyRootFunc: func(ctx api.Context) string {
|
||||||
|
return etcdgeneric.NamespaceKeyRootFunc(ctx, IngressPath)
|
||||||
|
},
|
||||||
|
// Produces a ingress that etcd understands, to the resource by combining
|
||||||
|
// the namespace in the context with the given prefix
|
||||||
|
KeyFunc: func(ctx api.Context, name string) (string, error) {
|
||||||
|
return etcdgeneric.NamespaceKeyFunc(ctx, IngressPath, name)
|
||||||
|
},
|
||||||
|
// Retrieve the name field of a replication controller
|
||||||
|
ObjectNameFunc: func(obj runtime.Object) (string, error) {
|
||||||
|
return obj.(*experimental.Ingress).Name, nil
|
||||||
|
},
|
||||||
|
// Used to match objects based on labels/fields for list and watch
|
||||||
|
PredicateFunc: func(label labels.Selector, field fields.Selector) generic.Matcher {
|
||||||
|
return ingress.MatchIngress(label, field)
|
||||||
|
},
|
||||||
|
EndpointName: "ingress",
|
||||||
|
|
||||||
|
// Used to validate controller creation
|
||||||
|
CreateStrategy: ingress.Strategy,
|
||||||
|
|
||||||
|
// Used to validate controller updates
|
||||||
|
UpdateStrategy: ingress.Strategy,
|
||||||
|
|
||||||
|
Storage: s,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &REST{store}
|
||||||
|
}
|
203
pkg/registry/ingress/etcd/etcd_test.go
Executable file
203
pkg/registry/ingress/etcd/etcd_test.go
Executable file
@@ -0,0 +1,203 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package etcd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/experimental"
|
||||||
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
|
"k8s.io/kubernetes/pkg/registry/registrytest"
|
||||||
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
|
"k8s.io/kubernetes/pkg/tools"
|
||||||
|
"k8s.io/kubernetes/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) {
|
||||||
|
etcdStorage, fakeClient := registrytest.NewEtcdStorage(t, "experimental")
|
||||||
|
ingressStorage := NewREST(etcdStorage)
|
||||||
|
return ingressStorage, fakeClient
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
namespace = api.NamespaceNone
|
||||||
|
name = "foo-ingress"
|
||||||
|
defaultHostname = "foo.bar.com"
|
||||||
|
defaultBackendName = "default-backend"
|
||||||
|
defaultBackendPort = util.IntOrString{Kind: util.IntstrInt, IntVal: 80}
|
||||||
|
defaultLoadBalancer = "127.0.0.1"
|
||||||
|
defaultPath = "/foo"
|
||||||
|
defaultPathMap = map[string]string{defaultPath: defaultBackendName}
|
||||||
|
)
|
||||||
|
|
||||||
|
type IngressRuleValues map[string]string
|
||||||
|
|
||||||
|
func toHTTPIngressPaths(pathMap map[string]string) []experimental.HTTPIngressPath {
|
||||||
|
httpPaths := []experimental.HTTPIngressPath{}
|
||||||
|
for path, backend := range pathMap {
|
||||||
|
httpPaths = append(httpPaths, experimental.HTTPIngressPath{
|
||||||
|
Path: path,
|
||||||
|
Backend: experimental.IngressBackend{
|
||||||
|
ServiceName: backend,
|
||||||
|
ServicePort: defaultBackendPort,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return httpPaths
|
||||||
|
}
|
||||||
|
|
||||||
|
func toIngressRules(hostRules map[string]IngressRuleValues) []experimental.IngressRule {
|
||||||
|
rules := []experimental.IngressRule{}
|
||||||
|
for host, pathMap := range hostRules {
|
||||||
|
rules = append(rules, experimental.IngressRule{
|
||||||
|
Host: host,
|
||||||
|
IngressRuleValue: experimental.IngressRuleValue{
|
||||||
|
HTTP: &experimental.HTTPIngressRuleValue{
|
||||||
|
Paths: toHTTPIngressPaths(pathMap),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return rules
|
||||||
|
}
|
||||||
|
|
||||||
|
func newIngress(pathMap map[string]string) *experimental.Ingress {
|
||||||
|
return &experimental.Ingress{
|
||||||
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
Spec: experimental.IngressSpec{
|
||||||
|
Backend: &experimental.IngressBackend{
|
||||||
|
ServiceName: defaultBackendName,
|
||||||
|
ServicePort: defaultBackendPort,
|
||||||
|
},
|
||||||
|
Rules: toIngressRules(map[string]IngressRuleValues{
|
||||||
|
defaultHostname: pathMap,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
Status: experimental.IngressStatus{
|
||||||
|
LoadBalancer: api.LoadBalancerStatus{
|
||||||
|
Ingress: []api.LoadBalancerIngress{
|
||||||
|
{IP: defaultLoadBalancer},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func validIngress() *experimental.Ingress {
|
||||||
|
return newIngress(defaultPathMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreate(t *testing.T) {
|
||||||
|
storage, fakeClient := newStorage(t)
|
||||||
|
test := registrytest.New(t, fakeClient, storage.Etcd)
|
||||||
|
ingress := validIngress()
|
||||||
|
noDefaultBackendAndRules := validIngress()
|
||||||
|
noDefaultBackendAndRules.Spec.Backend = &experimental.IngressBackend{}
|
||||||
|
noDefaultBackendAndRules.Spec.Rules = []experimental.IngressRule{}
|
||||||
|
badPath := validIngress()
|
||||||
|
badPath.Spec.Rules = toIngressRules(map[string]IngressRuleValues{
|
||||||
|
"foo.bar.com": {"/invalid[": "svc"}})
|
||||||
|
test.TestCreate(
|
||||||
|
// valid
|
||||||
|
ingress,
|
||||||
|
noDefaultBackendAndRules,
|
||||||
|
badPath,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdate(t *testing.T) {
|
||||||
|
storage, fakeClient := newStorage(t)
|
||||||
|
test := registrytest.New(t, fakeClient, storage.Etcd)
|
||||||
|
test.TestUpdate(
|
||||||
|
// valid
|
||||||
|
validIngress(),
|
||||||
|
// updateFunc
|
||||||
|
func(obj runtime.Object) runtime.Object {
|
||||||
|
object := obj.(*experimental.Ingress)
|
||||||
|
object.Spec.Rules = toIngressRules(map[string]IngressRuleValues{
|
||||||
|
"bar.foo.com": {"/bar": defaultBackendName},
|
||||||
|
})
|
||||||
|
return object
|
||||||
|
},
|
||||||
|
// invalid updateFunc: ObjeceMeta is not to be tampered with.
|
||||||
|
func(obj runtime.Object) runtime.Object {
|
||||||
|
object := obj.(*experimental.Ingress)
|
||||||
|
object.UID = "newUID"
|
||||||
|
return object
|
||||||
|
},
|
||||||
|
|
||||||
|
func(obj runtime.Object) runtime.Object {
|
||||||
|
object := obj.(*experimental.Ingress)
|
||||||
|
object.Name = ""
|
||||||
|
return object
|
||||||
|
},
|
||||||
|
|
||||||
|
func(obj runtime.Object) runtime.Object {
|
||||||
|
object := obj.(*experimental.Ingress)
|
||||||
|
object.Spec.Rules = toIngressRules(map[string]IngressRuleValues{
|
||||||
|
"foo.bar.com": {"/invalid[": "svc"}})
|
||||||
|
return object
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDelete(t *testing.T) {
|
||||||
|
storage, fakeClient := newStorage(t)
|
||||||
|
test := registrytest.New(t, fakeClient, storage.Etcd)
|
||||||
|
test.TestDelete(validIngress())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGet(t *testing.T) {
|
||||||
|
storage, fakeClient := newStorage(t)
|
||||||
|
test := registrytest.New(t, fakeClient, storage.Etcd)
|
||||||
|
test.TestGet(validIngress())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestList(t *testing.T) {
|
||||||
|
storage, fakeClient := newStorage(t)
|
||||||
|
test := registrytest.New(t, fakeClient, storage.Etcd)
|
||||||
|
test.TestList(validIngress())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWatch(t *testing.T) {
|
||||||
|
storage, fakeClient := newStorage(t)
|
||||||
|
test := registrytest.New(t, fakeClient, storage.Etcd)
|
||||||
|
test.TestWatch(
|
||||||
|
validIngress(),
|
||||||
|
// matching labels
|
||||||
|
[]labels.Set{},
|
||||||
|
// not matching labels
|
||||||
|
[]labels.Set{
|
||||||
|
{"a": "c"},
|
||||||
|
{"foo": "bar"},
|
||||||
|
},
|
||||||
|
// matching fields
|
||||||
|
[]fields.Set{
|
||||||
|
{"metadata.name": name},
|
||||||
|
},
|
||||||
|
// not matching fields
|
||||||
|
[]fields.Set{
|
||||||
|
{"metadata.name": "bar"},
|
||||||
|
{"name": name},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
116
pkg/registry/ingress/strategy.go
Normal file
116
pkg/registry/ingress/strategy.go
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 The Kubernetes Authors All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ingress
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/experimental"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/experimental/validation"
|
||||||
|
"k8s.io/kubernetes/pkg/fields"
|
||||||
|
"k8s.io/kubernetes/pkg/labels"
|
||||||
|
"k8s.io/kubernetes/pkg/registry/generic"
|
||||||
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
|
"k8s.io/kubernetes/pkg/util/fielderrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ingressStrategy implements verification logic for Replication Ingresss.
|
||||||
|
type ingressStrategy struct {
|
||||||
|
runtime.ObjectTyper
|
||||||
|
api.NameGenerator
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strategy is the default logic that applies when creating and updating Replication Ingress objects.
|
||||||
|
var Strategy = ingressStrategy{api.Scheme, api.SimpleNameGenerator}
|
||||||
|
|
||||||
|
// NamespaceScoped returns true because all Ingress' need to be within a namespace.
|
||||||
|
func (ingressStrategy) NamespaceScoped() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrepareForCreate clears the status of an Ingress before creation.
|
||||||
|
func (ingressStrategy) PrepareForCreate(obj runtime.Object) {
|
||||||
|
ingress := obj.(*experimental.Ingress)
|
||||||
|
ingress.Status = experimental.IngressStatus{}
|
||||||
|
|
||||||
|
ingress.Generation = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrepareForUpdate clears fields that are not allowed to be set by end users on update.
|
||||||
|
func (ingressStrategy) PrepareForUpdate(obj, old runtime.Object) {
|
||||||
|
newIngress := obj.(*experimental.Ingress)
|
||||||
|
oldIngress := old.(*experimental.Ingress)
|
||||||
|
//TODO: Clear Ingress status once we have a sub-resource.
|
||||||
|
|
||||||
|
// Any changes to the spec increment the generation number, any changes to the
|
||||||
|
// status should reflect the generation number of the corresponding object.
|
||||||
|
// See api.ObjectMeta description for more information on Generation.
|
||||||
|
if !reflect.DeepEqual(oldIngress.Spec, newIngress.Spec) {
|
||||||
|
newIngress.Generation = oldIngress.Generation + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates a new Ingress.
|
||||||
|
func (ingressStrategy) Validate(ctx api.Context, obj runtime.Object) fielderrors.ValidationErrorList {
|
||||||
|
ingress := obj.(*experimental.Ingress)
|
||||||
|
err := validation.ValidateIngress(ingress)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllowCreateOnUpdate is false for Ingress; this means POST is needed to create one.
|
||||||
|
func (ingressStrategy) AllowCreateOnUpdate() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateUpdate is the default update validation for an end user.
|
||||||
|
func (ingressStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) fielderrors.ValidationErrorList {
|
||||||
|
validationErrorList := validation.ValidateIngress(obj.(*experimental.Ingress))
|
||||||
|
updateErrorList := validation.ValidateIngressUpdate(old.(*experimental.Ingress), obj.(*experimental.Ingress))
|
||||||
|
return append(validationErrorList, updateErrorList...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllowUnconditionalUpdate is the default update policy for Ingress objects.
|
||||||
|
func (ingressStrategy) AllowUnconditionalUpdate() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IngressToSelectableFields returns a label set that represents the object.
|
||||||
|
func IngressToSelectableFields(ingress *experimental.Ingress) fields.Set {
|
||||||
|
return fields.Set{
|
||||||
|
"metadata.name": ingress.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MatchIngress is the filter used by the generic etcd backend to ingress
|
||||||
|
// watch events from etcd to clients of the apiserver only interested in specific
|
||||||
|
// labels/fields.
|
||||||
|
func MatchIngress(label labels.Selector, field fields.Selector) generic.Matcher {
|
||||||
|
return &generic.SelectionPredicate{
|
||||||
|
Label: label,
|
||||||
|
Field: field,
|
||||||
|
GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
|
||||||
|
ingress, ok := obj.(*experimental.Ingress)
|
||||||
|
if !ok {
|
||||||
|
return nil, nil, fmt.Errorf("Given object is not an Ingress.")
|
||||||
|
}
|
||||||
|
return labels.Set(ingress.ObjectMeta.Labels), IngressToSelectableFields(ingress), nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user