mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-02 00:07:50 +00:00
Merge pull request #13372 from thockin/strict-compat-external-ip
easier auto-conversion, strict compat with deprecatedPublicIPs
This commit is contained in:
commit
51a3b80b99
@ -13818,7 +13818,14 @@
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "ExternalIPs are used by external load balancers, or can be set by users to handle external traffic that arrives at a node. Externally visible IPs (e.g. load balancers) that should be proxied to this service."
|
||||
"description": "externalIPs is a list of IP addresses for which nodes in the cluster will also accept traffic for this service. These IPs are not managed by Kubernetes. The user is responsible for ensuring that traffic arrives at a node with this IP. A common example is external load-balancers that are not part of the Kubernetes system. A previous form of this functionality exists as the deprecatedPublicIPs field. When using this field, callers should also clear the deprecatedPublicIPs field."
|
||||
},
|
||||
"deprecatedPublicIPs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "deprecatedPublicIPs is deprecated and replaced by the externalIPs field with almost the exact same semantics. This field is retained in the v1 API for compatibility until at least 8/20/2016. It will be removed from any new API revisions. If both deprecatedPublicIPs *and* externalIPs are set, deprecatedPublicIPs is used."
|
||||
},
|
||||
"sessionAffinity": {
|
||||
"type": "string",
|
||||
|
@ -29,8 +29,10 @@ func addConversionFuncs() {
|
||||
err := api.Scheme.AddConversionFuncs(
|
||||
convert_api_PodSpec_To_v1_PodSpec,
|
||||
convert_api_ReplicationControllerSpec_To_v1_ReplicationControllerSpec,
|
||||
convert_api_ServiceSpec_To_v1_ServiceSpec,
|
||||
convert_v1_PodSpec_To_api_PodSpec,
|
||||
convert_v1_ReplicationControllerSpec_To_api_ReplicationControllerSpec,
|
||||
convert_v1_ServiceSpec_To_api_ServiceSpec,
|
||||
)
|
||||
if err != nil {
|
||||
// If one of the conversion functions is malformed, detect it immediately.
|
||||
@ -365,3 +367,28 @@ func convert_v1_PodSpec_To_api_PodSpec(in *PodSpec, out *api.PodSpec, s conversi
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convert_api_ServiceSpec_To_v1_ServiceSpec(in *api.ServiceSpec, out *ServiceSpec, s conversion.Scope) error {
|
||||
if err := autoconvert_api_ServiceSpec_To_v1_ServiceSpec(in, out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
// Publish both externalIPs and deprecatedPublicIPs fields in v1.
|
||||
for _, ip := range in.ExternalIPs {
|
||||
out.DeprecatedPublicIPs = append(out.DeprecatedPublicIPs, ip)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convert_v1_ServiceSpec_To_api_ServiceSpec(in *ServiceSpec, out *api.ServiceSpec, s conversion.Scope) error {
|
||||
if err := autoconvert_v1_ServiceSpec_To_api_ServiceSpec(in, out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
// Prefer the legacy deprecatedPublicIPs field, if provided.
|
||||
if len(in.DeprecatedPublicIPs) > 0 {
|
||||
out.ExternalIPs = nil
|
||||
for _, ip := range in.DeprecatedPublicIPs {
|
||||
out.ExternalIPs = append(out.ExternalIPs, ip)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2098,6 +2098,14 @@ func deepCopy_v1_ServiceSpec(in ServiceSpec, out *ServiceSpec, c *conversion.Clo
|
||||
} else {
|
||||
out.ExternalIPs = nil
|
||||
}
|
||||
if in.DeprecatedPublicIPs != nil {
|
||||
out.DeprecatedPublicIPs = make([]string, len(in.DeprecatedPublicIPs))
|
||||
for i := range in.DeprecatedPublicIPs {
|
||||
out.DeprecatedPublicIPs[i] = in.DeprecatedPublicIPs[i]
|
||||
}
|
||||
} else {
|
||||
out.DeprecatedPublicIPs = nil
|
||||
}
|
||||
out.SessionAffinity = in.SessionAffinity
|
||||
out.LoadBalancerIP = in.LoadBalancerIP
|
||||
return nil
|
||||
|
@ -1496,11 +1496,22 @@ type ServiceSpec struct {
|
||||
// More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#external-services
|
||||
Type ServiceType `json:"type,omitempty"`
|
||||
|
||||
// ExternalIPs are used by external load balancers, or can be set by
|
||||
// users to handle external traffic that arrives at a node.
|
||||
// Externally visible IPs (e.g. load balancers) that should be proxied to this service.
|
||||
// externalIPs is a list of IP addresses for which nodes in the cluster
|
||||
// will also accept traffic for this service. These IPs are not managed by
|
||||
// Kubernetes. The user is responsible for ensuring that traffic arrives
|
||||
// at a node with this IP. A common example is external load-balancers
|
||||
// that are not part of the Kubernetes system. A previous form of this
|
||||
// functionality exists as the deprecatedPublicIPs field. When using this
|
||||
// field, callers should also clear the deprecatedPublicIPs field.
|
||||
ExternalIPs []string `json:"externalIPs,omitempty"`
|
||||
|
||||
// deprecatedPublicIPs is deprecated and replaced by the externalIPs field
|
||||
// with almost the exact same semantics. This field is retained in the v1
|
||||
// API for compatibility until at least 8/20/2016. It will be removed from
|
||||
// any new API revisions. If both deprecatedPublicIPs *and* externalIPs are
|
||||
// set, deprecatedPublicIPs is used.
|
||||
DeprecatedPublicIPs []string `json:"deprecatedPublicIPs,omitempty"`
|
||||
|
||||
// Supports "ClientIP" and "None". Used to maintain session affinity.
|
||||
// Enable client IP based session affinity.
|
||||
// Must be ClientIP or None.
|
||||
|
@ -1290,14 +1290,15 @@ func (ServicePort) SwaggerDoc() map[string]string {
|
||||
}
|
||||
|
||||
var map_ServiceSpec = map[string]string{
|
||||
"": "ServiceSpec describes the attributes that a user creates on a service.",
|
||||
"ports": "The list of ports that are exposed by this service. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#virtual-ips-and-service-proxies",
|
||||
"selector": "This service will route traffic to pods having labels matching this selector. Label keys and values that must match in order to receive traffic for this service. If empty, all pods are selected, if not specified, endpoints must be manually specified. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#overview",
|
||||
"clusterIP": "ClusterIP is usually assigned by the master and is the IP address of the service. If specified, it will be allocated to the service if it is unused or else creation of the service will fail. Valid values are None, empty string (\"\"), or a valid IP address. 'None' can be specified for a headless service when proxying is not required. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#virtual-ips-and-service-proxies",
|
||||
"type": "Type of exposed service. Must be ClusterIP, NodePort, or LoadBalancer. Defaults to ClusterIP. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#external-services",
|
||||
"externalIPs": "ExternalIPs are used by external load balancers, or can be set by users to handle external traffic that arrives at a node. Externally visible IPs (e.g. load balancers) that should be proxied to this service.",
|
||||
"sessionAffinity": "Supports \"ClientIP\" and \"None\". Used to maintain session affinity. Enable client IP based session affinity. Must be ClientIP or None. Defaults to None. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#virtual-ips-and-service-proxies",
|
||||
"loadBalancerIP": "Only applies to Service Type: LoadBalancer LoadBalancer will get created with the IP specified in this field. This feature depends on whether the underlying cloud-provider supports specifying the loadBalancerIP when a load balancer is created. This field will be ignored if the cloud-provider does not support the feature.",
|
||||
"": "ServiceSpec describes the attributes that a user creates on a service.",
|
||||
"ports": "The list of ports that are exposed by this service. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#virtual-ips-and-service-proxies",
|
||||
"selector": "This service will route traffic to pods having labels matching this selector. Label keys and values that must match in order to receive traffic for this service. If empty, all pods are selected, if not specified, endpoints must be manually specified. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#overview",
|
||||
"clusterIP": "ClusterIP is usually assigned by the master and is the IP address of the service. If specified, it will be allocated to the service if it is unused or else creation of the service will fail. Valid values are None, empty string (\"\"), or a valid IP address. 'None' can be specified for a headless service when proxying is not required. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#virtual-ips-and-service-proxies",
|
||||
"type": "Type of exposed service. Must be ClusterIP, NodePort, or LoadBalancer. Defaults to ClusterIP. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#external-services",
|
||||
"externalIPs": "externalIPs is a list of IP addresses for which nodes in the cluster will also accept traffic for this service. These IPs are not managed by Kubernetes. The user is responsible for ensuring that traffic arrives at a node with this IP. A common example is external load-balancers that are not part of the Kubernetes system. A previous form of this functionality exists as the deprecatedPublicIPs field. When using this field, callers should also clear the deprecatedPublicIPs field.",
|
||||
"deprecatedPublicIPs": "deprecatedPublicIPs is deprecated and replaced by the externalIPs field with almost the exact same semantics. This field is retained in the v1 API for compatibility until at least 8/20/2016. It will be removed from any new API revisions. If both deprecatedPublicIPs *and* externalIPs are set, deprecatedPublicIPs is used.",
|
||||
"sessionAffinity": "Supports \"ClientIP\" and \"None\". Used to maintain session affinity. Enable client IP based session affinity. Must be ClientIP or None. Defaults to None. More info: http://releases.k8s.io/HEAD/docs/user-guide/services.md#virtual-ips-and-service-proxies",
|
||||
"loadBalancerIP": "Only applies to Service Type: LoadBalancer LoadBalancer will get created with the IP specified in this field. This feature depends on whether the underlying cloud-provider supports specifying the loadBalancerIP when a load balancer is created. This field will be ignored if the cloud-provider does not support the feature.",
|
||||
}
|
||||
|
||||
func (ServiceSpec) SwaggerDoc() map[string]string {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -44,6 +44,7 @@ func NewConversionGenerator(scheme *conversion.Scheme, targetPkg string) Convers
|
||||
scheme: scheme,
|
||||
targetPkg: targetPkg,
|
||||
convertibles: make(map[reflect.Type]reflect.Type),
|
||||
overridden: make(map[reflect.Type]bool),
|
||||
pkgOverwrites: make(map[string]string),
|
||||
imports: make(map[string]string),
|
||||
shortImports: make(map[string]string),
|
||||
@ -60,6 +61,7 @@ type conversionGenerator struct {
|
||||
scheme *conversion.Scheme
|
||||
targetPkg string
|
||||
convertibles map[reflect.Type]reflect.Type
|
||||
overridden map[reflect.Type]bool
|
||||
// If pkgOverwrites is set for a given package name, that package name
|
||||
// will be replaced while writing conversion function. If empty, package
|
||||
// name will be omitted.
|
||||
@ -165,9 +167,10 @@ func (g *conversionGenerator) generateConversionsBetween(inType, outType reflect
|
||||
if !existingConversion && (inErr != nil || outErr != nil) {
|
||||
return inErr
|
||||
}
|
||||
if !existingConversion {
|
||||
g.convertibles[inType] = outType
|
||||
if existingConversion {
|
||||
g.overridden[inType] = true
|
||||
}
|
||||
g.convertibles[inType] = outType
|
||||
return nil
|
||||
default:
|
||||
// All simple types should be handled correctly with default conversion.
|
||||
@ -368,7 +371,7 @@ func (g *conversionGenerator) RegisterConversionFunctions(w io.Writer, pkg strin
|
||||
// Write conversion function names alphabetically ordered.
|
||||
var names []string
|
||||
for inType, outType := range g.convertibles {
|
||||
names = append(names, g.conversionFunctionName(inType, outType))
|
||||
names = append(names, g.generatedFunctionName(inType, outType))
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
||||
@ -482,6 +485,10 @@ func (g *conversionGenerator) conversionFunctionName(inType, outType reflect.Typ
|
||||
return funcName
|
||||
}
|
||||
|
||||
func (g *conversionGenerator) generatedFunctionName(inType, outType reflect.Type) string {
|
||||
return "auto" + g.conversionFunctionName(inType, outType)
|
||||
}
|
||||
|
||||
func (g *conversionGenerator) writeHeader(b *buffer, name, inType, outType string, indent int) {
|
||||
format := "func %s(in *%s, out *%s, s conversion.Scope) error {\n"
|
||||
stmt := fmt.Sprintf(format, name, inType, outType)
|
||||
@ -654,10 +661,28 @@ func (g *conversionGenerator) writeConversionForPtr(b *buffer, inField, outField
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *conversionGenerator) canTryConversion(b *buffer, inType reflect.Type, inField, outField reflect.StructField, indent int) (bool, error) {
|
||||
if inField.Type.Kind() != outField.Type.Kind() {
|
||||
if !g.overridden[inType] {
|
||||
return false, fmt.Errorf("input %s.%s (%s) does not match output (%s) and conversion is not overridden", inType, inField.Name, inField.Type.Kind(), outField.Type.Kind())
|
||||
}
|
||||
b.addLine(fmt.Sprintf("// in.%s has no peer in out\n", inField.Name), indent)
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (g *conversionGenerator) writeConversionForStruct(b *buffer, inType, outType reflect.Type, indent int) error {
|
||||
for i := 0; i < inType.NumField(); i++ {
|
||||
inField := inType.Field(i)
|
||||
outField, _ := outType.FieldByName(inField.Name)
|
||||
outField, found := outType.FieldByName(inField.Name)
|
||||
if !found {
|
||||
if !g.overridden[inType] {
|
||||
return fmt.Errorf("input %s.%s has no peer in output %s and conversion is not overridden", inType, inField.Name, outType)
|
||||
}
|
||||
b.addLine(fmt.Sprintf("// in.%s has no peer in out\n", inField.Name), indent)
|
||||
continue
|
||||
}
|
||||
|
||||
existsConversion := g.scheme.Converter().HasConversionFunc(inField.Type, outField.Type)
|
||||
if existsConversion && !g.existsDedicatedConversionFunction(inField.Type, outField.Type) {
|
||||
@ -672,16 +697,31 @@ func (g *conversionGenerator) writeConversionForStruct(b *buffer, inType, outTyp
|
||||
|
||||
switch inField.Type.Kind() {
|
||||
case reflect.Map:
|
||||
if try, err := g.canTryConversion(b, inType, inField, outField, indent); err != nil {
|
||||
return err
|
||||
} else if !try {
|
||||
continue
|
||||
}
|
||||
if err := g.writeConversionForMap(b, inField, outField, indent); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
case reflect.Ptr:
|
||||
if try, err := g.canTryConversion(b, inType, inField, outField, indent); err != nil {
|
||||
return err
|
||||
} else if !try {
|
||||
continue
|
||||
}
|
||||
if err := g.writeConversionForPtr(b, inField, outField, indent); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
case reflect.Slice:
|
||||
if try, err := g.canTryConversion(b, inType, inField, outField, indent); err != nil {
|
||||
return err
|
||||
} else if !try {
|
||||
continue
|
||||
}
|
||||
if err := g.writeConversionForSlice(b, inField, outField, indent); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -721,8 +761,9 @@ func (g *conversionGenerator) writeConversionForStruct(b *buffer, inType, outTyp
|
||||
}
|
||||
|
||||
func (g *conversionGenerator) writeConversionForType(b *buffer, inType, outType reflect.Type, indent int) error {
|
||||
funcName := g.conversionFunctionName(inType, outType)
|
||||
g.writeHeader(b, funcName, g.typeName(inType), g.typeName(outType), indent)
|
||||
// Always emit the auto-generated name.
|
||||
autoFuncName := g.generatedFunctionName(inType, outType)
|
||||
g.writeHeader(b, autoFuncName, g.typeName(inType), g.typeName(outType), indent)
|
||||
if err := g.writeDefaultingFunc(b, inType, indent+1); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -736,6 +777,15 @@ func (g *conversionGenerator) writeConversionForType(b *buffer, inType, outType
|
||||
}
|
||||
g.writeFooter(b, indent)
|
||||
b.addLine("\n", 0)
|
||||
|
||||
if !g.overridden[inType] {
|
||||
// Also emit the "user-facing" name.
|
||||
userFuncName := g.conversionFunctionName(inType, outType)
|
||||
g.writeHeader(b, userFuncName, g.typeName(inType), g.typeName(outType), indent)
|
||||
b.addLine(fmt.Sprintf("return %s(in, out, s)\n", autoFuncName), indent+1)
|
||||
b.addLine("}\n\n", 0)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user