diff --git a/controller/api/destination/watcher/workload_watcher.go b/controller/api/destination/watcher/workload_watcher.go index 9e562b0d9..6603b8601 100644 --- a/controller/api/destination/watcher/workload_watcher.go +++ b/controller/api/destination/watcher/workload_watcher.go @@ -767,8 +767,9 @@ func GetAnnotatedOpaquePorts(pod *corev1.Pod, defaultPorts map[uint32]struct{}) return defaultPorts } opaquePorts := make(map[uint32]struct{}) + namedPorts := util.GetNamedPorts(pod.Spec.Containers) if annotation != "" { - for _, pr := range util.ParseContainerOpaquePorts(annotation, pod.Spec.Containers) { + for _, pr := range util.ParseContainerOpaquePorts(annotation, namedPorts) { for _, port := range pr.Ports() { opaquePorts[uint32(port)] = struct{}{} } diff --git a/controller/proxy-injector/webhook.go b/controller/proxy-injector/webhook.go index 80fd42483..e2cb147a2 100644 --- a/controller/proxy-injector/webhook.go +++ b/controller/proxy-injector/webhook.go @@ -101,7 +101,7 @@ func Inject(linkerdNamespace string) webhook.Handler { // If namespace has annotations that do not exist on pod then copy them // over to pod's template. - resourceConfig.AppendNamespaceAnnotations() + inject.AppendNamespaceAnnotations(resourceConfig.GetOverrideAnnotations(), resourceConfig.GetNsAnnotations(), resourceConfig.GetWorkloadAnnotations()) // If the pod did not inherit the opaque ports annotation from the // namespace, then add the default value from the config values. This diff --git a/controller/proxy-injector/webhook_test.go b/controller/proxy-injector/webhook_test.go index 3370d1fc1..64c9823c3 100644 --- a/controller/proxy-injector/webhook_test.go +++ b/controller/proxy-injector/webhook_test.go @@ -202,7 +202,7 @@ func TestGetPodPatch(t *testing.T) { // The namespace has two config annotations: one valid and one invalid // the pod patch should only contain the valid annotation. - conf.AppendNamespaceAnnotations() + inject.AppendNamespaceAnnotations(conf.GetOverrideAnnotations(), conf.GetNsAnnotations(), conf.GetWorkloadAnnotations()) patchJSON, err := conf.GetPodPatch(true) if err != nil { t.Fatalf("Unexpected PatchForAdmissionRequest error: %s", err) diff --git a/pkg/inject/inject.go b/pkg/inject/inject.go index aed727a0d..47d7bbea2 100644 --- a/pkg/inject/inject.go +++ b/pkg/inject/inject.go @@ -163,6 +163,330 @@ type annotationPatch struct { OpaquePorts string } +// AppendNamespaceAnnotations allows pods to inherit config specific annotations +// from the namespace they belong to. If the namespace has a valid config key +// that the pod does not, then it is appended to the pod's template +func AppendNamespaceAnnotations(base map[string]string, nsAnn map[string]string, workloadAnn map[string]string) { + ann := append(ProxyAnnotations, ProxyAlphaConfigAnnotations...) + ann = append(ann, k8s.ProxyInjectAnnotation) + + for _, key := range ann { + if _, found := nsAnn[key]; !found { + continue + } + if val, ok := GetConfigOverride(key, workloadAnn, nsAnn); ok { + base[key] = val + } + } +} + +// GetOverriddenValues returns the final Values struct which is created +// by overriding annotated configuration on top of default Values +func GetOverriddenValues(values *l5dcharts.Values, overrides map[string]string, namedPorts map[string]int32) (*l5dcharts.Values, error) { + // Make a copy of Values and mutate that + copyValues, err := values.DeepCopy() + if err != nil { + return nil, err + } + + applyAnnotationOverrides(copyValues, overrides, namedPorts) + return copyValues, nil +} + +func applyAnnotationOverrides(values *l5dcharts.Values, annotations map[string]string, namedPorts map[string]int32) { + + if override, ok := annotations[k8s.ProxyInjectAnnotation]; ok { + if override == k8s.ProxyInjectIngress { + values.Proxy.IsIngress = true + } + } + + if override, ok := annotations[k8s.ProxyImageAnnotation]; ok { + values.Proxy.Image.Name = override + } + + if override, ok := annotations[k8s.ProxyVersionOverrideAnnotation]; ok { + values.Proxy.Image.Version = override + } + + if override, ok := annotations[k8s.ProxyImagePullPolicyAnnotation]; ok { + values.Proxy.Image.PullPolicy = override + } + + if override, ok := annotations[k8s.ProxyInitImageVersionAnnotation]; ok { + values.ProxyInit.Image.Version = override + } + + if override, ok := annotations[k8s.ProxyControlPortAnnotation]; ok { + controlPort, err := strconv.ParseInt(override, 10, 32) + if err == nil { + values.Proxy.Ports.Control = int32(controlPort) + } + } + + if override, ok := annotations[k8s.ProxyInboundPortAnnotation]; ok { + inboundPort, err := strconv.ParseInt(override, 10, 32) + if err == nil { + values.Proxy.Ports.Inbound = int32(inboundPort) + } + } + + if override, ok := annotations[k8s.ProxyAdminPortAnnotation]; ok { + adminPort, err := strconv.ParseInt(override, 10, 32) + if err == nil { + values.Proxy.Ports.Admin = int32(adminPort) + } + } + + if override, ok := annotations[k8s.ProxyOutboundPortAnnotation]; ok { + outboundPort, err := strconv.ParseInt(override, 10, 32) + if err == nil { + values.Proxy.Ports.Outbound = int32(outboundPort) + } + } + + if override, ok := annotations[k8s.ProxyPodInboundPortsAnnotation]; ok { + values.Proxy.PodInboundPorts = override + } + + if override, ok := annotations[k8s.ProxyLogLevelAnnotation]; ok { + values.Proxy.LogLevel = override + } + + if override, ok := annotations[k8s.ProxyLogFormatAnnotation]; ok { + values.Proxy.LogFormat = override + } + + if override, ok := annotations[k8s.ProxyRequireIdentityOnInboundPortsAnnotation]; ok { + values.Proxy.RequireIdentityOnInboundPorts = override + } + + if override, ok := annotations[k8s.ProxyOutboundConnectTimeout]; ok { + duration, err := time.ParseDuration(override) + if err != nil { + log.Warnf("unrecognized proxy-outbound-connect-timeout duration value found on pod annotation: %s", err.Error()) + } else { + values.Proxy.OutboundConnectTimeout = fmt.Sprintf("%dms", int(duration.Seconds()*1000)) + } + } + + if override, ok := annotations[k8s.ProxyInboundConnectTimeout]; ok { + duration, err := time.ParseDuration(override) + if err != nil { + log.Warnf("unrecognized proxy-inbound-connect-timeout duration value found on pod annotation: %s", err.Error()) + } else { + values.Proxy.InboundConnectTimeout = fmt.Sprintf("%dms", int(duration.Seconds()*1000)) + } + } + + if override, ok := annotations[k8s.ProxyOutboundDiscoveryCacheUnusedTimeout]; ok { + duration, err := time.ParseDuration(override) + if err != nil { + log.Warnf("unrecognized duration value used on pod annotation %s: %s", k8s.ProxyOutboundDiscoveryCacheUnusedTimeout, err.Error()) + } else { + values.Proxy.OutboundDiscoveryCacheUnusedTimeout = fmt.Sprintf("%ds", int(duration.Seconds())) + } + } + + if override, ok := annotations[k8s.ProxyInboundDiscoveryCacheUnusedTimeout]; ok { + duration, err := time.ParseDuration(override) + if err != nil { + log.Warnf("unrecognized duration value used on pod annotation %s: %s", k8s.ProxyInboundDiscoveryCacheUnusedTimeout, err.Error()) + } else { + values.Proxy.InboundDiscoveryCacheUnusedTimeout = fmt.Sprintf("%ds", int(duration.Seconds())) + } + } + + if override, ok := annotations[k8s.ProxyDisableOutboundProtocolDetectTimeout]; ok { + value, err := strconv.ParseBool(override) + if err == nil { + values.Proxy.DisableOutboundProtocolDetectTimeout = value + } else { + log.Warnf("unrecognised value used on pod annotation %s: %s", k8s.ProxyDisableOutboundProtocolDetectTimeout, err.Error()) + } + } + + if override, ok := annotations[k8s.ProxyDisableInboundProtocolDetectTimeout]; ok { + value, err := strconv.ParseBool(override) + if err == nil { + values.Proxy.DisableInboundProtocolDetectTimeout = value + } else { + log.Warnf("unrecognised value used on pod annotation %s: %s", k8s.ProxyDisableInboundProtocolDetectTimeout, err.Error()) + } + } + + if override, ok := annotations[k8s.ProxyShutdownGracePeriodAnnotation]; ok { + duration, err := time.ParseDuration(override) + if err != nil { + log.Warnf("unrecognized proxy-shutdown-grace-period duration value found on pod annotation: %s", err.Error()) + } else { + values.Proxy.ShutdownGracePeriod = fmt.Sprintf("%dms", int(duration.Seconds()*1000)) + } + } + + if override, ok := annotations[k8s.ProxyEnableGatewayAnnotation]; ok { + value, err := strconv.ParseBool(override) + if err == nil { + values.Proxy.IsGateway = value + } + } + + if override, ok := annotations[k8s.ProxyWaitBeforeExitSecondsAnnotation]; ok { + waitBeforeExitSeconds, err := strconv.ParseUint(override, 10, 64) + if nil != err { + log.Warnf("unrecognized value used for the %s annotation, uint64 is expected: %s", + k8s.ProxyWaitBeforeExitSecondsAnnotation, override) + } else { + values.Proxy.WaitBeforeExitSeconds = waitBeforeExitSeconds + } + } + + if override, ok := annotations[k8s.ProxyEnableNativeSidecarAnnotation]; ok { + value, err := strconv.ParseBool(override) + if err == nil { + values.Proxy.NativeSidecar = value + } + } + + if override, ok := annotations[k8s.ProxyCPURequestAnnotation]; ok { + _, err := k8sResource.ParseQuantity(override) + if err != nil { + log.Warnf("%s (%s)", err, k8s.ProxyCPURequestAnnotation) + } else { + values.Proxy.Resources.CPU.Request = override + } + } + + if override, ok := annotations[k8s.ProxyMemoryRequestAnnotation]; ok { + _, err := k8sResource.ParseQuantity(override) + if err != nil { + log.Warnf("%s (%s)", err, k8s.ProxyMemoryRequestAnnotation) + } else { + values.Proxy.Resources.Memory.Request = override + } + } + + if override, ok := annotations[k8s.ProxyEphemeralStorageRequestAnnotation]; ok { + _, err := k8sResource.ParseQuantity(override) + if err != nil { + log.Warnf("%s (%s)", err, k8s.ProxyEphemeralStorageRequestAnnotation) + } else { + values.Proxy.Resources.EphemeralStorage.Request = override + } + } + + if override, ok := annotations[k8s.ProxyCPULimitAnnotation]; ok { + q, err := k8sResource.ParseQuantity(override) + if err != nil { + log.Warnf("%s (%s)", err, k8s.ProxyCPULimitAnnotation) + } else { + values.Proxy.Resources.CPU.Limit = override + + n, err := ToWholeCPUCores(q) + if err != nil { + log.Warnf("%s (%s)", err, k8s.ProxyCPULimitAnnotation) + } + values.Proxy.Cores = n + } + } + + if override, ok := annotations[k8s.ProxyMemoryLimitAnnotation]; ok { + _, err := k8sResource.ParseQuantity(override) + if err != nil { + log.Warnf("%s (%s)", err, k8s.ProxyMemoryLimitAnnotation) + } else { + values.Proxy.Resources.Memory.Limit = override + } + } + + if override, ok := annotations[k8s.ProxyEphemeralStorageLimitAnnotation]; ok { + _, err := k8sResource.ParseQuantity(override) + if err != nil { + log.Warnf("%s (%s)", err, k8s.ProxyEphemeralStorageLimitAnnotation) + } else { + values.Proxy.Resources.EphemeralStorage.Limit = override + } + } + + if override, ok := annotations[k8s.ProxyUIDAnnotation]; ok { + v, err := strconv.ParseInt(override, 10, 64) + if err == nil { + values.Proxy.UID = v + } + } + + if override, ok := annotations[k8s.ProxyEnableExternalProfilesAnnotation]; ok { + value, err := strconv.ParseBool(override) + if err == nil { + values.Proxy.EnableExternalProfiles = value + } + } + + if override, ok := annotations[k8s.ProxyInitImageAnnotation]; ok { + values.ProxyInit.Image.Name = override + } + + if override, ok := annotations[k8s.ProxyImagePullPolicyAnnotation]; ok { + values.ProxyInit.Image.PullPolicy = override + } + + if override, ok := annotations[k8s.ProxyIgnoreInboundPortsAnnotation]; ok { + values.ProxyInit.IgnoreInboundPorts = override + } + + if override, ok := annotations[k8s.ProxyIgnoreOutboundPortsAnnotation]; ok { + values.ProxyInit.IgnoreOutboundPorts = override + } + + if override, ok := annotations[k8s.ProxyOpaquePortsAnnotation]; ok { + var opaquePorts strings.Builder + for _, pr := range util.ParseContainerOpaquePorts(override, namedPorts) { + if opaquePorts.Len() > 0 { + opaquePorts.WriteRune(',') + } + opaquePorts.WriteString(pr.ToString()) + } + + values.Proxy.OpaquePorts = opaquePorts.String() + } + + if override, ok := annotations[k8s.DebugImageAnnotation]; ok { + values.DebugContainer.Image.Name = override + } + + if override, ok := annotations[k8s.DebugImageVersionAnnotation]; ok { + values.DebugContainer.Image.Version = override + } + + if override, ok := annotations[k8s.DebugImagePullPolicyAnnotation]; ok { + values.DebugContainer.Image.PullPolicy = override + } + + if override, ok := annotations[k8s.ProxyAwait]; ok { + if override == k8s.Enabled || override == k8s.Disabled { + values.Proxy.Await = override == k8s.Enabled + } else { + log.Warnf("unrecognized value used for the %s annotation, valid values are: [%s, %s]", k8s.ProxyAwait, k8s.Enabled, k8s.Disabled) + } + } + + if override, ok := annotations[k8s.ProxyDefaultInboundPolicyAnnotation]; ok { + if override != k8s.AllUnauthenticated && override != k8s.AllAuthenticated && override != k8s.ClusterUnauthenticated && override != k8s.ClusterAuthenticated && override != k8s.Deny { + log.Warnf("unrecognized value used for the %s annotation, valid values are: [%s, %s, %s, %s, %s]", k8s.ProxyDefaultInboundPolicyAnnotation, k8s.AllUnauthenticated, k8s.AllAuthenticated, k8s.ClusterUnauthenticated, k8s.ClusterAuthenticated, k8s.Deny) + } else { + values.Proxy.DefaultInboundPolicy = override + } + } + + if override, ok := annotations[k8s.ProxySkipSubnetsAnnotation]; ok { + values.ProxyInit.SkipSubnets = override + } + + if override, ok := annotations[k8s.ProxyAccessLogAnnotation]; ok { + values.Proxy.AccessLog = override + } +} + // NewResourceConfig creates and initializes a ResourceConfig func NewResourceConfig(values *l5dcharts.Values, origin Origin, ns string) *ResourceConfig { config := &ResourceConfig{ @@ -205,21 +529,20 @@ func (conf *ResourceConfig) GetOwnerRef() *metav1.OwnerReference { return conf.workload.ownerRef } -// AppendNamespaceAnnotations allows pods to inherit config specific annotations -// from the namespace they belong to. If the namespace has a valid config key -// that the pod does not, then it is appended to the pod's template -func (conf *ResourceConfig) AppendNamespaceAnnotations() { - annotations := append(ProxyAnnotations, ProxyAlphaConfigAnnotations...) - annotations = append(annotations, k8s.ProxyInjectAnnotation) +func (conf *ResourceConfig) GetOverrideAnnotations() map[string]string { + return conf.pod.annotations +} - for _, key := range annotations { - if _, found := conf.nsAnnotations[key]; !found { - continue - } - if val, ok := conf.GetConfigAnnotation(key); ok { - conf.AppendPodAnnotation(key, val) - } +func (conf *ResourceConfig) GetNsAnnotations() map[string]string { + return conf.nsAnnotations +} + +func (conf *ResourceConfig) GetWorkloadAnnotations() map[string]string { + if conf.IsPod() { + return conf.pod.meta.Annotations } + + return conf.workload.Meta.Annotations } // AppendPodAnnotations appends the given annotations to the pod spec in conf @@ -268,25 +591,30 @@ func (conf *ResourceConfig) GetValues() *l5dcharts.Values { return conf.values } -// GetOverriddenValues returns the final Values struct which is created -// by overriding annotated configuration on top of default Values -func (conf *ResourceConfig) GetOverriddenValues() (*l5dcharts.Values, error) { - // Make a copy of Values and mutate that - copyValues, err := conf.values.DeepCopy() - if err != nil { - return nil, err +func (conf *ResourceConfig) getAnnotationOverrides() map[string]string { + overrides := map[string]string{} + for k, v := range conf.pod.meta.Annotations { + overrides[k] = v } - copyValues.Proxy.PodInboundPorts = getPodInboundPorts(conf.pod.spec) - conf.applyAnnotationOverrides(copyValues) - return copyValues, nil + if conf.origin != OriginCLI { + for k, v := range conf.pod.annotations { + overrides[k] = v + } + } + return overrides } // GetPodPatch returns the JSON patch containing the proxy and init containers specs, if any. // If injectProxy is false, only the config.linkerd.io annotations are set. func (conf *ResourceConfig) GetPodPatch(injectProxy bool) ([]byte, error) { + namedPorts := make(map[string]int32) + if conf.HasPodTemplate() { + namedPorts = util.GetNamedPorts(conf.pod.spec.Containers) + } - values, err := conf.GetOverriddenValues() + values, err := GetOverriddenValues(conf.values, conf.getAnnotationOverrides(), namedPorts) + values.Proxy.PodInboundPorts = getPodInboundPorts(conf.pod.spec) if err != nil { return nil, fmt.Errorf("could not generate Overridden Values: %w", err) } @@ -357,20 +685,16 @@ func (conf *ResourceConfig) GetPodPatch(injectProxy bool) ([]byte, error) { // value for a given key. The second is used to decide whether or not the caller // should add the annotation. The caller should not add the annotation if the // resource already has its own. -func (conf *ResourceConfig) GetConfigAnnotation(annotationKey string) (string, bool) { - _, ok := conf.pod.meta.Annotations[annotationKey] +func GetConfigOverride(annotationKey string, workloadAnn map[string]string, nsAnn map[string]string) (string, bool) { + _, ok := workloadAnn[annotationKey] if ok { - log.Debugf("using pod %s %s annotation value", conf.pod.meta.Name, annotationKey) + log.Debugf("using workload %s annotation value", annotationKey) return "", false } - _, ok = conf.workload.Meta.Annotations[annotationKey] + + annotation, ok := nsAnn[annotationKey] if ok { - log.Debugf("using service %s %s annotation value", conf.workload.Meta.Name, annotationKey) - return "", false - } - annotation, ok := conf.nsAnnotations[annotationKey] - if ok { - log.Debugf("using namespace %s %s annotation value", conf.workload.Meta.Namespace, annotationKey) + log.Debugf("using namespace %s annotation value", annotationKey) return annotation, true } return "", false @@ -384,7 +708,12 @@ func (conf *ResourceConfig) CreateOpaquePortsPatch() ([]byte, error) { // does not need to be created. return nil, nil } - opaquePorts, ok := conf.GetConfigAnnotation(k8s.ProxyOpaquePortsAnnotation) + workloadAnn := conf.workload.Meta.Annotations + if conf.IsPod() { + workloadAnn = conf.pod.meta.Annotations + } + + opaquePorts, ok := GetConfigOverride(k8s.ProxyOpaquePortsAnnotation, workloadAnn, conf.nsAnnotations) if ok { // The workload's namespace has the opaque ports annotation, so it // should inherit that value. A patch is created which adds that @@ -839,314 +1168,6 @@ func (conf *ResourceConfig) injectPodAnnotations(values *podPatch) { } } -func (conf *ResourceConfig) applyAnnotationOverrides(values *l5dcharts.Values) { - annotations := make(map[string]string) - for k, v := range conf.pod.meta.Annotations { - annotations[k] = v - } - - // If injecting from CLI, skip applying overrides from new annotations; - // overrides in this case should already be applied through flags. - if conf.origin != OriginCLI { - // Override base values inferred from current pod annotations with - // values from annotations that will be applied to pod after the patch. - for k, v := range conf.pod.annotations { - annotations[k] = v - } - } - - if override, ok := annotations[k8s.ProxyInjectAnnotation]; ok { - if override == k8s.ProxyInjectIngress { - values.Proxy.IsIngress = true - } - } - - if override, ok := annotations[k8s.ProxyImageAnnotation]; ok { - values.Proxy.Image.Name = override - } - - if override, ok := annotations[k8s.ProxyVersionOverrideAnnotation]; ok { - values.Proxy.Image.Version = override - } - - if override, ok := annotations[k8s.ProxyImagePullPolicyAnnotation]; ok { - values.Proxy.Image.PullPolicy = override - } - - if override, ok := annotations[k8s.ProxyInitImageVersionAnnotation]; ok { - values.ProxyInit.Image.Version = override - } - - if override, ok := annotations[k8s.ProxyControlPortAnnotation]; ok { - controlPort, err := strconv.ParseInt(override, 10, 32) - if err == nil { - values.Proxy.Ports.Control = int32(controlPort) - } - } - - if override, ok := annotations[k8s.ProxyInboundPortAnnotation]; ok { - inboundPort, err := strconv.ParseInt(override, 10, 32) - if err == nil { - values.Proxy.Ports.Inbound = int32(inboundPort) - } - } - - if override, ok := annotations[k8s.ProxyAdminPortAnnotation]; ok { - adminPort, err := strconv.ParseInt(override, 10, 32) - if err == nil { - values.Proxy.Ports.Admin = int32(adminPort) - } - } - - if override, ok := annotations[k8s.ProxyOutboundPortAnnotation]; ok { - outboundPort, err := strconv.ParseInt(override, 10, 32) - if err == nil { - values.Proxy.Ports.Outbound = int32(outboundPort) - } - } - - if override, ok := annotations[k8s.ProxyPodInboundPortsAnnotation]; ok { - values.Proxy.PodInboundPorts = override - } - - if override, ok := annotations[k8s.ProxyLogLevelAnnotation]; ok { - values.Proxy.LogLevel = override - } - - if override, ok := annotations[k8s.ProxyLogFormatAnnotation]; ok { - values.Proxy.LogFormat = override - } - - if override, ok := annotations[k8s.ProxyRequireIdentityOnInboundPortsAnnotation]; ok { - values.Proxy.RequireIdentityOnInboundPorts = override - } - - if override, ok := annotations[k8s.ProxyOutboundConnectTimeout]; ok { - duration, err := time.ParseDuration(override) - if err != nil { - log.Warnf("unrecognized proxy-outbound-connect-timeout duration value found on pod annotation: %s", err.Error()) - } else { - values.Proxy.OutboundConnectTimeout = fmt.Sprintf("%dms", int(duration.Seconds()*1000)) - } - } - - if override, ok := annotations[k8s.ProxyInboundConnectTimeout]; ok { - duration, err := time.ParseDuration(override) - if err != nil { - log.Warnf("unrecognized proxy-inbound-connect-timeout duration value found on pod annotation: %s", err.Error()) - } else { - values.Proxy.InboundConnectTimeout = fmt.Sprintf("%dms", int(duration.Seconds()*1000)) - } - } - - if override, ok := annotations[k8s.ProxyOutboundDiscoveryCacheUnusedTimeout]; ok { - duration, err := time.ParseDuration(override) - if err != nil { - log.Warnf("unrecognized duration value used on pod annotation %s: %s", k8s.ProxyOutboundDiscoveryCacheUnusedTimeout, err.Error()) - } else { - values.Proxy.OutboundDiscoveryCacheUnusedTimeout = fmt.Sprintf("%ds", int(duration.Seconds())) - } - } - - if override, ok := annotations[k8s.ProxyInboundDiscoveryCacheUnusedTimeout]; ok { - duration, err := time.ParseDuration(override) - if err != nil { - log.Warnf("unrecognized duration value used on pod annotation %s: %s", k8s.ProxyInboundDiscoveryCacheUnusedTimeout, err.Error()) - } else { - values.Proxy.InboundDiscoveryCacheUnusedTimeout = fmt.Sprintf("%ds", int(duration.Seconds())) - } - } - - if override, ok := annotations[k8s.ProxyDisableOutboundProtocolDetectTimeout]; ok { - value, err := strconv.ParseBool(override) - if err == nil { - values.Proxy.DisableOutboundProtocolDetectTimeout = value - } else { - log.Warnf("unrecognised value used on pod annotation %s: %s", k8s.ProxyDisableOutboundProtocolDetectTimeout, err.Error()) - } - } - - if override, ok := annotations[k8s.ProxyDisableInboundProtocolDetectTimeout]; ok { - value, err := strconv.ParseBool(override) - if err == nil { - values.Proxy.DisableInboundProtocolDetectTimeout = value - } else { - log.Warnf("unrecognised value used on pod annotation %s: %s", k8s.ProxyDisableInboundProtocolDetectTimeout, err.Error()) - } - } - - if override, ok := annotations[k8s.ProxyShutdownGracePeriodAnnotation]; ok { - duration, err := time.ParseDuration(override) - if err != nil { - log.Warnf("unrecognized proxy-shutdown-grace-period duration value found on pod annotation: %s", err.Error()) - } else { - values.Proxy.ShutdownGracePeriod = fmt.Sprintf("%dms", int(duration.Seconds()*1000)) - } - } - - if override, ok := annotations[k8s.ProxyEnableGatewayAnnotation]; ok { - value, err := strconv.ParseBool(override) - if err == nil { - values.Proxy.IsGateway = value - } - } - - if override, ok := annotations[k8s.ProxyWaitBeforeExitSecondsAnnotation]; ok { - waitBeforeExitSeconds, err := strconv.ParseUint(override, 10, 64) - if nil != err { - log.Warnf("unrecognized value used for the %s annotation, uint64 is expected: %s", - k8s.ProxyWaitBeforeExitSecondsAnnotation, override) - } else { - values.Proxy.WaitBeforeExitSeconds = waitBeforeExitSeconds - } - } - - if override, ok := annotations[k8s.ProxyEnableNativeSidecarAnnotation]; ok { - value, err := strconv.ParseBool(override) - if err == nil { - values.Proxy.NativeSidecar = value - } - } - - if override, ok := annotations[k8s.ProxyCPURequestAnnotation]; ok { - _, err := k8sResource.ParseQuantity(override) - if err != nil { - log.Warnf("%s (%s)", err, k8s.ProxyCPURequestAnnotation) - } else { - values.Proxy.Resources.CPU.Request = override - } - } - - if override, ok := annotations[k8s.ProxyMemoryRequestAnnotation]; ok { - _, err := k8sResource.ParseQuantity(override) - if err != nil { - log.Warnf("%s (%s)", err, k8s.ProxyMemoryRequestAnnotation) - } else { - values.Proxy.Resources.Memory.Request = override - } - } - - if override, ok := annotations[k8s.ProxyEphemeralStorageRequestAnnotation]; ok { - _, err := k8sResource.ParseQuantity(override) - if err != nil { - log.Warnf("%s (%s)", err, k8s.ProxyEphemeralStorageRequestAnnotation) - } else { - values.Proxy.Resources.EphemeralStorage.Request = override - } - } - - if override, ok := annotations[k8s.ProxyCPULimitAnnotation]; ok { - q, err := k8sResource.ParseQuantity(override) - if err != nil { - log.Warnf("%s (%s)", err, k8s.ProxyCPULimitAnnotation) - } else { - values.Proxy.Resources.CPU.Limit = override - - n, err := ToWholeCPUCores(q) - if err != nil { - log.Warnf("%s (%s)", err, k8s.ProxyCPULimitAnnotation) - } - values.Proxy.Cores = n - } - } - - if override, ok := annotations[k8s.ProxyMemoryLimitAnnotation]; ok { - _, err := k8sResource.ParseQuantity(override) - if err != nil { - log.Warnf("%s (%s)", err, k8s.ProxyMemoryLimitAnnotation) - } else { - values.Proxy.Resources.Memory.Limit = override - } - } - - if override, ok := annotations[k8s.ProxyEphemeralStorageLimitAnnotation]; ok { - _, err := k8sResource.ParseQuantity(override) - if err != nil { - log.Warnf("%s (%s)", err, k8s.ProxyEphemeralStorageLimitAnnotation) - } else { - values.Proxy.Resources.EphemeralStorage.Limit = override - } - } - - if override, ok := annotations[k8s.ProxyUIDAnnotation]; ok { - v, err := strconv.ParseInt(override, 10, 64) - if err == nil { - values.Proxy.UID = v - } - } - - if override, ok := annotations[k8s.ProxyEnableExternalProfilesAnnotation]; ok { - value, err := strconv.ParseBool(override) - if err == nil { - values.Proxy.EnableExternalProfiles = value - } - } - - if override, ok := annotations[k8s.ProxyInitImageAnnotation]; ok { - values.ProxyInit.Image.Name = override - } - - if override, ok := annotations[k8s.ProxyImagePullPolicyAnnotation]; ok { - values.ProxyInit.Image.PullPolicy = override - } - - if override, ok := annotations[k8s.ProxyIgnoreInboundPortsAnnotation]; ok { - values.ProxyInit.IgnoreInboundPorts = override - } - - if override, ok := annotations[k8s.ProxyIgnoreOutboundPortsAnnotation]; ok { - values.ProxyInit.IgnoreOutboundPorts = override - } - - if override, ok := annotations[k8s.ProxyOpaquePortsAnnotation]; ok { - var opaquePorts strings.Builder - for _, pr := range util.ParseContainerOpaquePorts(override, conf.pod.spec.Containers) { - if opaquePorts.Len() > 0 { - opaquePorts.WriteRune(',') - } - opaquePorts.WriteString(pr.ToString()) - } - - values.Proxy.OpaquePorts = opaquePorts.String() - } - - if override, ok := annotations[k8s.DebugImageAnnotation]; ok { - values.DebugContainer.Image.Name = override - } - - if override, ok := annotations[k8s.DebugImageVersionAnnotation]; ok { - values.DebugContainer.Image.Version = override - } - - if override, ok := annotations[k8s.DebugImagePullPolicyAnnotation]; ok { - values.DebugContainer.Image.PullPolicy = override - } - - if override, ok := annotations[k8s.ProxyAwait]; ok { - if override == k8s.Enabled || override == k8s.Disabled { - values.Proxy.Await = override == k8s.Enabled - } else { - log.Warnf("unrecognized value used for the %s annotation, valid values are: [%s, %s]", k8s.ProxyAwait, k8s.Enabled, k8s.Disabled) - } - } - - if override, ok := annotations[k8s.ProxyDefaultInboundPolicyAnnotation]; ok { - if override != k8s.AllUnauthenticated && override != k8s.AllAuthenticated && override != k8s.ClusterUnauthenticated && override != k8s.ClusterAuthenticated && override != k8s.Deny { - log.Warnf("unrecognized value used for the %s annotation, valid values are: [%s, %s, %s, %s, %s]", k8s.ProxyDefaultInboundPolicyAnnotation, k8s.AllUnauthenticated, k8s.AllAuthenticated, k8s.ClusterUnauthenticated, k8s.ClusterAuthenticated, k8s.Deny) - } else { - values.Proxy.DefaultInboundPolicy = override - } - } - - if override, ok := annotations[k8s.ProxySkipSubnetsAnnotation]; ok { - values.ProxyInit.SkipSubnets = override - } - - if override, ok := annotations[k8s.ProxyAccessLogAnnotation]; ok { - values.Proxy.AccessLog = override - } -} - // GetOverriddenConfiguration returns a map of the overridden proxy annotations func (conf *ResourceConfig) GetOverriddenConfiguration() map[string]string { proxyOverrideConfig := map[string]string{} diff --git a/pkg/inject/inject_test.go b/pkg/inject/inject_test.go index b0ddcccca..569aaa3b0 100644 --- a/pkg/inject/inject_test.go +++ b/pkg/inject/inject_test.go @@ -6,6 +6,7 @@ import ( "github.com/go-test/deep" l5dcharts "github.com/linkerd/linkerd2/pkg/charts/linkerd2" "github.com/linkerd/linkerd2/pkg/k8s" + "github.com/linkerd/linkerd2/pkg/util" "github.com/linkerd/linkerd2/pkg/version" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -301,7 +302,6 @@ func TestGetOverriddenValues(t *testing.T) { expected: func() *l5dcharts.Values { values, _ := l5dcharts.NewValues() values.Proxy.OpaquePorts = "3306" - values.Proxy.PodInboundPorts = "3306" return values }, }, @@ -321,8 +321,12 @@ func TestGetOverriddenValues(t *testing.T) { t.Fatal(err) } - resourceConfig.AppendNamespaceAnnotations() - actual, err := resourceConfig.GetOverriddenValues() + AppendNamespaceAnnotations(resourceConfig.GetOverrideAnnotations(), resourceConfig.GetNsAnnotations(), resourceConfig.GetWorkloadAnnotations()) + actual, err := GetOverriddenValues( + resourceConfig.values, + resourceConfig.getAnnotationOverrides(), + util.GetNamedPorts(resourceConfig.pod.spec.Containers), + ) if err != nil { t.Fatal(err) } diff --git a/pkg/util/parsing.go b/pkg/util/parsing.go index 1bf252d7b..4222b2b0f 100644 --- a/pkg/util/parsing.go +++ b/pkg/util/parsing.go @@ -31,11 +31,11 @@ func ParsePorts(portsString string) map[uint32]struct{} { // ParseContainerOpaquePorts parses the opaque ports annotation into a list of // port ranges, including validating port ranges and converting named ports // into their port number equivalents. -func ParseContainerOpaquePorts(override string, containers []corev1.Container) []PortRange { +func ParseContainerOpaquePorts(override string, namedPorts map[string]int32) []PortRange { portRanges := GetPortRanges(override) var values []PortRange for _, pr := range portRanges { - port, named := isNamed(pr, containers) + port, named := namedPorts[pr] if named { values = append(values, PortRange{UpperBound: int(port), LowerBound: int(port)}) } else { @@ -50,6 +50,19 @@ func ParseContainerOpaquePorts(override string, containers []corev1.Container) [ return values } +func GetNamedPorts(containers []corev1.Container) map[string]int32 { + namedPorts := make(map[string]int32) + for _, container := range containers { + for _, p := range container.Ports { + if p.Name != "" { + namedPorts[p.Name] = p.ContainerPort + } + } + } + + return namedPorts +} + // GetPortRanges gets port ranges from an override annotation func GetPortRanges(override string) []string { var ports []string @@ -60,20 +73,6 @@ func GetPortRanges(override string) []string { return ports } -// isNamed checks if a port range is actually a container named port (e.g. -// `123-456` is a valid name, but also is a valid range); all port names must -// be checked before making it a list. -func isNamed(pr string, containers []corev1.Container) (int32, bool) { - for _, c := range containers { - for _, p := range c.Ports { - if p.Name == pr { - return p.ContainerPort, true - } - } - } - return 0, false -} - // ContainsString checks if a string collections contains the given string. func ContainsString(str string, collection []string) bool { for _, e := range collection { diff --git a/test/fuzzing/fuzzers.go b/test/fuzzing/fuzzers.go index cf26115b8..5d3a7a327 100644 --- a/test/fuzzing/fuzzers.go +++ b/test/fuzzing/fuzzers.go @@ -36,7 +36,7 @@ func FuzzParseContainerOpaquePorts(data []byte) int { if err != nil { return 0 } - _ = util.ParseContainerOpaquePorts(override, containers) + _ = util.ParseContainerOpaquePorts(override, util.GetNamedPorts(containers)) return 1 }