github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/manager/controlapi/common.go (about) 1 package controlapi 2 3 import ( 4 "regexp" 5 "strings" 6 7 "github.com/docker/docker/pkg/plugingetter" 8 "github.com/docker/libnetwork/driverapi" 9 "github.com/docker/libnetwork/ipamapi" 10 "github.com/docker/swarmkit/api" 11 "github.com/docker/swarmkit/manager/allocator" 12 "github.com/docker/swarmkit/manager/state/store" 13 "google.golang.org/grpc/codes" 14 "google.golang.org/grpc/status" 15 ) 16 17 var isValidDNSName = regexp.MustCompile(`^[a-zA-Z0-9](?:[-_]*[A-Za-z0-9]+)*$`) 18 19 // configs and secrets have different naming requirements from tasks and services 20 var isValidConfigOrSecretName = regexp.MustCompile(`^[a-zA-Z0-9]+(?:[a-zA-Z0-9-_.]*[a-zA-Z0-9])?$`) 21 22 func buildFilters(by func(string) store.By, values []string) store.By { 23 filters := make([]store.By, 0, len(values)) 24 for _, v := range values { 25 filters = append(filters, by(v)) 26 } 27 return store.Or(filters...) 28 } 29 30 func filterContains(match string, candidates []string) bool { 31 if len(candidates) == 0 { 32 return true 33 } 34 for _, c := range candidates { 35 if c == match { 36 return true 37 } 38 } 39 return false 40 } 41 42 func filterContainsPrefix(match string, candidates []string) bool { 43 if len(candidates) == 0 { 44 return true 45 } 46 for _, c := range candidates { 47 if strings.HasPrefix(match, c) { 48 return true 49 } 50 } 51 return false 52 } 53 54 func filterMatchLabels(match map[string]string, candidates map[string]string) bool { 55 if len(candidates) == 0 { 56 return true 57 } 58 59 for k, v := range candidates { 60 c, ok := match[k] 61 if !ok { 62 return false 63 } 64 if v != "" && v != c { 65 return false 66 } 67 } 68 return true 69 } 70 71 func validateAnnotations(m api.Annotations) error { 72 if m.Name == "" { 73 return status.Errorf(codes.InvalidArgument, "meta: name must be provided") 74 } 75 if !isValidDNSName.MatchString(m.Name) { 76 // if the name doesn't match the regex 77 return status.Errorf(codes.InvalidArgument, "name must be valid as a DNS name component") 78 } 79 if len(m.Name) > 63 { 80 // DNS labels are limited to 63 characters 81 return status.Errorf(codes.InvalidArgument, "name must be 63 characters or fewer") 82 } 83 return nil 84 } 85 86 func validateConfigOrSecretAnnotations(m api.Annotations) error { 87 if m.Name == "" { 88 return status.Errorf(codes.InvalidArgument, "name must be provided") 89 } else if len(m.Name) > 64 || !isValidConfigOrSecretName.MatchString(m.Name) { 90 // if the name doesn't match the regex 91 return status.Errorf(codes.InvalidArgument, 92 "invalid name, only 64 [a-zA-Z0-9-_.] characters allowed, and the start and end character must be [a-zA-Z0-9]") 93 } 94 return nil 95 } 96 97 func validateDriver(driver *api.Driver, pg plugingetter.PluginGetter, pluginType string) error { 98 if driver == nil { 99 // It is ok to not specify the driver. We will choose 100 // a default driver. 101 return nil 102 } 103 104 if driver.Name == "" { 105 return status.Errorf(codes.InvalidArgument, "driver name: if driver is specified name is required") 106 } 107 108 // First check against the known drivers 109 switch pluginType { 110 case ipamapi.PluginEndpointType: 111 if strings.ToLower(driver.Name) == ipamapi.DefaultIPAM { 112 return nil 113 } 114 case driverapi.NetworkPluginEndpointType: 115 if allocator.IsBuiltInNetworkDriver(driver.Name) { 116 return nil 117 } 118 default: 119 } 120 121 if pg == nil { 122 return status.Errorf(codes.InvalidArgument, "plugin %s not supported", driver.Name) 123 } 124 125 p, err := pg.Get(driver.Name, pluginType, plugingetter.Lookup) 126 if err != nil { 127 return status.Errorf(codes.InvalidArgument, "error during lookup of plugin %s", driver.Name) 128 } 129 130 if p.IsV1() { 131 return status.Errorf(codes.InvalidArgument, "legacy plugin %s of type %s is not supported in swarm mode", driver.Name, pluginType) 132 } 133 134 return nil 135 }