Skip to content

Commit

Permalink
Introduce inject check for known sidecars (linkerd#1619)
Browse files Browse the repository at this point in the history
`linkerd inject` was not checking its input for known sidecars and
initContainers.

Modify `linkerd inject` to check for existing sidecars and
initContainers, specifically, Linkerd, Istio, and Contour.

Part of linkerd#1516

Signed-off-by: Andrew Seigner <[email protected]>
  • Loading branch information
siggy committed Sep 11, 2018
1 parent bae0541 commit 5d85680
Show file tree
Hide file tree
Showing 21 changed files with 357 additions and 12 deletions.
63 changes: 52 additions & 11 deletions cli/cmd/inject.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const (

// for inject reports
hostNetworkDesc = "hostNetwork: pods do not use host networking"
sidecarDesc = "sidecar: pods do not have a proxy or initContainer already injected"
unsupportedDesc = "supported: at least one resource injected"
udpDesc = "udp: pod specs do not include UDP ports"
)
Expand All @@ -50,6 +51,7 @@ type injectOptions struct {
type injectReport struct {
name string
hostNetwork bool
sidecar bool
udp bool // true if any port in any container has `protocol: UDP`
unsupportedResource bool
}
Expand Down Expand Up @@ -179,13 +181,16 @@ func injectObjectMeta(t *metaV1.ObjectMeta, k8sLabels map[string]string, options
* injected, return false.
*/
func injectPodSpec(t *v1.PodSpec, identity k8s.TLSIdentity, controlPlaneDNSNameOverride string, options *injectOptions, report *injectReport) bool {
report.hostNetwork = t.HostNetwork
report.sidecar = checkSidecars(t)
report.udp = checkUDPPorts(t)

// Pods with `hostNetwork: true` share a network namespace with the host. The
// init-container would destroy the iptables configuration on the host, so
// skip the injection in this case.
if t.HostNetwork {
report.hostNetwork = true
// Skip injection if:
// 1) Pods with `hostNetwork: true` share a network namespace with the host.
// The init-container would destroy the iptables configuration on the host.
// OR
// 2) Known sidecars already present.
if report.hostNetwork || report.sidecar {
return false
}

Expand Down Expand Up @@ -637,17 +642,22 @@ func generateReport(injectReports []injectReport, output io.Writer) {

injected := []string{}
hostNetwork := []string{}
sidecar := []string{}
udp := []string{}

for _, r := range injectReports {
if !r.hostNetwork && !r.unsupportedResource {
if !r.hostNetwork && !r.sidecar && !r.unsupportedResource {
injected = append(injected, r.name)
}

if r.hostNetwork {
hostNetwork = append(hostNetwork, r.name)
}

if r.sidecar {
sidecar = append(sidecar, r.name)
}

if r.udp {
udp = append(udp, r.name)
}
Expand All @@ -664,11 +674,14 @@ func generateReport(injectReports []injectReport, output io.Writer) {
if len(hostNetwork) == 0 {
output.Write([]byte(fmt.Sprintf("%s%s\n", hostNetworkPrefix, okStatus)))
} else {
verb := "uses"
if len(hostNetwork) > 1 {
verb = "use"
}
output.Write([]byte(fmt.Sprintf("%s%s -- %s %s \"hostNetwork: true\"\n", hostNetworkPrefix, warnStatus, strings.Join(hostNetwork, ", "), verb)))
output.Write([]byte(fmt.Sprintf("%s%s -- \"hostNetwork: true\" detected in %s\n", hostNetworkPrefix, warnStatus, strings.Join(hostNetwork, ", "))))
}

sidecarPrefix := fmt.Sprintf("%s%s", sidecarDesc, getFiller(sidecarDesc))
if len(sidecar) == 0 {
output.Write([]byte(fmt.Sprintf("%s%s\n", sidecarPrefix, okStatus)))
} else {
output.Write([]byte(fmt.Sprintf("%s%s -- known sidecar detected in %s\n", sidecarPrefix, warnStatus, strings.Join(sidecar, ", "))))
}

unsupportedPrefix := fmt.Sprintf("%s%s", unsupportedDesc, getFiller(unsupportedDesc))
Expand Down Expand Up @@ -724,3 +737,31 @@ func checkUDPPorts(t *v1.PodSpec) bool {
}
return false
}

func checkSidecars(t *v1.PodSpec) bool {
// check for known proxies and initContainers
for _, container := range t.Containers {
if strings.HasPrefix(container.Image, "gcr.io/linkerd-io/proxy:") ||
strings.HasPrefix(container.Image, "gcr.io/istio-release/proxyv2:") ||
strings.HasPrefix(container.Image, "gcr.io/heptio-images/contour:") ||
strings.HasPrefix(container.Image, "docker.io/envoyproxy/envoy-alpine:") ||
container.Name == "linkerd-proxy" ||
container.Name == "istio-proxy" ||
container.Name == "contour" ||
container.Name == "envoy" {
return true
}
}
for _, ic := range t.InitContainers {
if strings.HasPrefix(ic.Image, "gcr.io/linkerd-io/proxy-init:") ||
strings.HasPrefix(ic.Image, "gcr.io/istio-release/proxy_init:") ||
strings.HasPrefix(ic.Image, "gcr.io/heptio-images/contour:") ||
ic.Name == "linkerd-init" ||
ic.Name == "istio-init" ||
ic.Name == "envoy-initconfig" {
return true
}
}

return false
}
18 changes: 18 additions & 0 deletions cli/cmd/inject_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,24 @@ func TestInjectYAML(t *testing.T) {
reportFileName: "inject_emojivoto_deployment_udp.report",
testInjectOptions: defaultOptions,
},
{
inputFileName: "inject_emojivoto_already_injected.input.yml",
goldenFileName: "inject_emojivoto_already_injected.input.yml",
reportFileName: "inject_emojivoto_already_injected.report",
testInjectOptions: defaultOptions,
},
{
inputFileName: "inject_emojivoto_istio.input.yml",
goldenFileName: "inject_emojivoto_istio.input.yml",
reportFileName: "inject_emojivoto_istio.report",
testInjectOptions: defaultOptions,
},
{
inputFileName: "inject_contour.input.yml",
goldenFileName: "inject_contour.input.yml",
reportFileName: "inject_contour.report",
testInjectOptions: defaultOptions,
},
}

for i, tc := range testCases {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

hostNetwork: pods do not use host networking...............................[ok]
sidecar: pods do not have a proxy or initContainer already injected........[ok]
supported: at least one resource injected..................................[ok]
udp: pod specs do not include UDP ports....................................[ok]

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

hostNetwork: pods do not use host networking...............................[ok]
sidecar: pods do not have a proxy or initContainer already injected........[ok]
supported: at least one resource injected..................................[ok]
udp: pod specs do not include UDP ports....................................[ok]

Expand All @@ -8,6 +9,7 @@ Summary: 1 of 1 YAML document(s) injected


hostNetwork: pods do not use host networking...............................[ok]
sidecar: pods do not have a proxy or initContainer already injected........[ok]
supported: at least one resource injected..................................[ok]
udp: pod specs do not include UDP ports....................................[ok]

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

hostNetwork: pods do not use host networking...............................[ok]
sidecar: pods do not have a proxy or initContainer already injected........[ok]
supported: at least one resource injected..................................[ok]
udp: pod specs do not include UDP ports....................................[ok]

Expand Down
55 changes: 55 additions & 0 deletions cli/cmd/testdata/inject_contour.input.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
app: contour
name: contour
namespace: heptio-contour
spec:
selector:
matchLabels:
app: contour
replicas: 2
template:
metadata:
labels:
app: contour
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9001"
prometheus.io/path: "/stats"
prometheus.io/format: "prometheus"
spec:
containers:
- image: gcr.io/heptio-images/contour:master
imagePullPolicy: Always
name: contour
command: ["contour"]
args: ["serve", "--incluster"]
- image: docker.io/envoyproxy/envoy-alpine:v1.6.0
name: envoy
ports:
- containerPort: 8080
name: http
- containerPort: 8443
name: https
command: ["envoy"]
args:
- --config-path /config/contour.yaml
- --service-cluster cluster0
- --service-node node0
- --log-level info
- --v2-config-only
volumeMounts:
- name: contour-config
mountPath: /config
initContainers:
- image: gcr.io/heptio-images/contour:master
imagePullPolicy: Always
name: envoy-initconfig
command: ["contour"]
args: ["bootstrap", "/config/contour.yaml"]
volumeMounts:
- name: contour-config
mountPath: /config
---
8 changes: 8 additions & 0 deletions cli/cmd/testdata/inject_contour.report
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

hostNetwork: pods do not use host networking...............................[ok]
sidecar: pods do not have a proxy or initContainer already injected........[warn] -- known sidecar detected in deployment/contour
supported: at least one resource injected..................................[warn] -- no supported objects found
udp: pod specs do not include UDP ports....................................[ok]

Summary: 0 of 1 YAML document(s) injected

151 changes: 151 additions & 0 deletions cli/cmd/testdata/inject_emojivoto_already_injected.input.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
creationTimestamp: null
name: web1
namespace: emojivoto
spec:
replicas: 1
selector:
matchLabels:
app: web-svc
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: web-svc
spec:
containers:
- env:
- name: WEB_PORT
value: "80"
- name: EMOJISVC_HOST
value: emoji-svc.emojivoto:8080
- name: VOTINGSVC_HOST
value: voting-svc.emojivoto:8080
- name: INDEX_BUNDLE
value: dist/index_bundle.js
image: buoyantio/emojivoto-web:v3
name: web-svc
ports:
- containerPort: 80
name: http
resources: {}
- image: gcr.io/linkerd-io/proxy:foo
status: {}
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
creationTimestamp: null
name: web2
namespace: emojivoto
spec:
replicas: 1
selector:
matchLabels:
app: web-svc
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: web-svc
spec:
containers:
- env:
- name: WEB_PORT
value: "80"
- name: EMOJISVC_HOST
value: emoji-svc.emojivoto:8080
- name: VOTINGSVC_HOST
value: voting-svc.emojivoto:8080
- name: INDEX_BUNDLE
value: dist/index_bundle.js
image: buoyantio/emojivoto-web:v3
name: web-svc
ports:
- containerPort: 80
name: http
resources: {}
- name: linkerd-proxy
status: {}
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
creationTimestamp: null
name: web3
namespace: emojivoto
spec:
replicas: 1
selector:
matchLabels:
app: web-svc
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: web-svc
spec:
containers:
- env:
- name: WEB_PORT
value: "80"
- name: EMOJISVC_HOST
value: emoji-svc.emojivoto:8080
- name: VOTINGSVC_HOST
value: voting-svc.emojivoto:8080
- name: INDEX_BUNDLE
value: dist/index_bundle.js
image: buoyantio/emojivoto-web:v3
name: web-svc
ports:
- containerPort: 80
name: http
resources: {}
initContainers:
- image: gcr.io/linkerd-io/proxy-init:foo
status: {}
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
creationTimestamp: null
name: web4
namespace: emojivoto
spec:
replicas: 1
selector:
matchLabels:
app: web-svc
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: web-svc
spec:
containers:
- env:
- name: WEB_PORT
value: "80"
- name: EMOJISVC_HOST
value: emoji-svc.emojivoto:8080
- name: VOTINGSVC_HOST
value: voting-svc.emojivoto:8080
- name: INDEX_BUNDLE
value: dist/index_bundle.js
image: buoyantio/emojivoto-web:v3
name: web-svc
ports:
- containerPort: 80
name: http
resources: {}
initContainers:
- name: linkerd-init
status: {}
---
8 changes: 8 additions & 0 deletions cli/cmd/testdata/inject_emojivoto_already_injected.report
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

hostNetwork: pods do not use host networking...............................[ok]
sidecar: pods do not have a proxy or initContainer already injected........[warn] -- known sidecar detected in deployment/web1, deployment/web2, deployment/web3, deployment/web4
supported: at least one resource injected..................................[warn] -- no supported objects found
udp: pod specs do not include UDP ports....................................[ok]

Summary: 0 of 4 YAML document(s) injected

Loading

0 comments on commit 5d85680

Please sign in to comment.