mirror of https://github.com/linkerd/linkerd2.git
Have the Webhook react to pod creation/update only (#2472)
Have the Webhook react to pod creation/update only This was already working almost out-of-the-box, just had to: - Change the webhook config so it watches pods instead of deployments - Grant some extra ClusterRole permissions - Add the piece that figures what's the OwnerReference and add the label for it - Manually inject service account mount paths - Readd volumes tests Fixes #2342 and #1751 Signed-off-by: Alejandro Pedraza <alejandro@buoyant.io>
This commit is contained in:
parent
9c442f6885
commit
7efe385feb
|
@ -80,7 +80,13 @@ rules:
|
||||||
verbs: ["create", "get", "delete"]
|
verbs: ["create", "get", "delete"]
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
resources: ["namespaces"]
|
resources: ["namespaces"]
|
||||||
verbs: ["get"]
|
verbs: ["list", "get", "watch"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["pods"]
|
||||||
|
verbs: ["list"]
|
||||||
|
- apiGroups: ["apps"]
|
||||||
|
resources: ["replicasets"]
|
||||||
|
verbs: ["list", "get", "watch"]
|
||||||
---
|
---
|
||||||
kind: ClusterRoleBinding
|
kind: ClusterRoleBinding
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
|
|
@ -142,7 +142,11 @@ func (rt resourceTransformerInject) transform(bytes []byte) ([]byte, []inject.Re
|
||||||
if patchJSON == nil {
|
if patchJSON == nil {
|
||||||
return bytes, reports, nil
|
return bytes, reports, nil
|
||||||
}
|
}
|
||||||
log.Infof("patch generated for: %s", conf)
|
// TODO: refactor GetPatch() for it to return just one report item
|
||||||
|
if len(reports) > 0 {
|
||||||
|
r := reports[0]
|
||||||
|
log.Infof("patch generated for: %s", r.ResName())
|
||||||
|
}
|
||||||
log.Debugf("patch: %s", patchJSON)
|
log.Debugf("patch: %s", patchJSON)
|
||||||
patch, err := jsonpatch.DecodePatch(patchJSON)
|
patch, err := jsonpatch.DecodePatch(patchJSON)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1491,7 +1491,13 @@ rules:
|
||||||
verbs: ["create", "get", "delete"]
|
verbs: ["create", "get", "delete"]
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
resources: ["namespaces"]
|
resources: ["namespaces"]
|
||||||
verbs: ["get"]
|
verbs: ["list", "get", "watch"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["pods"]
|
||||||
|
verbs: ["list"]
|
||||||
|
- apiGroups: ["apps"]
|
||||||
|
resources: ["replicasets"]
|
||||||
|
verbs: ["list", "get", "watch"]
|
||||||
---
|
---
|
||||||
kind: ClusterRoleBinding
|
kind: ClusterRoleBinding
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
|
|
@ -1424,7 +1424,13 @@ rules:
|
||||||
verbs: ["create", "get", "delete"]
|
verbs: ["create", "get", "delete"]
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
resources: ["namespaces"]
|
resources: ["namespaces"]
|
||||||
verbs: ["get"]
|
verbs: ["list", "get", "watch"]
|
||||||
|
- apiGroups: [""]
|
||||||
|
resources: ["pods"]
|
||||||
|
verbs: ["list"]
|
||||||
|
- apiGroups: ["apps"]
|
||||||
|
resources: ["replicasets"]
|
||||||
|
verbs: ["list", "get", "watch"]
|
||||||
---
|
---
|
||||||
kind: ClusterRoleBinding
|
kind: ClusterRoleBinding
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
|
|
@ -27,9 +27,9 @@ func main() {
|
||||||
defer close(stop)
|
defer close(stop)
|
||||||
signal.Notify(stop, os.Interrupt, os.Kill)
|
signal.Notify(stop, os.Interrupt, os.Kill)
|
||||||
|
|
||||||
k8sClient, err := k8s.NewClientSet(*kubeconfig)
|
k8sAPI, err := k8s.InitializeAPI(*kubeconfig, k8s.NS, k8s.RS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to initialize Kubernetes client: %s", err)
|
log.Fatalf("failed to initialize Kubernetes API: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rootCA, err := tls.GenerateRootCAWithDefaults("Proxy Injector Mutating Webhook Admission Controller CA")
|
rootCA, err := tls.GenerateRootCAWithDefaults("Proxy Injector Mutating Webhook Admission Controller CA")
|
||||||
|
@ -37,7 +37,7 @@ func main() {
|
||||||
log.Fatalf("failed to create root CA: %s", err)
|
log.Fatalf("failed to create root CA: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
webhookConfig, err := injector.NewWebhookConfig(k8sClient, *controllerNamespace, *webhookServiceName, rootCA)
|
webhookConfig, err := injector.NewWebhookConfig(k8sAPI, *controllerNamespace, *webhookServiceName, rootCA)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to read the trust anchor file: %s", err)
|
log.Fatalf("failed to read the trust anchor file: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -48,11 +48,13 @@ func main() {
|
||||||
}
|
}
|
||||||
log.Infof("created mutating webhook configuration: %s", mwc.ObjectMeta.SelfLink)
|
log.Infof("created mutating webhook configuration: %s", mwc.ObjectMeta.SelfLink)
|
||||||
|
|
||||||
s, err := injector.NewWebhookServer(k8sClient, *addr, *controllerNamespace, *noInitContainer, rootCA)
|
s, err := injector.NewWebhookServer(k8sAPI, *addr, *controllerNamespace, *noInitContainer, rootCA)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to initialize the webhook server: %s", err)
|
log.Fatalf("failed to initialize the webhook server: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
k8sAPI.Sync()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
log.Infof("listening at %s", *addr)
|
log.Infof("listening at %s", *addr)
|
||||||
if err := s.ListenAndServeTLS("", ""); err != nil {
|
if err := s.ListenAndServeTLS("", ""); err != nil {
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
name: linkerd-secrets
|
||||||
|
secret:
|
||||||
|
secretName: nginx-deployment-tls-linkerd-io
|
||||||
|
optional: true
|
|
@ -8,9 +8,9 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/linkerd/linkerd2/controller/k8s"
|
||||||
pkgTls "github.com/linkerd/linkerd2/pkg/tls"
|
pkgTls "github.com/linkerd/linkerd2/pkg/tls"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"k8s.io/client-go/kubernetes"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// WebhookServer is the webhook's HTTP server. It has an embedded webhook which
|
// WebhookServer is the webhook's HTTP server. It has an embedded webhook which
|
||||||
|
@ -21,7 +21,7 @@ type WebhookServer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWebhookServer returns a new instance of the WebhookServer.
|
// NewWebhookServer returns a new instance of the WebhookServer.
|
||||||
func NewWebhookServer(client kubernetes.Interface, addr, controllerNamespace string, noInitContainer bool, rootCA *pkgTls.CA) (*WebhookServer, error) {
|
func NewWebhookServer(api *k8s.API, addr, controllerNamespace string, noInitContainer bool, rootCA *pkgTls.CA) (*WebhookServer, error) {
|
||||||
c, err := tlsConfig(rootCA, controllerNamespace)
|
c, err := tlsConfig(rootCA, controllerNamespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -32,7 +32,7 @@ func NewWebhookServer(client kubernetes.Interface, addr, controllerNamespace str
|
||||||
TLSConfig: c,
|
TLSConfig: c,
|
||||||
}
|
}
|
||||||
|
|
||||||
webhook, err := NewWebhook(client, controllerNamespace, noInitContainer)
|
webhook, err := NewWebhook(api, controllerNamespace, noInitContainer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/linkerd/linkerd2/controller/k8s"
|
||||||
"github.com/linkerd/linkerd2/controller/proxy-injector/fake"
|
"github.com/linkerd/linkerd2/controller/proxy-injector/fake"
|
||||||
"github.com/linkerd/linkerd2/pkg/tls"
|
"github.com/linkerd/linkerd2/pkg/tls"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
@ -20,9 +21,12 @@ var (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// create a webhook which uses its fake client to seed the sidecar configmap
|
// create a webhook which uses its fake client to seed the sidecar configmap
|
||||||
fakeClient := fake.NewClient("")
|
k8sAPI, err := k8s.NewFakeAPI()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
webhook, err := NewWebhook(fakeClient, fake.DefaultControllerNamespace, false)
|
webhook, err := NewWebhook(k8sAPI, fake.DefaultControllerNamespace, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -73,13 +77,12 @@ func TestNewWebhookServer(t *testing.T) {
|
||||||
log.Fatalf("failed to create root CA: %s", err)
|
log.Fatalf("failed to create root CA: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
addr := ":7070"
|
||||||
addr = ":7070"
|
k8sAPI, err := k8s.NewFakeAPI()
|
||||||
kubeconfig = ""
|
if err != nil {
|
||||||
)
|
t.Fatalf("NewFakeAPI returned an error: %s", err)
|
||||||
fakeClient := fake.NewClient(kubeconfig)
|
}
|
||||||
|
server, err := NewWebhookServer(k8sAPI, addr, fake.DefaultControllerNamespace, false, rootCA)
|
||||||
server, err := NewWebhookServer(fakeClient, addr, fake.DefaultControllerNamespace, false, rootCA)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Unexpected error: ", err)
|
t.Fatal("Unexpected error: ", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,6 @@ webhooks:
|
||||||
caBundle: {{ .CABundle }}
|
caBundle: {{ .CABundle }}
|
||||||
rules:
|
rules:
|
||||||
- operations: [ "CREATE" , "UPDATE" ]
|
- operations: [ "CREATE" , "UPDATE" ]
|
||||||
apiGroups: ["apps", "extensions"]
|
apiGroups: [""]
|
||||||
apiVersions: ["v1", "v1beta1", "v1beta2"]
|
apiVersions: ["v1"]
|
||||||
resources: ["deployments"]`
|
resources: ["pods"]`
|
||||||
|
|
|
@ -4,16 +4,17 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
pb "github.com/linkerd/linkerd2/controller/gen/config"
|
pb "github.com/linkerd/linkerd2/controller/gen/config"
|
||||||
|
"github.com/linkerd/linkerd2/controller/k8s"
|
||||||
"github.com/linkerd/linkerd2/pkg/config"
|
"github.com/linkerd/linkerd2/pkg/config"
|
||||||
"github.com/linkerd/linkerd2/pkg/inject"
|
"github.com/linkerd/linkerd2/pkg/inject"
|
||||||
"github.com/linkerd/linkerd2/pkg/k8s"
|
pkgK8s "github.com/linkerd/linkerd2/pkg/k8s"
|
||||||
"github.com/linkerd/linkerd2/pkg/version"
|
"github.com/linkerd/linkerd2/pkg/version"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
"k8s.io/client-go/kubernetes"
|
|
||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,21 +22,21 @@ import (
|
||||||
// requests by injecting sidecar container spec into the pod spec during pod
|
// requests by injecting sidecar container spec into the pod spec during pod
|
||||||
// creation.
|
// creation.
|
||||||
type Webhook struct {
|
type Webhook struct {
|
||||||
client kubernetes.Interface
|
k8sAPI *k8s.API
|
||||||
deserializer runtime.Decoder
|
deserializer runtime.Decoder
|
||||||
controllerNamespace string
|
controllerNamespace string
|
||||||
noInitContainer bool
|
noInitContainer bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWebhook returns a new instance of Webhook.
|
// NewWebhook returns a new instance of Webhook.
|
||||||
func NewWebhook(client kubernetes.Interface, controllerNamespace string, noInitContainer bool) (*Webhook, error) {
|
func NewWebhook(api *k8s.API, controllerNamespace string, noInitContainer bool) (*Webhook, error) {
|
||||||
var (
|
var (
|
||||||
scheme = runtime.NewScheme()
|
scheme = runtime.NewScheme()
|
||||||
codecs = serializer.NewCodecFactory(scheme)
|
codecs = serializer.NewCodecFactory(scheme)
|
||||||
)
|
)
|
||||||
|
|
||||||
return &Webhook{
|
return &Webhook{
|
||||||
client: client,
|
k8sAPI: api,
|
||||||
deserializer: codecs.UniversalDeserializer(),
|
deserializer: codecs.UniversalDeserializer(),
|
||||||
controllerNamespace: controllerNamespace,
|
controllerNamespace: controllerNamespace,
|
||||||
noInitContainer: noInitContainer,
|
noInitContainer: noInitContainer,
|
||||||
|
@ -87,17 +88,17 @@ func (w *Webhook) decode(data []byte) (*admissionv1beta1.AdmissionReview, error)
|
||||||
func (w *Webhook) inject(request *admissionv1beta1.AdmissionRequest) (*admissionv1beta1.AdmissionResponse, error) {
|
func (w *Webhook) inject(request *admissionv1beta1.AdmissionRequest) (*admissionv1beta1.AdmissionResponse, error) {
|
||||||
log.Debugf("request object bytes: %s", request.Object.Raw)
|
log.Debugf("request object bytes: %s", request.Object.Raw)
|
||||||
|
|
||||||
globalConfig, err := config.Global(k8s.MountPathGlobalConfig)
|
globalConfig, err := config.Global(pkgK8s.MountPathGlobalConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
proxyConfig, err := config.Proxy(k8s.MountPathProxyConfig)
|
proxyConfig, err := config.Proxy(pkgK8s.MountPathProxyConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace, err := w.client.CoreV1().Namespaces().Get(request.Namespace, metav1.GetOptions{})
|
namespace, err := w.k8sAPI.NS().Lister().Get(request.Namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -105,6 +106,7 @@ func (w *Webhook) inject(request *admissionv1beta1.AdmissionRequest) (*admission
|
||||||
|
|
||||||
configs := &pb.All{Global: globalConfig, Proxy: proxyConfig}
|
configs := &pb.All{Global: globalConfig, Proxy: proxyConfig}
|
||||||
conf := inject.NewResourceConfig(configs).
|
conf := inject.NewResourceConfig(configs).
|
||||||
|
WithOwnerRetriever(w.ownerRetriever(request.Namespace)).
|
||||||
WithNsAnnotations(nsAnnotations).
|
WithNsAnnotations(nsAnnotations).
|
||||||
WithKind(request.Kind.Kind)
|
WithKind(request.Kind.Kind)
|
||||||
nonEmpty, err := conf.ParseMeta(request.Object.Raw)
|
nonEmpty, err := conf.ParseMeta(request.Object.Raw)
|
||||||
|
@ -120,7 +122,7 @@ func (w *Webhook) inject(request *admissionv1beta1.AdmissionRequest) (*admission
|
||||||
return admissionResponse, nil
|
return admissionResponse, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
p, _, err := conf.GetPatch(request.Object.Raw, inject.ShouldInjectWebhook)
|
p, reports, err := conf.GetPatch(request.Object.Raw, inject.ShouldInjectWebhook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -131,17 +133,15 @@ func (w *Webhook) inject(request *admissionv1beta1.AdmissionRequest) (*admission
|
||||||
|
|
||||||
p.AddCreatedByPodAnnotation(fmt.Sprintf("linkerd/proxy-injector %s", version.Version))
|
p.AddCreatedByPodAnnotation(fmt.Sprintf("linkerd/proxy-injector %s", version.Version))
|
||||||
|
|
||||||
// When adding workloads through `kubectl apply` the spec template labels are
|
|
||||||
// automatically copied to the workload's main metadata section.
|
|
||||||
// This doesn't happen when adding labels through the webhook. So we manually
|
|
||||||
// add them to remain consistent.
|
|
||||||
conf.AddRootLabels(p)
|
|
||||||
|
|
||||||
patchJSON, err := p.Marshal()
|
patchJSON, err := p.Marshal()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
log.Infof("patch generated for: %s", conf)
|
// TODO: refactor GetPatch() so it only returns one report item
|
||||||
|
if len(reports) > 0 {
|
||||||
|
r := reports[0]
|
||||||
|
log.Infof("patch generated for: %s", r.ResName())
|
||||||
|
}
|
||||||
log.Debugf("patch: %s", patchJSON)
|
log.Debugf("patch: %s", patchJSON)
|
||||||
|
|
||||||
patchType := admissionv1beta1.PatchTypeJSONPatch
|
patchType := admissionv1beta1.PatchTypeJSONPatch
|
||||||
|
@ -150,3 +150,10 @@ func (w *Webhook) inject(request *admissionv1beta1.AdmissionRequest) (*admission
|
||||||
|
|
||||||
return admissionResponse, nil
|
return admissionResponse, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *Webhook) ownerRetriever(ns string) inject.OwnerRetrieverFunc {
|
||||||
|
return func(p *v1.Pod) (string, string) {
|
||||||
|
p.SetNamespace(ns)
|
||||||
|
return w.k8sAPI.GetOwnerKindAndName(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/linkerd/linkerd2/controller/k8s"
|
||||||
"github.com/linkerd/linkerd2/controller/proxy-injector/tmpl"
|
"github.com/linkerd/linkerd2/controller/proxy-injector/tmpl"
|
||||||
k8sPkg "github.com/linkerd/linkerd2/pkg/k8s"
|
k8sPkg "github.com/linkerd/linkerd2/pkg/k8s"
|
||||||
"github.com/linkerd/linkerd2/pkg/tls"
|
"github.com/linkerd/linkerd2/pkg/tls"
|
||||||
|
@ -12,7 +13,6 @@ import (
|
||||||
arv1beta1 "k8s.io/api/admissionregistration/v1beta1"
|
arv1beta1 "k8s.io/api/admissionregistration/v1beta1"
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/client-go/kubernetes"
|
|
||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,11 +22,11 @@ type WebhookConfig struct {
|
||||||
webhookServiceName string
|
webhookServiceName string
|
||||||
trustAnchor []byte
|
trustAnchor []byte
|
||||||
configTemplate *template.Template
|
configTemplate *template.Template
|
||||||
k8sAPI kubernetes.Interface
|
k8sAPI *k8s.API
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWebhookConfig returns a new instance of initiator.
|
// NewWebhookConfig returns a new instance of initiator.
|
||||||
func NewWebhookConfig(client kubernetes.Interface, controllerNamespace, webhookServiceName string, rootCA *tls.CA) (*WebhookConfig, error) {
|
func NewWebhookConfig(api *k8s.API, controllerNamespace, webhookServiceName string, rootCA *tls.CA) (*WebhookConfig, error) {
|
||||||
trustAnchor := rootCA.Cred.EncodeCertificatePEM()
|
trustAnchor := rootCA.Cred.EncodeCertificatePEM()
|
||||||
|
|
||||||
t := template.New(k8sPkg.ProxyInjectorWebhookConfig)
|
t := template.New(k8sPkg.ProxyInjectorWebhookConfig)
|
||||||
|
@ -36,7 +36,7 @@ func NewWebhookConfig(client kubernetes.Interface, controllerNamespace, webhookS
|
||||||
webhookServiceName: webhookServiceName,
|
webhookServiceName: webhookServiceName,
|
||||||
trustAnchor: []byte(trustAnchor),
|
trustAnchor: []byte(trustAnchor),
|
||||||
configTemplate: template.Must(t.Parse(tmpl.MutatingWebhookConfigurationSpec)),
|
configTemplate: template.Must(t.Parse(tmpl.MutatingWebhookConfigurationSpec)),
|
||||||
k8sAPI: client,
|
k8sAPI: api,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,15 +97,18 @@ func (w *WebhookConfig) create() (*arv1beta1.MutatingWebhookConfiguration, error
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return w.k8sAPI.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Create(&config)
|
return w.k8sAPI.Client.
|
||||||
|
AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Create(&config)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WebhookConfig) get() (*arv1beta1.MutatingWebhookConfiguration, error) {
|
func (w *WebhookConfig) get() (*arv1beta1.MutatingWebhookConfiguration, error) {
|
||||||
return w.k8sAPI.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().
|
return w.k8sAPI.Client.
|
||||||
|
AdmissionregistrationV1beta1().MutatingWebhookConfigurations().
|
||||||
Get(k8sPkg.ProxyInjectorWebhookConfig, metav1.GetOptions{})
|
Get(k8sPkg.ProxyInjectorWebhookConfig, metav1.GetOptions{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WebhookConfig) delete() error {
|
func (w *WebhookConfig) delete() error {
|
||||||
return w.k8sAPI.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Delete(
|
return w.k8sAPI.Client.
|
||||||
k8sPkg.ProxyInjectorWebhookConfig, &metav1.DeleteOptions{})
|
AdmissionregistrationV1beta1().MutatingWebhookConfigurations().
|
||||||
|
Delete(k8sPkg.ProxyInjectorWebhookConfig, &metav1.DeleteOptions{})
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/linkerd/linkerd2/controller/k8s"
|
||||||
"github.com/linkerd/linkerd2/controller/proxy-injector/fake"
|
"github.com/linkerd/linkerd2/controller/proxy-injector/fake"
|
||||||
"github.com/linkerd/linkerd2/pkg/tls"
|
"github.com/linkerd/linkerd2/pkg/tls"
|
||||||
)
|
)
|
||||||
|
@ -16,14 +17,17 @@ func TestCreate(t *testing.T) {
|
||||||
)
|
)
|
||||||
log.SetOutput(ioutil.Discard)
|
log.SetOutput(ioutil.Discard)
|
||||||
|
|
||||||
client := fake.NewClient("")
|
k8sAPI, err := k8s.NewFakeAPI()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewFakeAPI returned an error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
rootCA, err := tls.GenerateRootCAWithDefaults("Test CA")
|
rootCA, err := tls.GenerateRootCAWithDefaults("Test CA")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create root CA: %s", err)
|
t.Fatalf("failed to create root CA: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
webhookConfig, err := NewWebhookConfig(client, namespace, webhookServiceName, rootCA)
|
webhookConfig, err := NewWebhookConfig(k8sAPI, namespace, webhookServiceName, rootCA)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Unexpected error: ", err)
|
t.Fatal("Unexpected error: ", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"github.com/linkerd/linkerd2/controller/gen/config"
|
"github.com/linkerd/linkerd2/controller/gen/config"
|
||||||
"github.com/linkerd/linkerd2/controller/proxy-injector/fake"
|
"github.com/linkerd/linkerd2/controller/proxy-injector/fake"
|
||||||
"github.com/linkerd/linkerd2/pkg/inject"
|
"github.com/linkerd/linkerd2/pkg/inject"
|
||||||
"github.com/linkerd/linkerd2/pkg/k8s"
|
pkgK8s "github.com/linkerd/linkerd2/pkg/k8s"
|
||||||
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
@ -42,7 +42,7 @@ var (
|
||||||
func confNsEnabled() *inject.ResourceConfig {
|
func confNsEnabled() *inject.ResourceConfig {
|
||||||
return inject.
|
return inject.
|
||||||
NewResourceConfig(configs).
|
NewResourceConfig(configs).
|
||||||
WithNsAnnotations(map[string]string{k8s.ProxyInjectAnnotation: k8s.ProxyInjectEnabled})
|
WithNsAnnotations(map[string]string{pkgK8s.ProxyInjectAnnotation: pkgK8s.ProxyInjectEnabled})
|
||||||
}
|
}
|
||||||
|
|
||||||
func confNsDisabled() *inject.ResourceConfig {
|
func confNsDisabled() *inject.ResourceConfig {
|
||||||
|
|
|
@ -73,6 +73,10 @@ var injectableKinds = []string{
|
||||||
k8s.StatefulSet,
|
k8s.StatefulSet,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OwnerRetrieverFunc is a function that returns a pod's owner reference
|
||||||
|
// kind and name
|
||||||
|
type OwnerRetrieverFunc func(*v1.Pod) (string, string)
|
||||||
|
|
||||||
// ResourceConfig contains the parsed information for a given workload
|
// ResourceConfig contains the parsed information for a given workload
|
||||||
type ResourceConfig struct {
|
type ResourceConfig struct {
|
||||||
configs *config.All
|
configs *config.All
|
||||||
|
@ -80,6 +84,7 @@ type ResourceConfig struct {
|
||||||
destinationDNSOverride string
|
destinationDNSOverride string
|
||||||
identityDNSOverride string
|
identityDNSOverride string
|
||||||
proxyOutboundCapacity map[string]uint
|
proxyOutboundCapacity map[string]uint
|
||||||
|
ownerRetriever OwnerRetrieverFunc
|
||||||
|
|
||||||
workload struct {
|
workload struct {
|
||||||
obj runtime.Object
|
obj runtime.Object
|
||||||
|
@ -108,20 +113,6 @@ func NewResourceConfig(configs *config.All) *ResourceConfig {
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
// String satisfies the Stringer interface
|
|
||||||
func (conf *ResourceConfig) String() string {
|
|
||||||
l := []string{}
|
|
||||||
|
|
||||||
if conf.workload.metaType.Kind != "" {
|
|
||||||
l = append(l, conf.workload.metaType.Kind)
|
|
||||||
}
|
|
||||||
if conf.workload.meta != nil {
|
|
||||||
l = append(l, fmt.Sprintf("%s.%s", conf.workload.meta.GetName(), conf.workload.meta.GetNamespace()))
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Join(l, "/")
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithKind enriches ResourceConfig with the workload kind
|
// WithKind enriches ResourceConfig with the workload kind
|
||||||
func (conf *ResourceConfig) WithKind(kind string) *ResourceConfig {
|
func (conf *ResourceConfig) WithKind(kind string) *ResourceConfig {
|
||||||
conf.workload.metaType = metav1.TypeMeta{Kind: kind}
|
conf.workload.metaType = metav1.TypeMeta{Kind: kind}
|
||||||
|
@ -143,6 +134,13 @@ func (conf *ResourceConfig) WithProxyOutboundCapacity(m map[string]uint) *Resour
|
||||||
return conf
|
return conf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithOwnerRetriever enriches ResourceConfig with a function that allows to retrieve
|
||||||
|
// the kind and name of the workload's owner reference
|
||||||
|
func (conf *ResourceConfig) WithOwnerRetriever(f OwnerRetrieverFunc) *ResourceConfig {
|
||||||
|
conf.ownerRetriever = f
|
||||||
|
return conf
|
||||||
|
}
|
||||||
|
|
||||||
// YamlMarshalObj returns the yaml for the workload in conf
|
// YamlMarshalObj returns the yaml for the workload in conf
|
||||||
func (conf *ResourceConfig) YamlMarshalObj() ([]byte, error) {
|
func (conf *ResourceConfig) YamlMarshalObj() ([]byte, error) {
|
||||||
return yaml.Marshal(conf.workload.obj)
|
return yaml.Marshal(conf.workload.obj)
|
||||||
|
@ -158,7 +156,7 @@ func (conf *ResourceConfig) ParseMetaAndYaml(bytes []byte) (*Report, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseMeta extracts metadata from bytes.
|
// ParseMeta extracts metadata from bytes.
|
||||||
// It returns false if the workload's payload is empty
|
// It returns false if the workload's payload is empty.
|
||||||
func (conf *ResourceConfig) ParseMeta(bytes []byte) (bool, error) {
|
func (conf *ResourceConfig) ParseMeta(bytes []byte) (bool, error) {
|
||||||
if err := yaml.Unmarshal(bytes, &conf.workload.metaType); err != nil {
|
if err := yaml.Unmarshal(bytes, &conf.workload.metaType); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
|
@ -181,12 +179,7 @@ func (conf *ResourceConfig) GetPatch(
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var patch *Patch
|
patch := NewPatch(conf.workload.metaType.Kind)
|
||||||
if strings.ToLower(conf.workload.metaType.Kind) == k8s.Pod {
|
|
||||||
patch = NewPatchPod()
|
|
||||||
} else {
|
|
||||||
patch = NewPatchDeployment()
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we don't inject anything into the pod template then output the
|
// If we don't inject anything into the pod template then output the
|
||||||
// original serialization of the original object. Otherwise, output the
|
// original serialization of the original object. Otherwise, output the
|
||||||
|
@ -246,6 +239,8 @@ func (conf *ResourceConfig) JSONToYAML(bytes []byte) ([]byte, error) {
|
||||||
return yaml.Marshal(obj)
|
return yaml.Marshal(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parse parses the bytes payload, filling the gaps in ResourceConfig
|
||||||
|
// depending on the workload kind
|
||||||
func (conf *ResourceConfig) parse(bytes []byte) error {
|
func (conf *ResourceConfig) parse(bytes []byte) error {
|
||||||
// The Kubernetes API is versioned and each version has an API modeled
|
// The Kubernetes API is versioned and each version has an API modeled
|
||||||
// with its own distinct Go types. If we tell `yaml.Unmarshal()` which
|
// with its own distinct Go types. If we tell `yaml.Unmarshal()` which
|
||||||
|
@ -352,6 +347,24 @@ func (conf *ResourceConfig) parse(bytes []byte) error {
|
||||||
conf.workload.obj = v
|
conf.workload.obj = v
|
||||||
conf.pod.spec = &v.Spec
|
conf.pod.spec = &v.Spec
|
||||||
conf.pod.Meta = &v.ObjectMeta
|
conf.pod.Meta = &v.ObjectMeta
|
||||||
|
|
||||||
|
if conf.ownerRetriever != nil {
|
||||||
|
kind, name := conf.ownerRetriever(v)
|
||||||
|
switch kind {
|
||||||
|
case k8s.Deployment:
|
||||||
|
conf.pod.labels[k8s.ProxyDeploymentLabel] = name
|
||||||
|
case k8s.ReplicationController:
|
||||||
|
conf.pod.labels[k8s.ProxyReplicationControllerLabel] = name
|
||||||
|
case k8s.ReplicaSet:
|
||||||
|
conf.pod.labels[k8s.ProxyReplicaSetLabel] = name
|
||||||
|
case k8s.Job:
|
||||||
|
conf.pod.labels[k8s.ProxyJobLabel] = name
|
||||||
|
case k8s.DaemonSet:
|
||||||
|
conf.pod.labels[k8s.ProxyDaemonSetLabel] = name
|
||||||
|
case k8s.StatefulSet:
|
||||||
|
conf.pod.labels[k8s.ProxyStatefulSetLabel] = name
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -364,8 +377,9 @@ func (conf *ResourceConfig) complete(template *v1.PodTemplateSpec) {
|
||||||
|
|
||||||
// injectPodSpec adds linkerd sidecars to the provided PodSpec.
|
// injectPodSpec adds linkerd sidecars to the provided PodSpec.
|
||||||
func (conf *ResourceConfig) injectPodSpec(patch *Patch) {
|
func (conf *ResourceConfig) injectPodSpec(patch *Patch) {
|
||||||
|
saVolumeMount := conf.serviceAccountVolumeMount()
|
||||||
if !conf.configs.GetGlobal().GetCniEnabled() {
|
if !conf.configs.GetGlobal().GetCniEnabled() {
|
||||||
conf.injectProxyInit(patch)
|
conf.injectProxyInit(patch, saVolumeMount)
|
||||||
}
|
}
|
||||||
|
|
||||||
proxyUID := conf.proxyUID()
|
proxyUID := conf.proxyUID()
|
||||||
|
@ -455,6 +469,10 @@ func (conf *ResourceConfig) injectPodSpec(patch *Patch) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if saVolumeMount != nil {
|
||||||
|
sidecar.VolumeMounts = []v1.VolumeMount{*saVolumeMount}
|
||||||
|
}
|
||||||
|
|
||||||
idctx := conf.configs.GetGlobal().GetIdentityContext()
|
idctx := conf.configs.GetGlobal().GetIdentityContext()
|
||||||
if idctx == nil {
|
if idctx == nil {
|
||||||
sidecar.Env = append(sidecar.Env, v1.EnvVar{
|
sidecar.Env = append(sidecar.Env, v1.EnvVar{
|
||||||
|
@ -527,7 +545,7 @@ func (conf *ResourceConfig) injectPodSpec(patch *Patch) {
|
||||||
patch.addContainer(&sidecar)
|
patch.addContainer(&sidecar)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conf *ResourceConfig) injectProxyInit(patch *Patch) {
|
func (conf *ResourceConfig) injectProxyInit(patch *Patch, saVolumeMount *v1.VolumeMount) {
|
||||||
nonRoot := false
|
nonRoot := false
|
||||||
runAsUser := int64(0)
|
runAsUser := int64(0)
|
||||||
initContainer := &v1.Container{
|
initContainer := &v1.Container{
|
||||||
|
@ -545,12 +563,28 @@ func (conf *ResourceConfig) injectProxyInit(patch *Patch) {
|
||||||
RunAsUser: &runAsUser,
|
RunAsUser: &runAsUser,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
if saVolumeMount != nil {
|
||||||
|
initContainer.VolumeMounts = []v1.VolumeMount{*saVolumeMount}
|
||||||
|
}
|
||||||
if len(conf.pod.spec.InitContainers) == 0 {
|
if len(conf.pod.spec.InitContainers) == 0 {
|
||||||
patch.addInitContainerRoot()
|
patch.addInitContainerRoot()
|
||||||
}
|
}
|
||||||
patch.addInitContainer(initContainer)
|
patch.addInitContainer(initContainer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (conf *ResourceConfig) serviceAccountVolumeMount() *v1.VolumeMount {
|
||||||
|
// Probably always true, but wanna be super-safe
|
||||||
|
if containers := conf.pod.spec.Containers; len(containers) > 0 {
|
||||||
|
for _, vm := range containers[0].VolumeMounts {
|
||||||
|
if vm.MountPath == k8s.MountPathServiceAccount {
|
||||||
|
vm := vm // pin
|
||||||
|
return &vm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Given a ObjectMeta, update ObjectMeta in place with the new labels and
|
// Given a ObjectMeta, update ObjectMeta in place with the new labels and
|
||||||
// annotations.
|
// annotations.
|
||||||
func (conf *ResourceConfig) injectObjectMeta(patch *Patch) {
|
func (conf *ResourceConfig) injectObjectMeta(patch *Patch) {
|
||||||
|
@ -565,15 +599,13 @@ func (conf *ResourceConfig) injectObjectMeta(patch *Patch) {
|
||||||
patch.addPodAnnotation(k8s.IdentityModeAnnotation, k8s.IdentityModeDisabled)
|
patch.addPodAnnotation(k8s.IdentityModeAnnotation, k8s.IdentityModeDisabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range conf.pod.labels {
|
if len(conf.pod.labels) > 0 {
|
||||||
patch.addPodLabel(k, v)
|
if len(conf.pod.Meta.Labels) == 0 {
|
||||||
}
|
patch.addPodLabelsRoot()
|
||||||
}
|
}
|
||||||
|
for k, v := range conf.pod.labels {
|
||||||
// AddRootLabels adds all the pod labels into the root workload (e.g. Deployment)
|
patch.addPodLabel(k, v)
|
||||||
func (conf *ResourceConfig) AddRootLabels(patch *Patch) {
|
}
|
||||||
for k, v := range conf.pod.labels {
|
|
||||||
patch.addRootLabel(k, v)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -227,7 +227,7 @@ func TestConfigAccessors(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := resourceConfig.parse(data); err != nil {
|
if _, err := resourceConfig.ParseMetaAndYaml(data); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,21 @@ type Patch struct {
|
||||||
patchPathPodAnnotations string
|
patchPathPodAnnotations string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPatchDeployment returns a new instance of Patch for Deployment-like workloads
|
// NewPatch returns a new instance of Patch for any kind of workload kind
|
||||||
func NewPatchDeployment() *Patch {
|
func NewPatch(kind string) *Patch {
|
||||||
|
if strings.ToLower(kind) == k8s.Pod {
|
||||||
|
return &Patch{
|
||||||
|
patchOps: []*patchOp{},
|
||||||
|
patchPathContainer: "/spec/containers/-",
|
||||||
|
patchPathInitContainerRoot: "/spec/initContainers",
|
||||||
|
patchPathInitContainer: "/spec/initContainers/-",
|
||||||
|
patchPathVolumeRoot: "/spec/volumes",
|
||||||
|
patchPathVolume: "/spec/volumes/-",
|
||||||
|
patchPathPodLabels: patchPathRootLabels,
|
||||||
|
patchPathPodAnnotations: "/metadata/annotations",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &Patch{
|
return &Patch{
|
||||||
patchOps: []*patchOp{},
|
patchOps: []*patchOp{},
|
||||||
patchPathContainer: "/spec/template/spec/containers/-",
|
patchPathContainer: "/spec/template/spec/containers/-",
|
||||||
|
@ -38,20 +51,6 @@ func NewPatchDeployment() *Patch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPatchPod returns a new instance of Patch for Pod workloads
|
|
||||||
func NewPatchPod() *Patch {
|
|
||||||
return &Patch{
|
|
||||||
patchOps: []*patchOp{},
|
|
||||||
patchPathContainer: "/spec/containers/-",
|
|
||||||
patchPathInitContainerRoot: "/spec/initContainers",
|
|
||||||
patchPathInitContainer: "/spec/initContainers/-",
|
|
||||||
patchPathVolumeRoot: "/spec/volumes",
|
|
||||||
patchPathVolume: "/spec/volumes/-",
|
|
||||||
patchPathPodLabels: patchPathRootLabels,
|
|
||||||
patchPathPodAnnotations: "/metadata/annotations",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshal returns the patch as JSON
|
// Marshal returns the patch as JSON
|
||||||
func (p *Patch) Marshal() ([]byte, error) {
|
func (p *Patch) Marshal() ([]byte, error) {
|
||||||
return json.Marshal(p.patchOps)
|
return json.Marshal(p.patchOps)
|
||||||
|
@ -97,6 +96,15 @@ func (p *Patch) addVolume(volume *corev1.Volume) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Patch) addPodLabelsRoot() {
|
||||||
|
p.patchOps = append(p.patchOps, &patchOp{
|
||||||
|
Op: "add",
|
||||||
|
Path: p.patchPathPodLabels,
|
||||||
|
Value: map[string]string{},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddPodLabel appends the label with the provided key and value
|
||||||
func (p *Patch) addPodLabel(key, value string) {
|
func (p *Patch) addPodLabel(key, value string) {
|
||||||
p.patchOps = append(p.patchOps, &patchOp{
|
p.patchOps = append(p.patchOps, &patchOp{
|
||||||
Op: "add",
|
Op: "add",
|
||||||
|
@ -105,14 +113,6 @@ func (p *Patch) addPodLabel(key, value string) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Patch) addRootLabel(key, value string) {
|
|
||||||
p.patchOps = append(p.patchOps, &patchOp{
|
|
||||||
Op: "add",
|
|
||||||
Path: patchPathRootLabels + "/" + escapeKey(key),
|
|
||||||
Value: value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Patch) addPodAnnotationsRoot() {
|
func (p *Patch) addPodAnnotationsRoot() {
|
||||||
p.patchOps = append(p.patchOps, &patchOp{
|
p.patchOps = append(p.patchOps, &patchOp{
|
||||||
Op: "add",
|
Op: "add",
|
||||||
|
|
|
@ -13,11 +13,10 @@ import (
|
||||||
func TestPatch(t *testing.T) {
|
func TestPatch(t *testing.T) {
|
||||||
fixture := fake.NewFactory(filepath.Join("..", "..", "controller", "proxy-injector", "fake", "data"))
|
fixture := fake.NewFactory(filepath.Join("..", "..", "controller", "proxy-injector", "fake", "data"))
|
||||||
|
|
||||||
// TODO end entity volume
|
secrets, err := fixture.Volume("inject-linkerd-secrets-volume-spec.yaml")
|
||||||
// secrets, err := fixture.Volume("inject-linkerd-secrets-volume-spec.yaml")
|
if err != nil {
|
||||||
// if err != nil {
|
t.Fatal("Unexpected error: ", err)
|
||||||
// t.Fatal("Unexpected error: ", err)
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
sidecar, err := fixture.Container("inject-sidecar-container-spec.yaml")
|
sidecar, err := fixture.Container("inject-sidecar-container-spec.yaml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -34,22 +33,22 @@ func TestPatch(t *testing.T) {
|
||||||
createdBy = "linkerd/cli v18.8.4"
|
createdBy = "linkerd/cli v18.8.4"
|
||||||
)
|
)
|
||||||
|
|
||||||
actual := NewPatchDeployment()
|
actual := NewPatch(k8sPkg.Deployment)
|
||||||
actual.addContainer(sidecar)
|
actual.addContainer(sidecar)
|
||||||
actual.addInitContainerRoot()
|
actual.addInitContainerRoot()
|
||||||
actual.addInitContainer(init)
|
actual.addInitContainer(init)
|
||||||
//actual.addVolumeRoot()
|
actual.addVolumeRoot()
|
||||||
//actual.addVolume(secrets)
|
actual.addVolume(secrets)
|
||||||
actual.addPodLabel(k8sPkg.ControllerNSLabel, controllerNamespace)
|
actual.addPodLabel(k8sPkg.ControllerNSLabel, controllerNamespace)
|
||||||
actual.addPodAnnotation(k8sPkg.CreatedByAnnotation, createdBy)
|
actual.addPodAnnotation(k8sPkg.CreatedByAnnotation, createdBy)
|
||||||
|
|
||||||
expected := NewPatchDeployment()
|
expected := NewPatch(k8sPkg.Deployment)
|
||||||
expected.patchOps = []*patchOp{
|
expected.patchOps = []*patchOp{
|
||||||
{Op: "add", Path: expected.patchPathContainer, Value: sidecar},
|
{Op: "add", Path: expected.patchPathContainer, Value: sidecar},
|
||||||
{Op: "add", Path: expected.patchPathInitContainerRoot, Value: []*v1.Container{}},
|
{Op: "add", Path: expected.patchPathInitContainerRoot, Value: []*v1.Container{}},
|
||||||
{Op: "add", Path: expected.patchPathInitContainer, Value: init},
|
{Op: "add", Path: expected.patchPathInitContainer, Value: init},
|
||||||
//{Op: "add", Path: expected.patchPathVolumeRoot, Value: []*v1.Volume{}},
|
{Op: "add", Path: expected.patchPathVolumeRoot, Value: []*v1.Volume{}},
|
||||||
//{Op: "add", Path: expected.patchPathVolume, Value: secrets},
|
{Op: "add", Path: expected.patchPathVolume, Value: secrets},
|
||||||
{Op: "add", Path: expected.patchPathPodLabels + "/" + escapeKey(k8sPkg.ControllerNSLabel), Value: controllerNamespace},
|
{Op: "add", Path: expected.patchPathPodLabels + "/" + escapeKey(k8sPkg.ControllerNSLabel), Value: controllerNamespace},
|
||||||
{Op: "add", Path: expected.patchPathPodAnnotations + "/" + escapeKey(k8sPkg.CreatedByAnnotation), Value: createdBy},
|
{Op: "add", Path: expected.patchPathPodAnnotations + "/" + escapeKey(k8sPkg.CreatedByAnnotation), Value: createdBy},
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,11 @@ func newReport(conf *ResourceConfig) Report {
|
||||||
var name string
|
var name string
|
||||||
if m := conf.pod.Meta; m != nil {
|
if m := conf.pod.Meta; m != nil {
|
||||||
name = m.Name
|
name = m.Name
|
||||||
|
if name == "" {
|
||||||
|
name = m.GenerateName
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Report{
|
return Report{
|
||||||
Kind: strings.ToLower(conf.workload.metaType.Kind),
|
Kind: strings.ToLower(conf.workload.metaType.Kind),
|
||||||
Name: name,
|
Name: name,
|
||||||
|
@ -35,13 +39,13 @@ func newReport(conf *ResourceConfig) Report {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResName returns a string "Kind/Name" for the workload referred in the report r
|
// ResName returns a string "Kind/Name" for the workload referred in the report r
|
||||||
func (r Report) ResName() string {
|
func (r *Report) ResName() string {
|
||||||
return fmt.Sprintf("%s/%s", r.Kind, r.Name)
|
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
|
// 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
|
// or there is already a sidecar or the resource is not supported or inject is explicitly disabled
|
||||||
func (r Report) Injectable() bool {
|
func (r *Report) Injectable() bool {
|
||||||
return !r.HostNetwork && !r.Sidecar && !r.UnsupportedResource && !r.InjectDisabled
|
return !r.HostNetwork && !r.Sidecar && !r.UnsupportedResource && !r.InjectDisabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -190,6 +190,10 @@ const (
|
||||||
// MountPathBase is the base directory of the mount path.
|
// MountPathBase is the base directory of the mount path.
|
||||||
MountPathBase = "/var/run/linkerd"
|
MountPathBase = "/var/run/linkerd"
|
||||||
|
|
||||||
|
// MountPathServiceAccount is the default path where Kuberenetes stores
|
||||||
|
// the service account token
|
||||||
|
MountPathServiceAccount = "/var/run/secrets/kubernetes.io/serviceaccount"
|
||||||
|
|
||||||
// MountPathGlobalConfig is the path at which the global config file is mounted.
|
// MountPathGlobalConfig is the path at which the global config file is mounted.
|
||||||
MountPathGlobalConfig = MountPathBase + "/config/global"
|
MountPathGlobalConfig = MountPathBase + "/config/global"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue