mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-01-04 23:17:50 +00:00
refactor services to v1beta3
This commit is contained in:
@@ -479,6 +479,38 @@ type ServiceList struct {
|
||||
Items []Service `json:"items" yaml:"items"`
|
||||
}
|
||||
|
||||
// ServiceStatus represents the current status of a service
|
||||
type ServiceStatus struct{}
|
||||
|
||||
// ServiceSpec describes the attributes that a user creates on a service
|
||||
type ServiceSpec struct {
|
||||
// Port is the TCP or UDP port that will be made available to each pod for connecting to the pods
|
||||
// proxied by this service.
|
||||
Port int `json:"port" yaml:"port"`
|
||||
|
||||
// Optional: Supports "TCP" and "UDP". Defaults to "TCP".
|
||||
Protocol Protocol `json:"protocol,omitempty" yaml:"protocol,omitempty"`
|
||||
|
||||
// This service will route traffic to pods having labels matching this selector.
|
||||
Selector map[string]string `json:"selector,omitempty" yaml:"selector,omitempty"`
|
||||
|
||||
// PortalIP is usually assigned by the master. If specified by the user
|
||||
// we will try to respect it or else fail the request. This field can
|
||||
// not be changed by updates.
|
||||
PortalIP string `json:"portalIP,omitempty" yaml:"portalIP,omitempty"`
|
||||
|
||||
// ProxyPort is assigned by the master. If 0, the proxy will choose an ephemeral port.
|
||||
// TODO: This is awkward - if we had a BoundService, it would be better factored.
|
||||
ProxyPort int `json:"proxyPort,omitempty" yaml:"proxyPort,omitempty"`
|
||||
|
||||
// CreateExternalLoadBalancer indicates whether a load balancer should be created for this service.
|
||||
CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty" yaml:"createExternalLoadBalancer,omitempty"`
|
||||
|
||||
// ContainerPort is the name of the port on the container to direct traffic to.
|
||||
// Optional, if unspecified use the first port on the container.
|
||||
ContainerPort util.IntOrString `json:"containerPort,omitempty" yaml:"containerPort,omitempty"`
|
||||
}
|
||||
|
||||
// Service is a named abstraction of software service (for example, mysql) consisting of local port
|
||||
// (for example 3306) that the proxy listens on, and the selector that determines which pods
|
||||
// will answer requests sent through the proxy.
|
||||
@@ -486,27 +518,11 @@ type Service struct {
|
||||
TypeMeta `json:",inline" yaml:",inline"`
|
||||
ObjectMeta `json:"metadata,omitempty" yaml:"metadata,omitempty"`
|
||||
|
||||
// Required.
|
||||
Port int `json:"port" yaml:"port"`
|
||||
// Optional: Defaults to "TCP".
|
||||
Protocol Protocol `yaml:"protocol,omitempty" json:"protocol,omitempty"`
|
||||
// Spec defines the behavior of a service.
|
||||
Spec ServiceSpec `json:"spec,omitempty" yaml:"spec,omitempty"`
|
||||
|
||||
// This service will route traffic to pods having labels matching this selector.
|
||||
Selector map[string]string `json:"selector,omitempty" yaml:"selector,omitempty"`
|
||||
CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty" yaml:"createExternalLoadBalancer,omitempty"`
|
||||
|
||||
// ContainerPort is the name of the port on the container to direct traffic to.
|
||||
// Optional, if unspecified use the first port on the container.
|
||||
ContainerPort util.IntOrString `json:"containerPort,omitempty" yaml:"containerPort,omitempty"`
|
||||
|
||||
// PortalIP is usually assigned by the master. If specified by the user
|
||||
// we will try to respect it or else fail the request. This field can
|
||||
// not be changed by updates.
|
||||
PortalIP string `json:"portalIP,omitempty" yaml:"portalIP,omitempty"`
|
||||
|
||||
// ProxyPort is assigned by the master. If specified by the user it will be ignored.
|
||||
// TODO: This is awkward - if we had a BoundService, it would be better factored.
|
||||
ProxyPort int `json:"proxyPort,omitempty" yaml:"proxyPort,omitempty"`
|
||||
// Status represents the current status of a service.
|
||||
Status ServiceStatus `json:"status,omitempty" yaml:"status,omitempty"`
|
||||
}
|
||||
|
||||
// Endpoints is a collection of endpoints that implement the actual service, for example:
|
||||
|
||||
@@ -247,6 +247,7 @@ func init() {
|
||||
},
|
||||
|
||||
func(in *newer.Service, out *Service, s conversion.Scope) error {
|
||||
|
||||
if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -257,16 +258,15 @@ func init() {
|
||||
return err
|
||||
}
|
||||
|
||||
out.Port = in.Port
|
||||
out.Protocol = Protocol(in.Protocol)
|
||||
if err := s.Convert(&in.Selector, &out.Selector, 0); err != nil {
|
||||
out.Port = in.Spec.Port
|
||||
out.Protocol = Protocol(in.Spec.Protocol)
|
||||
if err := s.Convert(&in.Spec.Selector, &out.Selector, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
out.CreateExternalLoadBalancer = in.CreateExternalLoadBalancer
|
||||
out.ContainerPort = in.ContainerPort
|
||||
out.PortalIP = in.PortalIP
|
||||
out.ProxyPort = in.ProxyPort
|
||||
|
||||
out.CreateExternalLoadBalancer = in.Spec.CreateExternalLoadBalancer
|
||||
out.ContainerPort = in.Spec.ContainerPort
|
||||
out.PortalIP = in.Spec.PortalIP
|
||||
out.ProxyPort = in.Spec.ProxyPort
|
||||
return nil
|
||||
},
|
||||
func(in *Service, out *newer.Service, s conversion.Scope) error {
|
||||
@@ -280,16 +280,15 @@ func init() {
|
||||
return err
|
||||
}
|
||||
|
||||
out.Port = in.Port
|
||||
out.Protocol = newer.Protocol(in.Protocol)
|
||||
if err := s.Convert(&in.Selector, &out.Selector, 0); err != nil {
|
||||
out.Spec.Port = in.Port
|
||||
out.Spec.Protocol = newer.Protocol(in.Protocol)
|
||||
if err := s.Convert(&in.Selector, &out.Spec.Selector, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
out.CreateExternalLoadBalancer = in.CreateExternalLoadBalancer
|
||||
out.ContainerPort = in.ContainerPort
|
||||
out.PortalIP = in.PortalIP
|
||||
out.ProxyPort = in.ProxyPort
|
||||
|
||||
out.Spec.CreateExternalLoadBalancer = in.CreateExternalLoadBalancer
|
||||
out.Spec.ContainerPort = in.ContainerPort
|
||||
out.Spec.PortalIP = in.PortalIP
|
||||
out.Spec.ProxyPort = in.ProxyPort
|
||||
return nil
|
||||
},
|
||||
|
||||
|
||||
@@ -188,15 +188,15 @@ func init() {
|
||||
return err
|
||||
}
|
||||
|
||||
out.Port = in.Port
|
||||
out.Protocol = Protocol(in.Protocol)
|
||||
if err := s.Convert(&in.Selector, &out.Selector, 0); err != nil {
|
||||
out.Port = in.Spec.Port
|
||||
out.Protocol = Protocol(in.Spec.Protocol)
|
||||
if err := s.Convert(&in.Spec.Selector, &out.Selector, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
out.CreateExternalLoadBalancer = in.CreateExternalLoadBalancer
|
||||
out.ContainerPort = in.ContainerPort
|
||||
out.PortalIP = in.PortalIP
|
||||
out.ProxyPort = in.ProxyPort
|
||||
out.CreateExternalLoadBalancer = in.Spec.CreateExternalLoadBalancer
|
||||
out.ContainerPort = in.Spec.ContainerPort
|
||||
out.PortalIP = in.Spec.PortalIP
|
||||
out.ProxyPort = in.Spec.ProxyPort
|
||||
|
||||
return nil
|
||||
},
|
||||
@@ -211,15 +211,15 @@ func init() {
|
||||
return err
|
||||
}
|
||||
|
||||
out.Port = in.Port
|
||||
out.Protocol = newer.Protocol(in.Protocol)
|
||||
if err := s.Convert(&in.Selector, &out.Selector, 0); err != nil {
|
||||
out.Spec.Port = in.Port
|
||||
out.Spec.Protocol = newer.Protocol(in.Protocol)
|
||||
if err := s.Convert(&in.Selector, &out.Spec.Selector, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
out.CreateExternalLoadBalancer = in.CreateExternalLoadBalancer
|
||||
out.ContainerPort = in.ContainerPort
|
||||
out.PortalIP = in.PortalIP
|
||||
out.ProxyPort = in.ProxyPort
|
||||
out.Spec.CreateExternalLoadBalancer = in.CreateExternalLoadBalancer
|
||||
out.Spec.ContainerPort = in.ContainerPort
|
||||
out.Spec.PortalIP = in.PortalIP
|
||||
out.Spec.ProxyPort = in.ProxyPort
|
||||
|
||||
return nil
|
||||
},
|
||||
|
||||
@@ -123,36 +123,37 @@ const (
|
||||
NamespaceAll string = ""
|
||||
)
|
||||
|
||||
// ContainerManifest corresponds to the Container Manifest format, documented at:
|
||||
// https://developers.google.com/compute/docs/containers/container_vms#container_manifest
|
||||
// This is used as the representation of Kubernetes workloads.
|
||||
// DEPRECATED: Exists to allow backwards compatible storage for clients accessing etcd
|
||||
// directly.
|
||||
type ContainerManifest struct {
|
||||
// Required: This must be a supported version string, such as "v1beta1".
|
||||
Version string `json:"version" yaml:"version"`
|
||||
// Required: This must be a DNS_SUBDOMAIN.
|
||||
// TODO: ID on Manifest is deprecated and will be removed in the future.
|
||||
ID string `json:"id" yaml:"id"`
|
||||
// TODO: UUID on Manifest is deprecated in the future once we are done
|
||||
// with the API refactoring. It is required for now to determine the instance
|
||||
// of a Pod.
|
||||
UUID string `json:"uuid,omitempty" yaml:"uuid,omitempty"`
|
||||
Volumes []Volume `json:"volumes" yaml:"volumes"`
|
||||
Containers []Container `json:"containers" yaml:"containers"`
|
||||
RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" yaml:"restartPolicy,omitempty"`
|
||||
}
|
||||
|
||||
// ContainerManifestList is used to communicate container manifests to kubelet.
|
||||
// DEPRECATED: Exists to allow backwards compatible storage for clients accessing etcd
|
||||
// directly.
|
||||
type ContainerManifestList struct {
|
||||
TypeMeta `json:",inline" yaml:",inline"`
|
||||
// ID is the legacy field representing Name
|
||||
ID string `json:"id,omitempty" yaml:"id,omitempty"`
|
||||
|
||||
Items []ContainerManifest `json:"items,omitempty" yaml:"items,omitempty"`
|
||||
}
|
||||
//
|
||||
//// ContainerManifest corresponds to the Container Manifest format, documented at:
|
||||
//// https://developers.google.com/compute/docs/containers/container_vms#container_manifest
|
||||
//// This is used as the representation of Kubernetes workloads.
|
||||
//// DEPRECATED: Exists to allow backwards compatible storage for clients accessing etcd
|
||||
//// directly.
|
||||
//type ContainerManifest struct {
|
||||
// // Required: This must be a supported version string, such as "v1beta1".
|
||||
// Version string `json:"version" yaml:"version"`
|
||||
// // Required: This must be a DNS_SUBDOMAIN.
|
||||
// // TODO: ID on Manifest is deprecated and will be removed in the future.
|
||||
// ID string `json:"id" yaml:"id"`
|
||||
// // TODO: UUID on Manifest is deprecated in the future once we are done
|
||||
// // with the API refactoring. It is required for now to determine the instance
|
||||
// // of a Pod.
|
||||
// UUID string `json:"uuid,omitempty" yaml:"uuid,omitempty"`
|
||||
// Volumes []Volume `json:"volumes" yaml:"volumes"`
|
||||
// Containers []Container `json:"containers" yaml:"containers"`
|
||||
// RestartPolicy RestartPolicy `json:"restartPolicy,omitempty" yaml:"restartPolicy,omitempty"`
|
||||
//}
|
||||
//
|
||||
//// ContainerManifestList is used to communicate container manifests to kubelet.
|
||||
//// DEPRECATED: Exists to allow backwards compatible storage for clients accessing etcd
|
||||
//// directly.
|
||||
//type ContainerManifestList struct {
|
||||
// TypeMeta `json:",inline" yaml:",inline"`
|
||||
// // ID is the legacy field representing Name
|
||||
// ID string `json:"id,omitempty" yaml:"id,omitempty"`
|
||||
//
|
||||
// Items []ContainerManifest `json:"items,omitempty" yaml:"items,omitempty"`
|
||||
//}
|
||||
|
||||
// Volume represents a named volume in a pod that may be accessed by any containers in the pod.
|
||||
type Volume struct {
|
||||
@@ -583,10 +584,7 @@ type ReplicationControllerList struct {
|
||||
}
|
||||
|
||||
// ServiceStatus represents the current status of a service
|
||||
type ServiceStatus struct {
|
||||
// ProxyPort is assigned by the master. If 0, the proxy will choose an ephemeral port.
|
||||
ProxyPort int `json:"proxyPort,omitempty" yaml:"proxyPort,omitempty"`
|
||||
}
|
||||
type ServiceStatus struct{}
|
||||
|
||||
// ServiceSpec describes the attributes that a user creates on a service
|
||||
type ServiceSpec struct {
|
||||
@@ -605,6 +603,9 @@ type ServiceSpec struct {
|
||||
// not be changed by updates.
|
||||
PortalIP string `json:"portalIP,omitempty" yaml:"portalIP,omitempty"`
|
||||
|
||||
// ProxyPort is assigned by the master. If 0, the proxy will choose an ephemeral port.
|
||||
ProxyPort int `json:"proxyPort,omitempty" yaml:"proxyPort,omitempty"`
|
||||
|
||||
// CreateExternalLoadBalancer indicates whether a load balancer should be created for this service.
|
||||
CreateExternalLoadBalancer bool `json:"createExternalLoadBalancer,omitempty" yaml:"createExternalLoadBalancer,omitempty"`
|
||||
|
||||
|
||||
@@ -392,19 +392,19 @@ func ValidateService(service *api.Service) errs.ValidationErrorList {
|
||||
if !util.IsDNSSubdomain(service.Namespace) {
|
||||
allErrs = append(allErrs, errs.NewFieldInvalid("namespace", service.Namespace))
|
||||
}
|
||||
if !util.IsValidPortNum(service.Port) {
|
||||
allErrs = append(allErrs, errs.NewFieldInvalid("port", service.Port))
|
||||
if !util.IsValidPortNum(service.Spec.Port) {
|
||||
allErrs = append(allErrs, errs.NewFieldInvalid("spec.port", service.Spec.Port))
|
||||
}
|
||||
if len(service.Protocol) == 0 {
|
||||
service.Protocol = "TCP"
|
||||
} else if !supportedPortProtocols.Has(strings.ToUpper(string(service.Protocol))) {
|
||||
allErrs = append(allErrs, errs.NewFieldNotSupported("protocol", service.Protocol))
|
||||
if len(service.Spec.Protocol) == 0 {
|
||||
service.Spec.Protocol = "TCP"
|
||||
} else if !supportedPortProtocols.Has(strings.ToUpper(string(service.Spec.Protocol))) {
|
||||
allErrs = append(allErrs, errs.NewFieldNotSupported("spec.protocol", service.Spec.Protocol))
|
||||
}
|
||||
if labels.Set(service.Selector).AsSelector().Empty() {
|
||||
allErrs = append(allErrs, errs.NewFieldRequired("selector", service.Selector))
|
||||
if labels.Set(service.Spec.Selector).AsSelector().Empty() {
|
||||
allErrs = append(allErrs, errs.NewFieldRequired("spec.selector", service.Spec.Selector))
|
||||
}
|
||||
allErrs = append(allErrs, validateLabels(service.Labels)...)
|
||||
allErrs = append(allErrs, validateLabels(service.Selector)...)
|
||||
allErrs = append(allErrs, validateLabels(service.Spec.Selector)...)
|
||||
return allErrs
|
||||
}
|
||||
|
||||
|
||||
@@ -633,8 +633,10 @@ func TestValidateService(t *testing.T) {
|
||||
name: "missing id",
|
||||
svc: api.Service{
|
||||
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault},
|
||||
Port: 8675,
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
Spec: api.ServiceSpec{
|
||||
Port: 8675,
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
},
|
||||
},
|
||||
// Should fail because the ID is missing.
|
||||
numErrs: 1,
|
||||
@@ -643,8 +645,10 @@ func TestValidateService(t *testing.T) {
|
||||
name: "missing namespace",
|
||||
svc: api.Service{
|
||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||
Port: 8675,
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
Spec: api.ServiceSpec{
|
||||
Port: 8675,
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
},
|
||||
},
|
||||
// Should fail because the Namespace is missing.
|
||||
numErrs: 1,
|
||||
@@ -653,8 +657,10 @@ func TestValidateService(t *testing.T) {
|
||||
name: "invalid id",
|
||||
svc: api.Service{
|
||||
ObjectMeta: api.ObjectMeta{Name: "123abc", Namespace: api.NamespaceDefault},
|
||||
Port: 8675,
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
Spec: api.ServiceSpec{
|
||||
Port: 8675,
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
},
|
||||
},
|
||||
// Should fail because the ID is invalid.
|
||||
numErrs: 1,
|
||||
@@ -663,7 +669,9 @@ func TestValidateService(t *testing.T) {
|
||||
name: "missing port",
|
||||
svc: api.Service{
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
Spec: api.ServiceSpec{
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
},
|
||||
},
|
||||
// Should fail because the port number is missing/invalid.
|
||||
numErrs: 1,
|
||||
@@ -672,8 +680,10 @@ func TestValidateService(t *testing.T) {
|
||||
name: "invalid port",
|
||||
svc: api.Service{
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
||||
Port: 65536,
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
Spec: api.ServiceSpec{
|
||||
Port: 66536,
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
},
|
||||
},
|
||||
// Should fail because the port number is invalid.
|
||||
numErrs: 1,
|
||||
@@ -682,9 +692,11 @@ func TestValidateService(t *testing.T) {
|
||||
name: "invalid protocol",
|
||||
svc: api.Service{
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
||||
Port: 8675,
|
||||
Protocol: "INVALID",
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
Spec: api.ServiceSpec{
|
||||
Port: 8675,
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
Protocol: "INVALID",
|
||||
},
|
||||
},
|
||||
// Should fail because the protocol is invalid.
|
||||
numErrs: 1,
|
||||
@@ -693,7 +705,9 @@ func TestValidateService(t *testing.T) {
|
||||
name: "missing selector",
|
||||
svc: api.Service{
|
||||
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault},
|
||||
Port: 8675,
|
||||
Spec: api.ServiceSpec{
|
||||
Port: 8675,
|
||||
},
|
||||
},
|
||||
// Should fail because the selector is missing.
|
||||
numErrs: 1,
|
||||
@@ -702,9 +716,11 @@ func TestValidateService(t *testing.T) {
|
||||
name: "valid 1",
|
||||
svc: api.Service{
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
||||
Port: 1,
|
||||
Protocol: "TCP",
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
Spec: api.ServiceSpec{
|
||||
Port: 8675,
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
Protocol: "TCP",
|
||||
},
|
||||
},
|
||||
numErrs: 0,
|
||||
},
|
||||
@@ -712,9 +728,11 @@ func TestValidateService(t *testing.T) {
|
||||
name: "valid 2",
|
||||
svc: api.Service{
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
||||
Port: 65535,
|
||||
Protocol: "UDP",
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
Spec: api.ServiceSpec{
|
||||
Port: 8675,
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
Protocol: "UDP",
|
||||
},
|
||||
},
|
||||
numErrs: 0,
|
||||
},
|
||||
@@ -722,8 +740,10 @@ func TestValidateService(t *testing.T) {
|
||||
name: "valid 3",
|
||||
svc: api.Service{
|
||||
ObjectMeta: api.ObjectMeta{Name: "abc123", Namespace: api.NamespaceDefault},
|
||||
Port: 80,
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
Spec: api.ServiceSpec{
|
||||
Port: 8675,
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
},
|
||||
},
|
||||
numErrs: 0,
|
||||
},
|
||||
@@ -737,8 +757,10 @@ func TestValidateService(t *testing.T) {
|
||||
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
|
||||
},
|
||||
},
|
||||
Port: 80,
|
||||
Selector: map[string]string{"foo": "bar", "NoUppercaseOrSpecialCharsLike=Equals": "bar"},
|
||||
Spec: api.ServiceSpec{
|
||||
Port: 8675,
|
||||
Selector: map[string]string{"foo": "bar", "NoUppercaseOrSpecialCharsLike=Equals": "bar"},
|
||||
},
|
||||
},
|
||||
numErrs: 2,
|
||||
},
|
||||
@@ -752,15 +774,17 @@ func TestValidateService(t *testing.T) {
|
||||
}
|
||||
|
||||
svc := api.Service{
|
||||
Port: 6502,
|
||||
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault},
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
Spec: api.ServiceSpec{
|
||||
Port: 8675,
|
||||
Selector: map[string]string{"foo": "bar"},
|
||||
},
|
||||
}
|
||||
errs := ValidateService(&svc)
|
||||
if len(errs) != 0 {
|
||||
t.Errorf("Unexpected non-zero error list: %#v", errs)
|
||||
}
|
||||
if svc.Protocol != "TCP" {
|
||||
if svc.Spec.Protocol != "TCP" {
|
||||
t.Errorf("Expected default protocol of 'TCP': %#v", errs)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user