From 38fb23f120ef981f01be18bc0c9f9e1d74e2dbc3 Mon Sep 17 00:00:00 2001 From: Irbe Krumina Date: Mon, 15 Apr 2024 17:24:59 +0100 Subject: [PATCH] cmd/k8s-operator,k8s-operator: allow users to configure proxy env vars via ProxyClass (#11743) Adds new ProxyClass.spec.statefulSet.pod.{tailscaleContainer,tailscaleInitContainer}.Env field that allow users to provide key, value pairs that will be set as env vars for the respective containers. Allow overriding all containerboot env vars, but warn that this is not supported and might break (in docs + a warning when validating ProxyClass). Updates tailscale/tailscale#10709 Signed-off-by: Irbe Krumina --- .../crds/tailscale.com_proxyclasses.yaml | 30 +++++++ .../deploy/manifests/operator.yaml | 30 +++++++ cmd/k8s-operator/proxyclass.go | 16 ++++ cmd/k8s-operator/proxyclass_test.go | 23 +++++- cmd/k8s-operator/sts.go | 9 ++ cmd/k8s-operator/sts_test.go | 5 ++ cmd/k8s-operator/testutils_test.go | 29 +++++++ k8s-operator/api.md | 82 +++++++++++++++++++ .../apis/v1alpha1/types_proxyclass.go | 28 +++++++ .../apis/v1alpha1/zz_generated.deepcopy.go | 20 +++++ 10 files changed, 268 insertions(+), 4 deletions(-) diff --git a/cmd/k8s-operator/deploy/crds/tailscale.com_proxyclasses.yaml b/cmd/k8s-operator/deploy/crds/tailscale.com_proxyclasses.yaml index 83504f4c0..e72c9ccc0 100644 --- a/cmd/k8s-operator/deploy/crds/tailscale.com_proxyclasses.yaml +++ b/cmd/k8s-operator/deploy/crds/tailscale.com_proxyclasses.yaml @@ -177,6 +177,21 @@ spec: description: Configuration for the proxy container running tailscale. type: object properties: + env: + description: List of environment variables to set in the container. https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#environment-variables Note that environment variables provided here will take precedence over Tailscale-specific environment variables set by the operator, however running proxies with custom values for Tailscale environment variables (i.e TS_USERSPACE) is not recommended and might break in the future. + type: array + items: + type: object + required: + - name + properties: + name: + description: Name of the environment variable. Must be a C_IDENTIFIER. + type: string + pattern: ^[-._a-zA-Z][-._a-zA-Z0-9]*$ + value: + description: 'Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "".' + type: string resources: description: Container resource requirements. By default Tailscale Kubernetes operator does not apply any resource requirements. The amount of resources required wil depend on the amount of resources the operator needs to parse, usage patterns and cluster size. https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#resources type: object @@ -305,6 +320,21 @@ spec: description: Configuration for the proxy init container that enables forwarding. type: object properties: + env: + description: List of environment variables to set in the container. https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#environment-variables Note that environment variables provided here will take precedence over Tailscale-specific environment variables set by the operator, however running proxies with custom values for Tailscale environment variables (i.e TS_USERSPACE) is not recommended and might break in the future. + type: array + items: + type: object + required: + - name + properties: + name: + description: Name of the environment variable. Must be a C_IDENTIFIER. + type: string + pattern: ^[-._a-zA-Z][-._a-zA-Z0-9]*$ + value: + description: 'Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "".' + type: string resources: description: Container resource requirements. By default Tailscale Kubernetes operator does not apply any resource requirements. The amount of resources required wil depend on the amount of resources the operator needs to parse, usage patterns and cluster size. https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#resources type: object diff --git a/cmd/k8s-operator/deploy/manifests/operator.yaml b/cmd/k8s-operator/deploy/manifests/operator.yaml index 62e444f82..0ef72b91c 100644 --- a/cmd/k8s-operator/deploy/manifests/operator.yaml +++ b/cmd/k8s-operator/deploy/manifests/operator.yaml @@ -326,6 +326,21 @@ spec: tailscaleContainer: description: Configuration for the proxy container running tailscale. properties: + env: + description: List of environment variables to set in the container. https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#environment-variables Note that environment variables provided here will take precedence over Tailscale-specific environment variables set by the operator, however running proxies with custom values for Tailscale environment variables (i.e TS_USERSPACE) is not recommended and might break in the future. + items: + properties: + name: + description: Name of the environment variable. Must be a C_IDENTIFIER. + pattern: ^[-._a-zA-Z][-._a-zA-Z0-9]*$ + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "".' + type: string + required: + - name + type: object + type: array resources: description: Container resource requirements. By default Tailscale Kubernetes operator does not apply any resource requirements. The amount of resources required wil depend on the amount of resources the operator needs to parse, usage patterns and cluster size. https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#resources properties: @@ -454,6 +469,21 @@ spec: tailscaleInitContainer: description: Configuration for the proxy init container that enables forwarding. properties: + env: + description: List of environment variables to set in the container. https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#environment-variables Note that environment variables provided here will take precedence over Tailscale-specific environment variables set by the operator, however running proxies with custom values for Tailscale environment variables (i.e TS_USERSPACE) is not recommended and might break in the future. + items: + properties: + name: + description: Name of the environment variable. Must be a C_IDENTIFIER. + pattern: ^[-._a-zA-Z][-._a-zA-Z0-9]*$ + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "".' + type: string + required: + - name + type: object + type: array resources: description: Container resource requirements. By default Tailscale Kubernetes operator does not apply any resource requirements. The amount of resources required wil depend on the amount of resources the operator needs to parse, usage patterns and cluster size. https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#resources properties: diff --git a/cmd/k8s-operator/proxyclass.go b/cmd/k8s-operator/proxyclass.go index 74ed71e6b..0cb653477 100644 --- a/cmd/k8s-operator/proxyclass.go +++ b/cmd/k8s-operator/proxyclass.go @@ -10,6 +10,7 @@ package main import ( "context" "fmt" + "strings" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" @@ -30,7 +31,9 @@ import ( const ( reasonProxyClassInvalid = "ProxyClassInvalid" reasonProxyClassValid = "ProxyClassValid" + reasonCustomTSEnvVar = "CustomTSEnvVar" messageProxyClassInvalid = "ProxyClass is not valid: %v" + messageCustomTSEnvVar = "ProxyClass overrides the default value for %s env var for %s container. Running with custom values for Tailscale env vars is not recommended and might break in the future." ) type ProxyClassReconciler struct { @@ -98,6 +101,19 @@ func (a *ProxyClassReconciler) validate(pc *tsapi.ProxyClass) (violations field. violations = append(violations, errs...) } } + if tc := pod.TailscaleContainer; tc != nil { + for _, e := range tc.Env { + if strings.HasPrefix(string(e.Name), "TS_") { + a.recorder.Event(pc, corev1.EventTypeWarning, reasonCustomTSEnvVar, fmt.Sprintf(messageCustomTSEnvVar, string(e.Name), "tailscale")) + } + if strings.EqualFold(string(e.Name), "EXPERIMENTAL_TS_CONFIGFILE_PATH") { + a.recorder.Event(pc, corev1.EventTypeWarning, reasonCustomTSEnvVar, fmt.Sprintf(messageCustomTSEnvVar, string(e.Name), "tailscale")) + } + if strings.EqualFold(string(e.Name), "EXPERIMENTAL_ALLOW_PROXYING_CLUSTER_TRAFFIC_VIA_INGRESS") { + a.recorder.Event(pc, corev1.EventTypeWarning, reasonCustomTSEnvVar, fmt.Sprintf(messageCustomTSEnvVar, string(e.Name), "tailscale")) + } + } + } } } // We do not validate embedded fields (security context, resource diff --git a/cmd/k8s-operator/proxyclass_test.go b/cmd/k8s-operator/proxyclass_test.go index 70b92f29d..4cc4f7844 100644 --- a/cmd/k8s-operator/proxyclass_test.go +++ b/cmd/k8s-operator/proxyclass_test.go @@ -36,8 +36,9 @@ func TestProxyClass(t *testing.T) { Labels: map[string]string{"foo": "bar", "xyz1234": "abc567"}, Annotations: map[string]string{"foo.io/bar": "{'key': 'val1232'}"}, Pod: &tsapi.Pod{ - Labels: map[string]string{"foo": "bar", "xyz1234": "abc567"}, - Annotations: map[string]string{"foo.io/bar": "{'key': 'val1232'}"}, + Labels: map[string]string{"foo": "bar", "xyz1234": "abc567"}, + Annotations: map[string]string{"foo.io/bar": "{'key': 'val1232'}"}, + TailscaleContainer: &tsapi.Container{Env: []tsapi.Env{{Name: "FOO", Value: "BAR"}}}, }, }, }, @@ -51,16 +52,17 @@ func TestProxyClass(t *testing.T) { if err != nil { t.Fatal(err) } + fr := record.NewFakeRecorder(3) // bump this if you expect a test case to throw more events cl := tstest.NewClock(tstest.ClockOpts{}) pcr := &ProxyClassReconciler{ Client: fc, logger: zl.Sugar(), clock: cl, - recorder: record.NewFakeRecorder(1), + recorder: fr, } - expectReconciled(t, pcr, "", "test") // 1. A valid ProxyClass resource gets its status updated to Ready. + expectReconciled(t, pcr, "", "test") pc.Status.Conditions = append(pc.Status.Conditions, tsapi.ConnectorCondition{ Type: tsapi.ProxyClassready, Status: metav1.ConditionTrue, @@ -80,4 +82,17 @@ func TestProxyClass(t *testing.T) { msg := `ProxyClass is not valid: .spec.statefulSet.labels: Invalid value: "?!someVal": a valid label must be an empty string or consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyValue', or 'my_value', or '12345', regex used for validation is '(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?')` tsoperator.SetProxyClassCondition(pc, tsapi.ProxyClassready, metav1.ConditionFalse, reasonProxyClassInvalid, msg, 0, cl, zl.Sugar()) expectEqual(t, fc, pc, nil) + expectedEvent := "Warning ProxyClassInvalid ProxyClass is not valid: .spec.statefulSet.labels: Invalid value: \"?!someVal\": a valid label must be an empty string or consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyValue', or 'my_value', or '12345', regex used for validation is '(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?')" + expectEvents(t, fr, []string{expectedEvent}) + + // 2. An valid ProxyClass but with a Tailscale env vars set results in warning events. + mustUpdate(t, fc, "", "test", func(proxyClass *tsapi.ProxyClass) { + proxyClass.Spec.StatefulSet.Labels = nil // unset invalid labels from the previous test + proxyClass.Spec.StatefulSet.Pod.TailscaleContainer.Env = []tsapi.Env{{Name: "TS_USERSPACE", Value: "true"}, {Name: "EXPERIMENTAL_TS_CONFIGFILE_PATH"}, {Name: "EXPERIMENTAL_ALLOW_PROXYING_CLUSTER_TRAFFIC_VIA_INGRESS"}} + }) + expectedEvents := []string{"Warning CustomTSEnvVar ProxyClass overrides the default value for TS_USERSPACE env var for tailscale container. Running with custom values for Tailscale env vars is not recommended and might break in the future.", + "Warning CustomTSEnvVar ProxyClass overrides the default value for EXPERIMENTAL_TS_CONFIGFILE_PATH env var for tailscale container. Running with custom values for Tailscale env vars is not recommended and might break in the future.", + "Warning CustomTSEnvVar ProxyClass overrides the default value for EXPERIMENTAL_ALLOW_PROXYING_CLUSTER_TRAFFIC_VIA_INGRESS env var for tailscale container. Running with custom values for Tailscale env vars is not recommended and might break in the future."} + expectReconciled(t, pcr, "", "test") + expectEvents(t, fr, expectedEvents) } diff --git a/cmd/k8s-operator/sts.go b/cmd/k8s-operator/sts.go index 67cae4393..4c800cdbb 100644 --- a/cmd/k8s-operator/sts.go +++ b/cmd/k8s-operator/sts.go @@ -644,6 +644,15 @@ func applyProxyClassToStatefulSet(pc *tsapi.ProxyClass, ss *appsv1.StatefulSet) base.SecurityContext = overlay.SecurityContext } base.Resources = overlay.Resources + for _, e := range overlay.Env { + // Env vars configured via ProxyClass might override env + // vars that have been specified by the operator, i.e + // TS_USERSPACE. The intended behaviour is to allow this + // and in practice it works without explicitly removing + // the operator configured value here as a later value + // in the env var list overrides an earlier one. + base.Env = append(base.Env, corev1.EnvVar{Name: string(e.Name), Value: e.Value}) + } return base } for i, c := range ss.Spec.Template.Spec.Containers { diff --git a/cmd/k8s-operator/sts_test.go b/cmd/k8s-operator/sts_test.go index 94c42e8f8..29c8a24fb 100644 --- a/cmd/k8s-operator/sts_test.go +++ b/cmd/k8s-operator/sts_test.go @@ -75,6 +75,7 @@ func Test_applyProxyClassToStatefulSet(t *testing.T) { Limits: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("1000m"), corev1.ResourceMemory: resource.MustParse("128Mi")}, Requests: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("500m"), corev1.ResourceMemory: resource.MustParse("64Mi")}, }, + Env: []tsapi.Env{{Name: "foo", Value: "bar"}, {Name: "TS_USERSPACE", Value: "true"}, {Name: "bar"}}, }, TailscaleInitContainer: &tsapi.Container{ SecurityContext: &corev1.SecurityContext{ @@ -85,6 +86,7 @@ func Test_applyProxyClassToStatefulSet(t *testing.T) { Limits: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("1000m"), corev1.ResourceMemory: resource.MustParse("128Mi")}, Requests: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("500m"), corev1.ResourceMemory: resource.MustParse("64Mi")}, }, + Env: []tsapi.Env{{Name: "foo", Value: "bar"}, {Name: "TS_USERSPACE", Value: "true"}, {Name: "bar"}}, }, }, }, @@ -142,6 +144,8 @@ func Test_applyProxyClassToStatefulSet(t *testing.T) { wantSS.Spec.Template.Spec.InitContainers[0].SecurityContext = proxyClassAllOpts.Spec.StatefulSet.Pod.TailscaleInitContainer.SecurityContext wantSS.Spec.Template.Spec.Containers[0].Resources = proxyClassAllOpts.Spec.StatefulSet.Pod.TailscaleContainer.Resources wantSS.Spec.Template.Spec.InitContainers[0].Resources = proxyClassAllOpts.Spec.StatefulSet.Pod.TailscaleInitContainer.Resources + wantSS.Spec.Template.Spec.InitContainers[0].Env = append(wantSS.Spec.Template.Spec.InitContainers[0].Env, []corev1.EnvVar{{Name: "foo", Value: "bar"}, {Name: "TS_USERSPACE", Value: "true"}, {Name: "bar"}}...) + wantSS.Spec.Template.Spec.Containers[0].Env = append(wantSS.Spec.Template.Spec.Containers[0].Env, []corev1.EnvVar{{Name: "foo", Value: "bar"}, {Name: "TS_USERSPACE", Value: "true"}, {Name: "bar"}}...) gotSS := applyProxyClassToStatefulSet(proxyClassAllOpts, nonUserspaceProxySS.DeepCopy()) if diff := cmp.Diff(gotSS, wantSS); diff != "" { @@ -175,6 +179,7 @@ func Test_applyProxyClassToStatefulSet(t *testing.T) { wantSS.Spec.Template.Spec.Tolerations = proxyClassAllOpts.Spec.StatefulSet.Pod.Tolerations wantSS.Spec.Template.Spec.Containers[0].SecurityContext = proxyClassAllOpts.Spec.StatefulSet.Pod.TailscaleContainer.SecurityContext wantSS.Spec.Template.Spec.Containers[0].Resources = proxyClassAllOpts.Spec.StatefulSet.Pod.TailscaleContainer.Resources + wantSS.Spec.Template.Spec.Containers[0].Env = append(wantSS.Spec.Template.Spec.Containers[0].Env, []corev1.EnvVar{{Name: "foo", Value: "bar"}, {Name: "TS_USERSPACE", Value: "true"}, {Name: "bar"}}...) gotSS = applyProxyClassToStatefulSet(proxyClassAllOpts, userspaceProxySS.DeepCopy()) if diff := cmp.Diff(gotSS, wantSS); diff != "" { t.Fatalf("Unexpected result applying ProxyClass with custom labels and annotations to a StatefulSet for a userspace proxy (-got +want):\n%s", diff) diff --git a/cmd/k8s-operator/testutils_test.go b/cmd/k8s-operator/testutils_test.go index 767ab2e0c..c9377cfad 100644 --- a/cmd/k8s-operator/testutils_test.go +++ b/cmd/k8s-operator/testutils_test.go @@ -20,6 +20,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/tools/record" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" "tailscale.com/client/tailscale" @@ -515,6 +516,34 @@ func expectRequeue(t *testing.T, sr reconcile.Reconciler, ns, name string) { } } +// expectEvents accepts a test recorder and a list of events, tests that expected +// events are sent down the recorder's channel. Waits for 5s for each event. +func expectEvents(t *testing.T, rec *record.FakeRecorder, wantsEvents []string) { + t.Helper() + // Events are not expected to arrive in order. + seenEvents := make([]string, 0) + for i := 0; i < len(wantsEvents); i++ { + timer := time.NewTimer(time.Second * 5) + defer timer.Stop() + select { + case gotEvent := <-rec.Events: + found := false + for _, wantEvent := range wantsEvents { + if wantEvent == gotEvent { + found = true + seenEvents = append(seenEvents, gotEvent) + break + } + } + if !found { + t.Errorf("got unexpected event %q, expected events: %+#v", gotEvent, wantsEvents) + } + case <-timer.C: + t.Errorf("timeout waiting for an event, wants events %#+v, got events %+#v", wantsEvents, seenEvents) + } + } +} + type fakeTSClient struct { sync.Mutex keyRequests []tailscale.KeyCapabilities diff --git a/k8s-operator/api.md b/k8s-operator/api.md index e2cd47c25..f0026b3af 100644 --- a/k8s-operator/api.md +++ b/k8s-operator/api.md @@ -771,6 +771,13 @@ Configuration for the proxy container running tailscale. + env + []object + + List of environment variables to set in the container. https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#environment-variables Note that environment variables provided here will take precedence over Tailscale-specific environment variables set by the operator, however running proxies with custom values for Tailscale environment variables (i.e TS_USERSPACE) is not recommended and might break in the future.
+ + false + resources object @@ -788,6 +795,40 @@ Configuration for the proxy container running tailscale. +### ProxyClass.spec.statefulSet.pod.tailscaleContainer.env[index] +[↩ Parent](#proxyclassspecstatefulsetpodtailscalecontainer) + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
namestring + Name of the environment variable. Must be a C_IDENTIFIER.
+
true
valuestring + Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "".
+
false
+ + ### ProxyClass.spec.statefulSet.pod.tailscaleContainer.resources [↩ Parent](#proxyclassspecstatefulsetpodtailscalecontainer) @@ -1141,6 +1182,13 @@ Configuration for the proxy init container that enables forwarding. + env + []object + + List of environment variables to set in the container. https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#environment-variables Note that environment variables provided here will take precedence over Tailscale-specific environment variables set by the operator, however running proxies with custom values for Tailscale environment variables (i.e TS_USERSPACE) is not recommended and might break in the future.
+ + false + resources object @@ -1158,6 +1206,40 @@ Configuration for the proxy init container that enables forwarding. +### ProxyClass.spec.statefulSet.pod.tailscaleInitContainer.env[index] +[↩ Parent](#proxyclassspecstatefulsetpodtailscaleinitcontainer) + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
namestring + Name of the environment variable. Must be a C_IDENTIFIER.
+
true
valuestring + Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "".
+
false
+ + ### ProxyClass.spec.statefulSet.pod.tailscaleInitContainer.resources [↩ Parent](#proxyclassspecstatefulsetpodtailscaleinitcontainer) diff --git a/k8s-operator/apis/v1alpha1/types_proxyclass.go b/k8s-operator/apis/v1alpha1/types_proxyclass.go index 98d7b5753..077e792a7 100644 --- a/k8s-operator/apis/v1alpha1/types_proxyclass.go +++ b/k8s-operator/apis/v1alpha1/types_proxyclass.go @@ -131,8 +131,36 @@ type Container struct { // https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#resources // +optional Resources corev1.ResourceRequirements `json:"resources,omitempty"` + // List of environment variables to set in the container. + // https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#environment-variables + // Note that environment variables provided here will take precedence + // over Tailscale-specific environment variables set by the operator, + // however running proxies with custom values for Tailscale environment + // variables (i.e TS_USERSPACE) is not recommended and might break in + // the future. + // +optional + Env []Env `json:"env,omitempty"` } +type Env struct { + // Name of the environment variable. Must be a C_IDENTIFIER. + Name Name `json:"name"` + // Variable references $(VAR_NAME) are expanded using the previously defined + // environment variables in the container and any service environment + // variables. If a variable cannot be resolved, the reference in the input + // string will be unchanged. Double $$ are reduced to a single $, which + // allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + // produce the string literal "$(VAR_NAME)". Escaped references will never + // be expanded, regardless of whether the variable exists or not. Defaults + // to "". + // +optional + Value string `json:"value,omitempty"` +} + +// +kubebuilder:validation:Type=string +// +kubebuilder:validation:Pattern=`^[-._a-zA-Z][-._a-zA-Z0-9]*$` +type Name string + type ProxyClassStatus struct { // List of status conditions to indicate the status of the ProxyClass. // Known condition types are `ProxyClassReady`. diff --git a/k8s-operator/apis/v1alpha1/zz_generated.deepcopy.go b/k8s-operator/apis/v1alpha1/zz_generated.deepcopy.go index efd202eee..fd14fe2ae 100644 --- a/k8s-operator/apis/v1alpha1/zz_generated.deepcopy.go +++ b/k8s-operator/apis/v1alpha1/zz_generated.deepcopy.go @@ -146,6 +146,11 @@ func (in *Container) DeepCopyInto(out *Container) { (*in).DeepCopyInto(*out) } in.Resources.DeepCopyInto(&out.Resources) + if in.Env != nil { + in, out := &in.Env, &out.Env + *out = make([]Env, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Container. @@ -158,6 +163,21 @@ func (in *Container) DeepCopy() *Container { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Env) DeepCopyInto(out *Env) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Env. +func (in *Env) DeepCopy() *Env { + if in == nil { + return nil + } + out := new(Env) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Pod) DeepCopyInto(out *Pod) { *out = *in