func validateObject(obj interface{}) (errors []error) { switch t := obj.(type) { case *api.ReplicationController: errors = validation.ValidateManifest(&t.DesiredState.PodTemplate.DesiredState.Manifest) case *api.ReplicationControllerList: for i := range t.Items { errors = append(errors, validateObject(&t.Items[i])...) } case *api.Service: errors = validation.ValidateService(t) case *api.ServiceList: for i := range t.Items { errors = append(errors, validateObject(&t.Items[i])...) } case *api.Pod: errors = validation.ValidateManifest(&t.DesiredState.Manifest) case *api.PodList: for i := range t.Items { errors = append(errors, validateObject(&t.Items[i])...) } default: return []error{fmt.Errorf("no validation defined for %#v", obj)} } return errors }
func (rs *REST) Update(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) { service := obj.(*api.Service) if !api.ValidNamespace(ctx, &service.ObjectMeta) { return nil, errors.NewConflict("service", service.Namespace, fmt.Errorf("Service.Namespace does not match the provided context")) } if errs := validation.ValidateService(service, rs.registry, ctx); len(errs) > 0 { return nil, errors.NewInvalid("service", service.Name, errs) } return apiserver.MakeAsync(func() (runtime.Object, error) { cur, err := rs.registry.GetService(ctx, service.Name) if err != nil { return nil, err } if service.Spec.PortalIP != cur.Spec.PortalIP { // TODO: Would be nice to pass "field is immutable" to users. el := errors.ValidationErrorList{errors.NewFieldInvalid("spec.portalIP", service.Spec.PortalIP)} return nil, errors.NewInvalid("service", service.Name, el) } // Copy over non-user fields. service.Spec.ProxyPort = cur.Spec.ProxyPort // TODO: check to see if external load balancer status changed err = rs.registry.UpdateService(ctx, service) if err != nil { return nil, err } return rs.registry.GetService(ctx, service.Name) }), nil }
func validateObject(obj runtime.Object) (errors []error) { ctx := api.NewDefaultContext() switch t := obj.(type) { case *api.ReplicationController: errors = validation.ValidateManifest(&t.DesiredState.PodTemplate.DesiredState.Manifest) case *api.ReplicationControllerList: for i := range t.Items { errors = append(errors, validateObject(&t.Items[i])...) } case *api.Service: api.ValidNamespace(ctx, &t.ObjectMeta) errors = validation.ValidateService(t, registrytest.NewServiceRegistry(), api.NewDefaultContext()) case *api.ServiceList: for i := range t.Items { errors = append(errors, validateObject(&t.Items[i])...) } case *api.Pod: api.ValidNamespace(ctx, &t.ObjectMeta) errors = validation.ValidateManifest(&t.DesiredState.Manifest) case *api.PodList: for i := range t.Items { errors = append(errors, validateObject(&t.Items[i])...) } default: return []error{fmt.Errorf("no validation defined for %#v", obj)} } return errors }
func TestCompatibility_v1_Service(t *testing.T) { // Test "spec.portalIP" -> "spec.clusterIP" expectedIP := "1.2.3.4" // Test "tcp" protocol gets converted to "TCP" and validated originalProtocol := "tcp" expectedProtocol := "TCP" input := []byte(fmt.Sprintf(` { "kind":"Service", "apiVersion":"v1", "metadata":{"name":"my-service-name", "namespace":"my-service-namespace"}, "spec": { "portalIP":"%s", "ports":[{"port":1,"protocol":"%s"}] } } `, expectedIP, originalProtocol)) t.Log("Testing 1.0.0 v1 migration added in PR #3592") testCompatibility( t, "v1", input, func(obj runtime.Object) fielderrors.ValidationErrorList { return validation.ValidateService(obj.(*api.Service)) }, map[string]string{ "spec.portalIP": expectedIP, "spec.clusterIP": expectedIP, "spec.ports[0].protocol": expectedProtocol, }, ) }
func (rs *REST) Update(obj runtime.Object) (<-chan runtime.Object, error) { srv := obj.(*api.Service) if errs := validation.ValidateService(srv); len(errs) > 0 { return nil, errors.NewInvalid("service", srv.ID, errs) } return apiserver.MakeAsync(func() (runtime.Object, error) { // TODO: check to see if external load balancer status changed err := rs.registry.UpdateService(srv) if err != nil { return nil, err } return rs.registry.GetService(srv.ID) }), nil }
func validateObject(path string, obj runtime.Object, t *testing.T) { // if an object requires a namespace server side, be sure that it is filled in for validation if validation.HasObjectMeta(obj) { namespaceRequired, err := validation.GetRequiresNamespace(obj) if err != nil { t.Errorf("Expected no error, Got %v", err) return } if namespaceRequired { objectMeta, err := kapi.ObjectMetaFor(obj) if err != nil { t.Errorf("Expected no error, Got %v", err) return } objectMeta.Namespace = kapi.NamespaceDefault } } switch typedObj := obj.(type) { case *kapi.Pod: if errors := kvalidation.ValidatePod(typedObj); len(errors) > 0 { t.Errorf("%s did not validate correctly: %v", path, errors) } case *kapi.Service: if errors := kvalidation.ValidateService(typedObj); len(errors) > 0 { t.Errorf("%s did not validate correctly: %v", path, errors) } case *kapi.List, *imageapi.ImageStreamList: if list, err := runtime.ExtractList(typedObj); err == nil { runtime.DecodeList(list, kapi.Scheme) for i := range list { validateObject(path, list[i], t) } } else { t.Errorf("Expected no error, Got %v", err) } default: if errors := validation.Validator.Validate(obj); len(errors) > 0 { t.Errorf("%s with %v did not validate correctly: %v", path, reflect.TypeOf(obj), errors) } } }
func (rs *RegistryStorage) Update(obj interface{}) (<-chan interface{}, error) { srv := obj.(*api.Service) if errs := validation.ValidateService(srv); len(errs) > 0 { return nil, errors.NewInvalid("service", srv.ID, errs) } return apiserver.MakeAsync(func() (interface{}, error) { // TODO: check to see if external load balancer status changed err := rs.registry.UpdateService(*srv) if err != nil { return nil, err } return rs.registry.GetService(srv.ID) }), nil }
func validateObject(obj runtime.Object) (errors []error) { switch t := obj.(type) { case *api.ReplicationController: if t.Namespace == "" { t.Namespace = api.NamespaceDefault } errors = validation.ValidateReplicationController(t) case *api.ReplicationControllerList: for i := range t.Items { errors = append(errors, validateObject(&t.Items[i])...) } case *api.Service: if t.Namespace == "" { t.Namespace = api.NamespaceDefault } errors = validation.ValidateService(t) case *api.ServiceList: for i := range t.Items { errors = append(errors, validateObject(&t.Items[i])...) } case *api.Pod: if t.Namespace == "" { t.Namespace = api.NamespaceDefault } errors = validation.ValidatePod(t) case *api.PodList: for i := range t.Items { errors = append(errors, validateObject(&t.Items[i])...) } case *api.PersistentVolume: errors = validation.ValidatePersistentVolume(t) case *api.PersistentVolumeClaim: if t.Namespace == "" { t.Namespace = api.NamespaceDefault } errors = validation.ValidatePersistentVolumeClaim(t) case *api.PodTemplate: if t.Namespace == "" { t.Namespace = api.NamespaceDefault } errors = validation.ValidatePodTemplate(t) default: return []error{fmt.Errorf("no validation defined for %#v", obj)} } return errors }
func (rs *REST) Create(obj runtime.Object) (<-chan runtime.Object, error) { srv := obj.(*api.Service) if errs := validation.ValidateService(srv); len(errs) > 0 { return nil, errors.NewInvalid("service", srv.ID, errs) } srv.CreationTimestamp = util.Now() return apiserver.MakeAsync(func() (runtime.Object, error) { // TODO: Consider moving this to a rectification loop, so that we make/remove external load balancers // correctly no matter what http operations happen. if srv.CreateExternalLoadBalancer { if rs.cloud == nil { return nil, fmt.Errorf("requested an external service, but no cloud provider supplied.") } balancer, ok := rs.cloud.TCPLoadBalancer() if !ok { return nil, fmt.Errorf("The cloud provider does not support external TCP load balancers.") } zones, ok := rs.cloud.Zones() if !ok { return nil, fmt.Errorf("The cloud provider does not support zone enumeration.") } hosts, err := rs.machines.List() if err != nil { return nil, err } zone, err := zones.GetZone() if err != nil { return nil, err } err = balancer.CreateTCPLoadBalancer(srv.ID, zone.Region, srv.Port, hosts) if err != nil { return nil, err } } err := rs.registry.CreateService(srv) if err != nil { return nil, err } return rs.registry.GetService(srv.ID) }), nil }
func validateObject(obj runtime.Object) (errors []error) { ctx := api.NewDefaultContext() switch t := obj.(type) { case *api.ReplicationController: if t.Namespace == "" { t.Namespace = api.NamespaceDefault } errors = validation.ValidateReplicationController(t) case *api.ReplicationControllerList: for i := range t.Items { errors = append(errors, validateObject(&t.Items[i])...) } case *api.Service: if t.Namespace == "" { t.Namespace = api.NamespaceDefault } api.ValidNamespace(ctx, &t.ObjectMeta) errors = validation.ValidateService(t) case *api.ServiceList: for i := range t.Items { errors = append(errors, validateObject(&t.Items[i])...) } case *api.Pod: if t.Namespace == "" { t.Namespace = api.NamespaceDefault } api.ValidNamespace(ctx, &t.ObjectMeta) errors = validation.ValidatePod(t) case *api.PodList: for i := range t.Items { errors = append(errors, validateObject(&t.Items[i])...) } default: return []error{fmt.Errorf("no validation defined for %#v", obj)} } return errors }
// Validate validates a new service. func (svcStrategy) Validate(ctx api.Context, obj runtime.Object) fielderrors.ValidationErrorList { service := obj.(*api.Service) return validation.ValidateService(service) }
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) { service := obj.(*api.Service) if !api.ValidNamespace(ctx, &service.ObjectMeta) { return nil, errors.NewConflict("service", service.Namespace, fmt.Errorf("Service.Namespace does not match the provided context")) } if errs := validation.ValidateService(service, rs.registry, ctx); len(errs) > 0 { return nil, errors.NewInvalid("service", service.Name, errs) } service.CreationTimestamp = util.Now() if service.Spec.PortalIP == "" { // Allocate next available. if ip, err := rs.portalMgr.AllocateNext(); err != nil { return nil, err } else { service.Spec.PortalIP = ip.String() } } else { // Try to respect the requested IP. if err := rs.portalMgr.Allocate(net.ParseIP(service.Spec.PortalIP)); err != nil { // TODO: Differentiate "IP already allocated" from real errors. el := errors.ValidationErrorList{errors.NewFieldInvalid("spec.portalIP", service.Spec.PortalIP)} return nil, errors.NewInvalid("service", service.Name, el) } } return apiserver.MakeAsync(func() (runtime.Object, error) { // TODO: Consider moving this to a rectification loop, so that we make/remove external load balancers // correctly no matter what http operations happen. service.Spec.ProxyPort = 0 if service.Spec.CreateExternalLoadBalancer { if rs.cloud == nil { return nil, fmt.Errorf("requested an external service, but no cloud provider supplied.") } balancer, ok := rs.cloud.TCPLoadBalancer() if !ok { return nil, fmt.Errorf("The cloud provider does not support external TCP load balancers.") } zones, ok := rs.cloud.Zones() if !ok { return nil, fmt.Errorf("The cloud provider does not support zone enumeration.") } hosts, err := rs.machines.ListMinions(ctx) if err != nil { return nil, err } zone, err := zones.GetZone() if err != nil { return nil, err } err = balancer.CreateTCPLoadBalancer(service.Name, zone.Region, service.Spec.Port, hostsFromMinionList(hosts)) if err != nil { return nil, err } // External load-balancers require a known port for the service proxy. // TODO: If we end up brokering HostPorts between Pods and Services, this can be any port. service.Spec.ProxyPort = service.Spec.Port } err := rs.registry.CreateService(ctx, service) if err != nil { return nil, err } return rs.registry.GetService(ctx, service.Name) }), nil }
// Validate validates a new service. func (svcStrategy) Validate(obj runtime.Object) errors.ValidationErrorList { service := obj.(*api.Service) return validation.ValidateService(service) }
func (rs *REST) Create(ctx api.Context, obj runtime.Object) (<-chan apiserver.RESTResult, error) { service := obj.(*api.Service) if !api.ValidNamespace(ctx, &service.ObjectMeta) { return nil, errors.NewConflict("service", service.Namespace, fmt.Errorf("Service.Namespace does not match the provided context")) } if errs := validation.ValidateService(service, rs.registry, ctx); len(errs) > 0 { return nil, errors.NewInvalid("service", service.Name, errs) } api.FillObjectMetaSystemFields(ctx, &service.ObjectMeta) if service.Spec.PortalIP == "" { // Allocate next available. if ip, err := rs.portalMgr.AllocateNext(); err != nil { return nil, err } else { service.Spec.PortalIP = ip.String() } } else { // Try to respect the requested IP. if err := rs.portalMgr.Allocate(net.ParseIP(service.Spec.PortalIP)); err != nil { el := errors.ValidationErrorList{errors.NewFieldInvalid("spec.portalIP", service.Spec.PortalIP, err.Error())} return nil, errors.NewInvalid("service", service.Name, el) } } return apiserver.MakeAsync(func() (runtime.Object, error) { // TODO: Consider moving this to a rectification loop, so that we make/remove external load balancers // correctly no matter what http operations happen. // TODO: Get rid of ProxyPort. service.Spec.ProxyPort = 0 if service.Spec.CreateExternalLoadBalancer { if rs.cloud == nil { return nil, fmt.Errorf("requested an external service, but no cloud provider supplied.") } balancer, ok := rs.cloud.TCPLoadBalancer() if !ok { return nil, fmt.Errorf("the cloud provider does not support external TCP load balancers.") } zones, ok := rs.cloud.Zones() if !ok { return nil, fmt.Errorf("the cloud provider does not support zone enumeration.") } hosts, err := rs.machines.ListMinions(ctx) if err != nil { return nil, err } zone, err := zones.GetZone() if err != nil { return nil, err } var ip net.IP if len(service.Spec.PublicIPs) > 0 { for _, publicIP := range service.Spec.PublicIPs { ip, err = balancer.CreateTCPLoadBalancer(service.Name, zone.Region, net.ParseIP(publicIP), service.Spec.Port, hostsFromMinionList(hosts)) if err != nil { break } } } else { ip, err = balancer.CreateTCPLoadBalancer(service.Name, zone.Region, nil, service.Spec.Port, hostsFromMinionList(hosts)) } if err != nil { return nil, err } service.Spec.PublicIPs = []string{ip.String()} } err := rs.registry.CreateService(ctx, service) if err != nil { return nil, err } return rs.registry.GetService(ctx, service.Name) }), nil }