istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/model/validation.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package model 16 17 import ( 18 "fmt" 19 "strings" 20 21 "github.com/hashicorp/go-multierror" 22 23 "istio.io/istio/pkg/config/labels" 24 "istio.io/istio/pkg/config/validation/agent" 25 ) 26 27 // UnixAddressPrefix is the prefix used to indicate an address is for a Unix Domain socket. It is used in 28 // ServiceEntry.Endpoint.Address message. 29 const ( 30 UnixAddressPrefix = "unix://" 31 PodIPAddressPrefix = "0.0.0.0" 32 LocalhostAddressPrefix = "127.0.0.1" 33 PodIPv6AddressPrefix = "::" 34 LocalhostIPv6AddressPrefix = "::1" 35 ) 36 37 // Validate ensures that the service object is well-defined 38 func (s *Service) Validate() error { 39 var errs error 40 if len(s.Hostname) == 0 { 41 errs = multierror.Append(errs, fmt.Errorf("invalid empty hostname")) 42 } 43 parts := strings.Split(string(s.Hostname), ".") 44 for _, part := range parts { 45 if !labels.IsDNS1123Label(part) { 46 errs = multierror.Append(errs, fmt.Errorf("invalid hostname part: %q", part)) 47 } 48 } 49 50 // Require at least one port 51 if len(s.Ports) == 0 { 52 errs = multierror.Append(errs, fmt.Errorf("service must have at least one declared port")) 53 } 54 55 // Port names can be empty if there exists only one port 56 for _, port := range s.Ports { 57 if port.Name == "" { 58 if len(s.Ports) > 1 { 59 errs = multierror.Append(errs, 60 fmt.Errorf("empty port names are not allowed for services with multiple ports")) 61 } 62 } else if !labels.IsDNS1123Label(port.Name) { 63 errs = multierror.Append(errs, fmt.Errorf("invalid name: %q", port.Name)) 64 } 65 if err := agent.ValidatePort(port.Port); err != nil { 66 errs = multierror.Append(errs, 67 fmt.Errorf("invalid service port value %d for %q: %v", port.Port, port.Name, err)) 68 } 69 } 70 return errs 71 } 72 73 // Validate ensures that the service instance is well-defined 74 func (instance *ServiceInstance) Validate() error { 75 var errs error 76 if instance.Service == nil { 77 errs = multierror.Append(errs, fmt.Errorf("missing service in the instance")) 78 } else if err := instance.Service.Validate(); err != nil { 79 errs = multierror.Append(errs, err) 80 } 81 82 if instance.Endpoint != nil { 83 if err := instance.Endpoint.Labels.Validate(); err != nil { 84 errs = multierror.Append(errs, err) 85 } 86 87 if err := agent.ValidatePort(int(instance.Endpoint.EndpointPort)); err != nil { 88 errs = multierror.Append(errs, err) 89 } 90 } 91 92 port := instance.ServicePort 93 if port == nil { 94 errs = multierror.Append(errs, fmt.Errorf("missing service port")) 95 } else if instance.Service != nil { 96 expected, ok := instance.Service.Ports.Get(port.Name) 97 if !ok { 98 errs = multierror.Append(errs, fmt.Errorf("missing service port %q", port.Name)) 99 } else { 100 if expected.Port != port.Port { 101 errs = multierror.Append(errs, 102 fmt.Errorf("unexpected service port value %d, expected %d", port.Port, expected.Port)) 103 } 104 if expected.Protocol != port.Protocol { 105 errs = multierror.Append(errs, 106 fmt.Errorf("unexpected service protocol %s, expected %s", port.Protocol, expected.Protocol)) 107 } 108 } 109 } 110 111 return errs 112 }