linkerd2/pkg/inject/report.go

118 lines
3.6 KiB
Go

package inject
import (
"fmt"
"strings"
"github.com/linkerd/linkerd2/pkg/healthcheck"
"github.com/linkerd/linkerd2/pkg/k8s"
v1 "k8s.io/api/core/v1"
)
// Report contains the Kind and Name for a given workload along with booleans
// describing the result of the injection transformation
type Report struct {
Kind string
Name string
HostNetwork bool
Sidecar bool
UDP bool // true if any port in any container has `protocol: UDP`
UnsupportedResource bool
InjectDisabled bool
// Uninjected consists of two boolean flags to indicate if a proxy and
// proxy-init containers have been uninjected in this report
Uninjected struct {
// Proxy is true if a proxy container has been uninjected
Proxy bool
// ProxyInit is true if a proxy-init container has been uninjected
ProxyInit bool
}
}
// newReport returns a new Report struct, initialized with the Kind and Name
// from conf
func newReport(conf *ResourceConfig) *Report {
var name string
if m := conf.workload.Meta; m != nil {
name = m.Name
} else if m := conf.pod.meta; m != nil {
name = m.Name
if name == "" {
name = m.GenerateName
}
}
report := &Report{
Kind: strings.ToLower(conf.workload.metaType.Kind),
Name: name,
}
if conf.pod.meta != nil && conf.pod.spec != nil {
report.InjectDisabled = report.disableByAnnotation(conf)
report.HostNetwork = conf.pod.spec.HostNetwork
report.Sidecar = healthcheck.HasExistingSidecars(conf.pod.spec)
report.UDP = checkUDPPorts(conf.pod.spec)
} else {
report.UnsupportedResource = true
}
return report
}
// ResName returns a string "Kind/Name" for the workload referred in the report r
func (r *Report) ResName() string {
return fmt.Sprintf("%s/%s", r.Kind, r.Name)
}
// Injectable returns false if the report flags indicate that the workload is on a host network
// or there is already a sidecar or the resource is not supported or inject is explicitly disabled
func (r *Report) Injectable() bool {
return !r.HostNetwork && !r.Sidecar && !r.UnsupportedResource && !r.InjectDisabled
}
func checkUDPPorts(t *v1.PodSpec) bool {
// Check for ports with `protocol: UDP`, which will not be routed by Linkerd
for _, container := range t.Containers {
for _, port := range container.Ports {
if port.Protocol == v1.ProtocolUDP {
return true
}
}
}
return false
}
func (r *Report) disableByAnnotation(conf *ResourceConfig) bool {
// truth table of the effects of the inject annotation:
//
// origin | namespace | pod | inject? | return
// ------- | --------- | -------- | -------- | ------
// webhook | enabled | enabled | yes | false
// webhook | enabled | "" | yes | false
// webhook | enabled | disabled | no | true
// webhook | disabled | enabled | yes | false
// webhook | "" | enabled | yes | false
// webhook | disabled | disabled | no | true
// webhook | "" | disabled | no | true
// webhook | disabled | "" | no | true
// webhook | "" | "" | no | true
// cli | n/a | enabled | yes | false
// cli | n/a | "" | yes | false
// cli | n/a | disabled | no | true
podAnnotation := conf.pod.meta.Annotations[k8s.ProxyInjectAnnotation]
nsAnnotation := conf.nsAnnotations[k8s.ProxyInjectAnnotation]
if conf.origin == OriginCLI {
return podAnnotation == k8s.ProxyInjectDisabled
}
if nsAnnotation == k8s.ProxyInjectEnabled {
return podAnnotation == k8s.ProxyInjectDisabled
}
return podAnnotation != k8s.ProxyInjectEnabled
}