From d6dfb7f242b91cac34f70cce654c0a61daf247ea Mon Sep 17 00:00:00 2001 From: Irbe Krumina Date: Sun, 8 Sep 2024 21:06:07 +0300 Subject: [PATCH] kube,cmd/{k8s-operator,containerboot},envknob,ipn/store/kubestore,*/depaware.txt: split out kube types (#13417) Further split kube package into kube/{client,api,types}. This is so that consumers who only need constants/static types don't have to import the client and api bits. Updates#cleanup Signed-off-by: Irbe Krumina --- cmd/containerboot/kube.go | 21 ++++++------ cmd/containerboot/kube_test.go | 53 +++++++++++++++--------------- cmd/derper/depaware.txt | 2 +- cmd/k8s-operator/connector.go | 8 ++--- cmd/k8s-operator/connector_test.go | 8 ++--- cmd/k8s-operator/depaware.txt | 4 ++- cmd/k8s-operator/ingress.go | 4 +-- cmd/k8s-operator/ingress_test.go | 6 ++-- cmd/k8s-operator/nameserver.go | 4 +-- cmd/k8s-operator/operator.go | 6 ++-- cmd/k8s-operator/operator_test.go | 28 ++++++++-------- cmd/k8s-operator/proxy.go | 8 ++--- cmd/k8s-operator/sts.go | 10 +++--- cmd/k8s-operator/svc.go | 6 ++-- cmd/stund/depaware.txt | 5 ++- cmd/tailscale/depaware.txt | 2 +- cmd/tailscaled/depaware.txt | 4 ++- envknob/envknob.go | 4 +-- ipn/store/kubestore/store_kube.go | 21 ++++++------ kube/{ => api}/api.go | 6 +++- kube/{ => client}/client.go | 32 ++++++++++-------- kube/{ => client}/fake_client.go | 14 ++++---- kube/{ => types}/grants.go | 7 +++- kube/{ => types}/metrics.go | 2 +- 24 files changed, 143 insertions(+), 122 deletions(-) rename kube/{ => api}/api.go (96%) rename kube/{ => client}/client.go (89%) rename kube/{ => client}/fake_client.go (68%) rename kube/{ => types}/grants.go (89%) rename kube/{ => types}/metrics.go (98%) diff --git a/cmd/containerboot/kube.go b/cmd/containerboot/kube.go index 0415f7d02..251256293 100644 --- a/cmd/containerboot/kube.go +++ b/cmd/containerboot/kube.go @@ -15,14 +15,15 @@ import ( "net/netip" "os" - "tailscale.com/kube" + kubeapi "tailscale.com/kube/api" + kubeclient "tailscale.com/kube/client" "tailscale.com/tailcfg" ) // storeDeviceID writes deviceID to 'device_id' data field of the named // Kubernetes Secret. func storeDeviceID(ctx context.Context, secretName string, deviceID tailcfg.StableNodeID) error { - s := &kube.Secret{ + s := &kubeapi.Secret{ Data: map[string][]byte{ "device_id": []byte(deviceID), }, @@ -42,7 +43,7 @@ func storeDeviceEndpoints(ctx context.Context, secretName string, fqdn string, a return err } - s := &kube.Secret{ + s := &kubeapi.Secret{ Data: map[string][]byte{ "device_fqdn": []byte(fqdn), "device_ips": deviceIPs, @@ -55,14 +56,14 @@ func storeDeviceEndpoints(ctx context.Context, secretName string, fqdn string, a // secret. No-op if there is no authkey in the secret. func deleteAuthKey(ctx context.Context, secretName string) error { // m is a JSON Patch data structure, see https://jsonpatch.com/ or RFC 6902. - m := []kube.JSONPatch{ + m := []kubeclient.JSONPatch{ { Op: "remove", Path: "/data/authkey", }, } if err := kc.JSONPatchSecret(ctx, secretName, m); err != nil { - if s, ok := err.(*kube.Status); ok && s.Code == http.StatusUnprocessableEntity { + if s, ok := err.(*kubeapi.Status); ok && s.Code == http.StatusUnprocessableEntity { // This is kubernetes-ese for "the field you asked to // delete already doesn't exist", aka no-op. return nil @@ -72,7 +73,7 @@ func deleteAuthKey(ctx context.Context, secretName string) error { return nil } -var kc kube.Client +var kc kubeclient.Client // setupKube is responsible for doing any necessary configuration and checks to // ensure that tailscale state storage and authentication mechanism will work on @@ -88,12 +89,12 @@ func (cfg *settings) setupKube(ctx context.Context) error { cfg.KubernetesCanPatch = canPatch s, err := kc.GetSecret(ctx, cfg.KubeSecret) - if err != nil && kube.IsNotFoundErr(err) && !canCreate { + if err != nil && kubeclient.IsNotFoundErr(err) && !canCreate { return fmt.Errorf("Tailscale state Secret %s does not exist and we don't have permissions to create it. "+ "If you intend to store tailscale state elsewhere than a Kubernetes Secret, "+ "you can explicitly set TS_KUBE_SECRET env var to an empty string. "+ "Else ensure that RBAC is set up that allows the service account associated with this installation to create Secrets.", cfg.KubeSecret) - } else if err != nil && !kube.IsNotFoundErr(err) { + } else if err != nil && !kubeclient.IsNotFoundErr(err) { return fmt.Errorf("Getting Tailscale state Secret %s: %v", cfg.KubeSecret, err) } @@ -128,10 +129,10 @@ func initKubeClient(root string) { if root != "/" { // If we are running in a test, we need to set the root path to the fake // service account directory. - kube.SetRootPathForTesting(root) + kubeclient.SetRootPathForTesting(root) } var err error - kc, err = kube.New() + kc, err = kubeclient.New() if err != nil { log.Fatalf("Error creating kube client: %v", err) } diff --git a/cmd/containerboot/kube_test.go b/cmd/containerboot/kube_test.go index 1f030959f..1b9f9b3c8 100644 --- a/cmd/containerboot/kube_test.go +++ b/cmd/containerboot/kube_test.go @@ -11,7 +11,8 @@ import ( "testing" "github.com/google/go-cmp/cmp" - "tailscale.com/kube" + kubeapi "tailscale.com/kube/api" + kubeclient "tailscale.com/kube/client" ) func TestSetupKube(t *testing.T) { @@ -20,7 +21,7 @@ func TestSetupKube(t *testing.T) { cfg *settings wantErr bool wantCfg *settings - kc kube.Client + kc kubeclient.Client }{ { name: "TS_AUTHKEY set, state Secret exists", @@ -28,11 +29,11 @@ func TestSetupKube(t *testing.T) { AuthKey: "foo", KubeSecret: "foo", }, - kc: &kube.FakeClient{ + kc: &kubeclient.FakeClient{ CheckSecretPermissionsImpl: func(context.Context, string) (bool, bool, error) { return false, false, nil }, - GetSecretImpl: func(context.Context, string) (*kube.Secret, error) { + GetSecretImpl: func(context.Context, string) (*kubeapi.Secret, error) { return nil, nil }, }, @@ -47,12 +48,12 @@ func TestSetupKube(t *testing.T) { AuthKey: "foo", KubeSecret: "foo", }, - kc: &kube.FakeClient{ + kc: &kubeclient.FakeClient{ CheckSecretPermissionsImpl: func(context.Context, string) (bool, bool, error) { return false, true, nil }, - GetSecretImpl: func(context.Context, string) (*kube.Secret, error) { - return nil, &kube.Status{Code: 404} + GetSecretImpl: func(context.Context, string) (*kubeapi.Secret, error) { + return nil, &kubeapi.Status{Code: 404} }, }, wantCfg: &settings{ @@ -66,12 +67,12 @@ func TestSetupKube(t *testing.T) { AuthKey: "foo", KubeSecret: "foo", }, - kc: &kube.FakeClient{ + kc: &kubeclient.FakeClient{ CheckSecretPermissionsImpl: func(context.Context, string) (bool, bool, error) { return false, false, nil }, - GetSecretImpl: func(context.Context, string) (*kube.Secret, error) { - return nil, &kube.Status{Code: 404} + GetSecretImpl: func(context.Context, string) (*kubeapi.Secret, error) { + return nil, &kubeapi.Status{Code: 404} }, }, wantCfg: &settings{ @@ -86,12 +87,12 @@ func TestSetupKube(t *testing.T) { AuthKey: "foo", KubeSecret: "foo", }, - kc: &kube.FakeClient{ + kc: &kubeclient.FakeClient{ CheckSecretPermissionsImpl: func(context.Context, string) (bool, bool, error) { return false, false, nil }, - GetSecretImpl: func(context.Context, string) (*kube.Secret, error) { - return nil, &kube.Status{Code: 403} + GetSecretImpl: func(context.Context, string) (*kubeapi.Secret, error) { + return nil, &kubeapi.Status{Code: 403} }, }, wantCfg: &settings{ @@ -110,7 +111,7 @@ func TestSetupKube(t *testing.T) { AuthKey: "foo", KubeSecret: "foo", }, - kc: &kube.FakeClient{ + kc: &kubeclient.FakeClient{ CheckSecretPermissionsImpl: func(context.Context, string) (bool, bool, error) { return false, false, errors.New("broken") }, @@ -126,12 +127,12 @@ func TestSetupKube(t *testing.T) { wantCfg: &settings{ KubeSecret: "foo", }, - kc: &kube.FakeClient{ + kc: &kubeclient.FakeClient{ CheckSecretPermissionsImpl: func(context.Context, string) (bool, bool, error) { return false, true, nil }, - GetSecretImpl: func(context.Context, string) (*kube.Secret, error) { - return nil, &kube.Status{Code: 404} + GetSecretImpl: func(context.Context, string) (*kubeapi.Secret, error) { + return nil, &kubeapi.Status{Code: 404} }, }, }, @@ -144,12 +145,12 @@ func TestSetupKube(t *testing.T) { wantCfg: &settings{ KubeSecret: "foo", }, - kc: &kube.FakeClient{ + kc: &kubeclient.FakeClient{ CheckSecretPermissionsImpl: func(context.Context, string) (bool, bool, error) { return false, false, nil }, - GetSecretImpl: func(context.Context, string) (*kube.Secret, error) { - return &kube.Secret{}, nil + GetSecretImpl: func(context.Context, string) (*kubeapi.Secret, error) { + return &kubeapi.Secret{}, nil }, }, }, @@ -158,12 +159,12 @@ func TestSetupKube(t *testing.T) { cfg: &settings{ KubeSecret: "foo", }, - kc: &kube.FakeClient{ + kc: &kubeclient.FakeClient{ CheckSecretPermissionsImpl: func(context.Context, string) (bool, bool, error) { return false, false, nil }, - GetSecretImpl: func(context.Context, string) (*kube.Secret, error) { - return &kube.Secret{Data: map[string][]byte{"authkey": []byte("foo")}}, nil + GetSecretImpl: func(context.Context, string) (*kubeapi.Secret, error) { + return &kubeapi.Secret{Data: map[string][]byte{"authkey": []byte("foo")}}, nil }, }, wantCfg: &settings{ @@ -176,12 +177,12 @@ func TestSetupKube(t *testing.T) { cfg: &settings{ KubeSecret: "foo", }, - kc: &kube.FakeClient{ + kc: &kubeclient.FakeClient{ CheckSecretPermissionsImpl: func(context.Context, string) (bool, bool, error) { return true, false, nil }, - GetSecretImpl: func(context.Context, string) (*kube.Secret, error) { - return &kube.Secret{Data: map[string][]byte{"authkey": []byte("foo")}}, nil + GetSecretImpl: func(context.Context, string) (*kubeapi.Secret, error) { + return &kubeapi.Secret{Data: map[string][]byte{"authkey": []byte("foo")}}, nil }, }, wantCfg: &settings{ diff --git a/cmd/derper/depaware.txt b/cmd/derper/depaware.txt index 5be7e761a..184e2a373 100644 --- a/cmd/derper/depaware.txt +++ b/cmd/derper/depaware.txt @@ -99,7 +99,7 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa tailscale.com/hostinfo from tailscale.com/net/netmon+ tailscale.com/ipn from tailscale.com/client/tailscale tailscale.com/ipn/ipnstate from tailscale.com/client/tailscale+ - tailscale.com/kube from tailscale.com/envknob + tailscale.com/kube/types from tailscale.com/envknob tailscale.com/metrics from tailscale.com/cmd/derper+ tailscale.com/net/dnscache from tailscale.com/derp/derphttp tailscale.com/net/ktimeout from tailscale.com/cmd/derper diff --git a/cmd/k8s-operator/connector.go b/cmd/k8s-operator/connector.go index 621836f94..44136a8c4 100644 --- a/cmd/k8s-operator/connector.go +++ b/cmd/k8s-operator/connector.go @@ -26,7 +26,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" tsoperator "tailscale.com/k8s-operator" tsapi "tailscale.com/k8s-operator/apis/v1alpha1" - "tailscale.com/kube" + kubetypes "tailscale.com/kube/types" "tailscale.com/tstime" "tailscale.com/util/clientmetric" "tailscale.com/util/set" @@ -62,11 +62,11 @@ type ConnectorReconciler struct { var ( // gaugeConnectorResources tracks the overall number of Connectors currently managed by this operator instance. - gaugeConnectorResources = clientmetric.NewGauge(kube.MetricConnectorResourceCount) + gaugeConnectorResources = clientmetric.NewGauge(kubetypes.MetricConnectorResourceCount) // gaugeConnectorSubnetRouterResources tracks the number of Connectors managed by this operator instance that are subnet routers. - gaugeConnectorSubnetRouterResources = clientmetric.NewGauge(kube.MetricConnectorWithSubnetRouterCount) + gaugeConnectorSubnetRouterResources = clientmetric.NewGauge(kubetypes.MetricConnectorWithSubnetRouterCount) // gaugeConnectorExitNodeResources tracks the number of Connectors currently managed by this operator instance that are exit nodes. - gaugeConnectorExitNodeResources = clientmetric.NewGauge(kube.MetricConnectorWithExitNodeCount) + gaugeConnectorExitNodeResources = clientmetric.NewGauge(kubetypes.MetricConnectorWithExitNodeCount) ) func (a *ConnectorReconciler) Reconcile(ctx context.Context, req reconcile.Request) (res reconcile.Result, err error) { diff --git a/cmd/k8s-operator/connector_test.go b/cmd/k8s-operator/connector_test.go index 48f59e15b..8143f25ac 100644 --- a/cmd/k8s-operator/connector_test.go +++ b/cmd/k8s-operator/connector_test.go @@ -16,7 +16,7 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client/fake" tsapi "tailscale.com/k8s-operator/apis/v1alpha1" - "tailscale.com/kube" + kubetypes "tailscale.com/kube/types" "tailscale.com/tstest" "tailscale.com/util/mak" ) @@ -75,7 +75,7 @@ func TestConnector(t *testing.T) { hostname: "test-connector", isExitNode: true, subnetRoutes: "10.40.0.0/14", - app: kube.AppConnector, + app: kubetypes.AppConnector, } expectEqual(t, fc, expectedSecret(t, fc, opts), nil) expectEqual(t, fc, expectedSTS(t, fc, opts), removeHashAnnotation) @@ -171,7 +171,7 @@ func TestConnector(t *testing.T) { parentType: "connector", subnetRoutes: "10.40.0.0/14", hostname: "test-connector", - app: kube.AppConnector, + app: kubetypes.AppConnector, } expectEqual(t, fc, expectedSecret(t, fc, opts), nil) expectEqual(t, fc, expectedSTS(t, fc, opts), removeHashAnnotation) @@ -257,7 +257,7 @@ func TestConnectorWithProxyClass(t *testing.T) { hostname: "test-connector", isExitNode: true, subnetRoutes: "10.40.0.0/14", - app: kube.AppConnector, + app: kubetypes.AppConnector, } expectEqual(t, fc, expectedSecret(t, fc, opts), nil) expectEqual(t, fc, expectedSTS(t, fc, opts), removeHashAnnotation) diff --git a/cmd/k8s-operator/depaware.txt b/cmd/k8s-operator/depaware.txt index 121647a20..fde31f2af 100644 --- a/cmd/k8s-operator/depaware.txt +++ b/cmd/k8s-operator/depaware.txt @@ -690,7 +690,9 @@ tailscale.com/cmd/k8s-operator dependencies: (generated by github.com/tailscale/ tailscale.com/k8s-operator/sessionrecording/spdy from tailscale.com/k8s-operator/sessionrecording tailscale.com/k8s-operator/sessionrecording/tsrecorder from tailscale.com/k8s-operator/sessionrecording+ tailscale.com/k8s-operator/sessionrecording/ws from tailscale.com/k8s-operator/sessionrecording - tailscale.com/kube from tailscale.com/cmd/k8s-operator+ + tailscale.com/kube/api from tailscale.com/ipn/store/kubestore+ + tailscale.com/kube/client from tailscale.com/ipn/store/kubestore + tailscale.com/kube/types from tailscale.com/cmd/k8s-operator+ tailscale.com/licenses from tailscale.com/client/web tailscale.com/log/filelogger from tailscale.com/logpolicy tailscale.com/log/sockstatlog from tailscale.com/ipn/ipnlocal diff --git a/cmd/k8s-operator/ingress.go b/cmd/k8s-operator/ingress.go index 99aabc441..590509348 100644 --- a/cmd/k8s-operator/ingress.go +++ b/cmd/k8s-operator/ingress.go @@ -23,7 +23,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" "tailscale.com/ipn" - "tailscale.com/kube" + kubetypes "tailscale.com/kube/types" "tailscale.com/types/opt" "tailscale.com/util/clientmetric" "tailscale.com/util/set" @@ -54,7 +54,7 @@ type IngressReconciler struct { var ( // gaugeIngressResources tracks the number of ingress resources that we're // currently managing. - gaugeIngressResources = clientmetric.NewGauge(kube.MetricIngressResourceCount) + gaugeIngressResources = clientmetric.NewGauge(kubetypes.MetricIngressResourceCount) ) func (a *IngressReconciler) Reconcile(ctx context.Context, req reconcile.Request) (_ reconcile.Result, err error) { diff --git a/cmd/k8s-operator/ingress_test.go b/cmd/k8s-operator/ingress_test.go index 2588a804d..b4524b6f6 100644 --- a/cmd/k8s-operator/ingress_test.go +++ b/cmd/k8s-operator/ingress_test.go @@ -17,7 +17,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" "tailscale.com/ipn" tsapi "tailscale.com/k8s-operator/apis/v1alpha1" - "tailscale.com/kube" + kubetypes "tailscale.com/kube/types" "tailscale.com/types/ptr" "tailscale.com/util/mak" ) @@ -94,7 +94,7 @@ func TestTailscaleIngress(t *testing.T) { namespace: "default", parentType: "ingress", hostname: "default-test", - app: kube.AppIngressResource, + app: kubetypes.AppIngressResource, } serveConfig := &ipn.ServeConfig{ TCP: map[uint16]*ipn.TCPPortHandler{443: {HTTPS: true}}, @@ -226,7 +226,7 @@ func TestTailscaleIngressWithProxyClass(t *testing.T) { namespace: "default", parentType: "ingress", hostname: "default-test", - app: kube.AppIngressResource, + app: kubetypes.AppIngressResource, } serveConfig := &ipn.ServeConfig{ TCP: map[uint16]*ipn.TCPPortHandler{443: {HTTPS: true}}, diff --git a/cmd/k8s-operator/nameserver.go b/cmd/k8s-operator/nameserver.go index 4a864e12b..769291381 100644 --- a/cmd/k8s-operator/nameserver.go +++ b/cmd/k8s-operator/nameserver.go @@ -28,7 +28,7 @@ import ( "sigs.k8s.io/yaml" tsoperator "tailscale.com/k8s-operator" tsapi "tailscale.com/k8s-operator/apis/v1alpha1" - "tailscale.com/kube" + kubetypes "tailscale.com/kube/types" "tailscale.com/tstime" "tailscale.com/util/clientmetric" "tailscale.com/util/set" @@ -63,7 +63,7 @@ type NameserverReconciler struct { managedNameservers set.Slice[types.UID] // one or none } -var gaugeNameserverResources = clientmetric.NewGauge(kube.MetricNameserverCount) +var gaugeNameserverResources = clientmetric.NewGauge(kubetypes.MetricNameserverCount) func (a *NameserverReconciler) Reconcile(ctx context.Context, req reconcile.Request) (res reconcile.Result, err error) { logger := a.logger.With("dnsConfig", req.Name) diff --git a/cmd/k8s-operator/operator.go b/cmd/k8s-operator/operator.go index aa59d8de2..72ccf4cf6 100644 --- a/cmd/k8s-operator/operator.go +++ b/cmd/k8s-operator/operator.go @@ -39,7 +39,7 @@ import ( "tailscale.com/ipn" "tailscale.com/ipn/store/kubestore" tsapi "tailscale.com/k8s-operator/apis/v1alpha1" - "tailscale.com/kube" + kubetypes "tailscale.com/kube/types" "tailscale.com/tsnet" "tailscale.com/tstime" "tailscale.com/types/logger" @@ -88,9 +88,9 @@ func main() { // https://tailscale.com/kb/1236/kubernetes-operator/?q=kubernetes#accessing-the-kubernetes-control-plane-using-an-api-server-proxy. mode := parseAPIProxyMode() if mode == apiserverProxyModeDisabled { - hostinfo.SetApp(kube.AppOperator) + hostinfo.SetApp(kubetypes.AppOperator) } else { - hostinfo.SetApp(kube.AppAPIServerProxy) + hostinfo.SetApp(kubetypes.AppAPIServerProxy) } s, tsClient := initTSNet(zlog) diff --git a/cmd/k8s-operator/operator_test.go b/cmd/k8s-operator/operator_test.go index 583d5a3d4..0df29b5e7 100644 --- a/cmd/k8s-operator/operator_test.go +++ b/cmd/k8s-operator/operator_test.go @@ -22,7 +22,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/controller-runtime/pkg/reconcile" tsapi "tailscale.com/k8s-operator/apis/v1alpha1" - "tailscale.com/kube" + kubetypes "tailscale.com/kube/types" "tailscale.com/net/dns/resolvconffile" "tailscale.com/tstest" "tailscale.com/tstime" @@ -124,7 +124,7 @@ func TestLoadBalancerClass(t *testing.T) { parentType: "svc", hostname: "default-test", clusterTargetIP: "10.20.30.40", - app: kube.AppIngressProxy, + app: kubetypes.AppIngressProxy, } expectEqual(t, fc, expectedSecret(t, fc, opts), nil) @@ -262,7 +262,7 @@ func TestTailnetTargetFQDNAnnotation(t *testing.T) { parentType: "svc", tailnetTargetFQDN: tailnetTargetFQDN, hostname: "default-test", - app: kube.AppEgressProxy, + app: kubetypes.AppEgressProxy, } expectEqual(t, fc, expectedSecret(t, fc, o), nil) @@ -374,7 +374,7 @@ func TestTailnetTargetIPAnnotation(t *testing.T) { parentType: "svc", tailnetTargetIP: tailnetTargetIP, hostname: "default-test", - app: kube.AppEgressProxy, + app: kubetypes.AppEgressProxy, } expectEqual(t, fc, expectedSecret(t, fc, o), nil) @@ -483,7 +483,7 @@ func TestAnnotations(t *testing.T) { parentType: "svc", hostname: "default-test", clusterTargetIP: "10.20.30.40", - app: kube.AppIngressProxy, + app: kubetypes.AppIngressProxy, } expectEqual(t, fc, expectedSecret(t, fc, o), nil) @@ -589,7 +589,7 @@ func TestAnnotationIntoLB(t *testing.T) { parentType: "svc", hostname: "default-test", clusterTargetIP: "10.20.30.40", - app: kube.AppIngressProxy, + app: kubetypes.AppIngressProxy, } expectEqual(t, fc, expectedSecret(t, fc, o), nil) @@ -719,7 +719,7 @@ func TestLBIntoAnnotation(t *testing.T) { parentType: "svc", hostname: "default-test", clusterTargetIP: "10.20.30.40", - app: kube.AppIngressProxy, + app: kubetypes.AppIngressProxy, } expectEqual(t, fc, expectedSecret(t, fc, o), nil) @@ -859,7 +859,7 @@ func TestCustomHostname(t *testing.T) { parentType: "svc", hostname: "reindeer-flotilla", clusterTargetIP: "10.20.30.40", - app: kube.AppIngressProxy, + app: kubetypes.AppIngressProxy, } expectEqual(t, fc, expectedSecret(t, fc, o), nil) @@ -972,7 +972,7 @@ func TestCustomPriorityClassName(t *testing.T) { hostname: "tailscale-critical", priorityClassName: "custom-priority-class-name", clusterTargetIP: "10.20.30.40", - app: kube.AppIngressProxy, + app: kubetypes.AppIngressProxy, } expectEqual(t, fc, expectedSTS(t, fc, o), removeHashAnnotation) @@ -1041,7 +1041,7 @@ func TestProxyClassForService(t *testing.T) { parentType: "svc", hostname: "default-test", clusterTargetIP: "10.20.30.40", - app: kube.AppIngressProxy, + app: kubetypes.AppIngressProxy, } expectEqual(t, fc, expectedSecret(t, fc, opts), nil) expectEqual(t, fc, expectedHeadlessService(shortName, "svc"), nil) @@ -1135,7 +1135,7 @@ func TestDefaultLoadBalancer(t *testing.T) { parentType: "svc", hostname: "default-test", clusterTargetIP: "10.20.30.40", - app: kube.AppIngressProxy, + app: kubetypes.AppIngressProxy, } expectEqual(t, fc, expectedSTS(t, fc, o), removeHashAnnotation) @@ -1192,7 +1192,7 @@ func TestProxyFirewallMode(t *testing.T) { hostname: "default-test", firewallMode: "nftables", clusterTargetIP: "10.20.30.40", - app: kube.AppIngressProxy, + app: kubetypes.AppIngressProxy, } expectEqual(t, fc, expectedSTS(t, fc, o), removeHashAnnotation) } @@ -1247,7 +1247,7 @@ func TestTailscaledConfigfileHash(t *testing.T) { hostname: "default-test", clusterTargetIP: "10.20.30.40", confFileHash: "e09bededa0379920141cbd0b0dbdf9b8b66545877f9e8397423f5ce3e1ba439e", - app: kube.AppIngressProxy, + app: kubetypes.AppIngressProxy, } expectEqual(t, fc, expectedSTS(t, fc, o), nil) @@ -1542,7 +1542,7 @@ func Test_externalNameService(t *testing.T) { parentType: "svc", hostname: "default-test", clusterTargetDNS: "foo.com", - app: kube.AppIngressProxy, + app: kubetypes.AppIngressProxy, } expectEqual(t, fc, expectedSecret(t, fc, opts), nil) diff --git a/cmd/k8s-operator/proxy.go b/cmd/k8s-operator/proxy.go index e15d066dc..66b0786eb 100644 --- a/cmd/k8s-operator/proxy.go +++ b/cmd/k8s-operator/proxy.go @@ -23,7 +23,7 @@ import ( "tailscale.com/client/tailscale" "tailscale.com/client/tailscale/apitype" ksr "tailscale.com/k8s-operator/sessionrecording" - tskube "tailscale.com/kube" + kubetypes "tailscale.com/kube/types" "tailscale.com/tailcfg" "tailscale.com/tsnet" "tailscale.com/util/clientmetric" @@ -339,10 +339,10 @@ const ( func addImpersonationHeaders(r *http.Request, log *zap.SugaredLogger) error { log = log.With("remote", r.RemoteAddr) who := whoIsKey.Value(r.Context()) - rules, err := tailcfg.UnmarshalCapJSON[tskube.KubernetesCapRule](who.CapMap, tailcfg.PeerCapabilityKubernetes) + rules, err := tailcfg.UnmarshalCapJSON[kubetypes.KubernetesCapRule](who.CapMap, tailcfg.PeerCapabilityKubernetes) if len(rules) == 0 && err == nil { // Try the old capability name for backwards compatibility. - rules, err = tailcfg.UnmarshalCapJSON[tskube.KubernetesCapRule](who.CapMap, oldCapabilityName) + rules, err = tailcfg.UnmarshalCapJSON[kubetypes.KubernetesCapRule](who.CapMap, oldCapabilityName) } if err != nil { return fmt.Errorf("failed to unmarshal capability: %v", err) @@ -392,7 +392,7 @@ func determineRecorderConfig(who *apitype.WhoIsResponse) (failOpen bool, recorde return false, nil, errors.New("[unexpected] cannot determine caller") } failOpen = true - rules, err := tailcfg.UnmarshalCapJSON[tskube.KubernetesCapRule](who.CapMap, tailcfg.PeerCapabilityKubernetes) + rules, err := tailcfg.UnmarshalCapJSON[kubetypes.KubernetesCapRule](who.CapMap, tailcfg.PeerCapabilityKubernetes) if err != nil { return failOpen, nil, fmt.Errorf("failed to unmarshal Kubernetes capability: %w", err) } diff --git a/cmd/k8s-operator/sts.go b/cmd/k8s-operator/sts.go index a6b03ee83..0b792e6f2 100644 --- a/cmd/k8s-operator/sts.go +++ b/cmd/k8s-operator/sts.go @@ -31,7 +31,7 @@ import ( "tailscale.com/ipn" tsoperator "tailscale.com/k8s-operator" tsapi "tailscale.com/k8s-operator/apis/v1alpha1" - "tailscale.com/kube" + kubetypes "tailscale.com/kube/types" "tailscale.com/net/netutil" "tailscale.com/tailcfg" "tailscale.com/types/opt" @@ -626,16 +626,16 @@ func (a *tailscaleSTSReconciler) reconcileSTS(ctx context.Context, logger *zap.S func appInfoForProxy(cfg *tailscaleSTSConfig) (string, error) { if cfg.ClusterTargetDNSName != "" || cfg.ClusterTargetIP != "" { - return kube.AppIngressProxy, nil + return kubetypes.AppIngressProxy, nil } if cfg.TailnetTargetFQDN != "" || cfg.TailnetTargetIP != "" { - return kube.AppEgressProxy, nil + return kubetypes.AppEgressProxy, nil } if cfg.ServeConfig != nil { - return kube.AppIngressResource, nil + return kubetypes.AppIngressResource, nil } if cfg.Connector != nil { - return kube.AppConnector, nil + return kubetypes.AppConnector, nil } return "", errors.New("unable to determine proxy type") } diff --git a/cmd/k8s-operator/svc.go b/cmd/k8s-operator/svc.go index 3062488bf..75ccff2f7 100644 --- a/cmd/k8s-operator/svc.go +++ b/cmd/k8s-operator/svc.go @@ -25,7 +25,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" tsoperator "tailscale.com/k8s-operator" tsapi "tailscale.com/k8s-operator/apis/v1alpha1" - "tailscale.com/kube" + kubetypes "tailscale.com/kube/types" "tailscale.com/net/dns/resolvconffile" "tailscale.com/tstime" "tailscale.com/util/clientmetric" @@ -70,10 +70,10 @@ type ServiceReconciler struct { var ( // gaugeEgressProxies tracks the number of egress proxies that we're // currently managing. - gaugeEgressProxies = clientmetric.NewGauge(kube.MetricEgressProxyCount) + gaugeEgressProxies = clientmetric.NewGauge(kubetypes.MetricEgressProxyCount) // gaugeIngressProxies tracks the number of ingress proxies that we're // currently managing. - gaugeIngressProxies = clientmetric.NewGauge(kube.MetricIngressProxyCount) + gaugeIngressProxies = clientmetric.NewGauge(kubetypes.MetricIngressProxyCount) ) func childResourceLabels(name, ns, typ string) map[string]string { diff --git a/cmd/stund/depaware.txt b/cmd/stund/depaware.txt index 31bacf2b4..8a0a6dcd7 100644 --- a/cmd/stund/depaware.txt +++ b/cmd/stund/depaware.txt @@ -50,7 +50,7 @@ tailscale.com/cmd/stund dependencies: (generated by github.com/tailscale/depawar google.golang.org/protobuf/types/known/timestamppb from github.com/prometheus/client_golang/prometheus+ tailscale.com from tailscale.com/version tailscale.com/envknob from tailscale.com/tsweb+ - tailscale.com/kube from tailscale.com/envknob + tailscale.com/kube/types from tailscale.com/envknob tailscale.com/metrics from tailscale.com/net/stunserver+ tailscale.com/net/netaddr from tailscale.com/net/tsaddr tailscale.com/net/stun from tailscale.com/net/stunserver @@ -75,7 +75,6 @@ tailscale.com/cmd/stund dependencies: (generated by github.com/tailscale/depawar tailscale.com/util/dnsname from tailscale.com/tailcfg tailscale.com/util/fastuuid from tailscale.com/tsweb tailscale.com/util/lineread from tailscale.com/version/distro - tailscale.com/util/multierr from tailscale.com/kube tailscale.com/util/nocasemaps from tailscale.com/types/ipproto tailscale.com/util/slicesx from tailscale.com/tailcfg tailscale.com/util/vizerror from tailscale.com/tailcfg+ @@ -131,7 +130,7 @@ tailscale.com/cmd/stund dependencies: (generated by github.com/tailscale/depawar crypto/sha512 from crypto/ecdsa+ crypto/subtle from crypto/aes+ crypto/tls from net/http+ - crypto/x509 from crypto/tls+ + crypto/x509 from crypto/tls crypto/x509/pkix from crypto/x509 database/sql/driver from github.com/google/uuid embed from crypto/internal/nistec+ diff --git a/cmd/tailscale/depaware.txt b/cmd/tailscale/depaware.txt index ec4ba4aa4..22dc30fbf 100644 --- a/cmd/tailscale/depaware.txt +++ b/cmd/tailscale/depaware.txt @@ -98,7 +98,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep tailscale.com/internal/noiseconn from tailscale.com/cmd/tailscale/cli tailscale.com/ipn from tailscale.com/client/tailscale+ tailscale.com/ipn/ipnstate from tailscale.com/client/tailscale+ - tailscale.com/kube from tailscale.com/envknob + tailscale.com/kube/types from tailscale.com/envknob tailscale.com/licenses from tailscale.com/client/web+ tailscale.com/metrics from tailscale.com/derp+ tailscale.com/net/captivedetection from tailscale.com/net/netcheck diff --git a/cmd/tailscaled/depaware.txt b/cmd/tailscaled/depaware.txt index 2ae69623e..2ec6cf4bf 100644 --- a/cmd/tailscaled/depaware.txt +++ b/cmd/tailscaled/depaware.txt @@ -279,7 +279,9 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de L tailscale.com/ipn/store/awsstore from tailscale.com/ipn/store L tailscale.com/ipn/store/kubestore from tailscale.com/ipn/store tailscale.com/ipn/store/mem from tailscale.com/ipn/ipnlocal+ - tailscale.com/kube from tailscale.com/ipn/store/kubestore+ + L tailscale.com/kube/api from tailscale.com/ipn/store/kubestore+ + L tailscale.com/kube/client from tailscale.com/ipn/store/kubestore + tailscale.com/kube/types from tailscale.com/envknob tailscale.com/licenses from tailscale.com/client/web tailscale.com/log/filelogger from tailscale.com/logpolicy tailscale.com/log/sockstatlog from tailscale.com/ipn/ipnlocal diff --git a/envknob/envknob.go b/envknob/envknob.go index 0fc723746..350519c8c 100644 --- a/envknob/envknob.go +++ b/envknob/envknob.go @@ -31,7 +31,7 @@ import ( "sync/atomic" "time" - "tailscale.com/kube" + kubetypes "tailscale.com/kube/types" "tailscale.com/types/opt" "tailscale.com/version" "tailscale.com/version/distro" @@ -410,7 +410,7 @@ func TKASkipSignatureCheck() bool { return Bool("TS_UNSAFE_SKIP_NKS_VERIFICATION // Kubernetes Operator components. func App() string { a := os.Getenv("TS_INTERNAL_APP") - if a == kube.AppConnector || a == kube.AppEgressProxy || a == kube.AppIngressProxy || a == kube.AppIngressResource { + if a == kubetypes.AppConnector || a == kubetypes.AppEgressProxy || a == kubetypes.AppIngressProxy || a == kubetypes.AppIngressResource { return a } return "" diff --git a/ipn/store/kubestore/store_kube.go b/ipn/store/kubestore/store_kube.go index 0c90d06b3..4b96bd89e 100644 --- a/ipn/store/kubestore/store_kube.go +++ b/ipn/store/kubestore/store_kube.go @@ -13,20 +13,21 @@ import ( "time" "tailscale.com/ipn" - "tailscale.com/kube" + kubeapi "tailscale.com/kube/api" + kubeclient "tailscale.com/kube/client" "tailscale.com/types/logger" ) // Store is an ipn.StateStore that uses a Kubernetes Secret for persistence. type Store struct { - client kube.Client + client kubeclient.Client canPatch bool secretName string } // New returns a new Store that persists to the named secret. func New(_ logger.Logf, secretName string) (*Store, error) { - c, err := kube.New() + c, err := kubeclient.New() if err != nil { return nil, err } @@ -58,7 +59,7 @@ func (s *Store) ReadState(id ipn.StateKey) ([]byte, error) { secret, err := s.client.GetSecret(ctx, s.secretName) if err != nil { - if st, ok := err.(*kube.Status); ok && st.Code == 404 { + if st, ok := err.(*kubeapi.Status); ok && st.Code == 404 { return nil, ipn.ErrStateNotExist } return nil, err @@ -88,13 +89,13 @@ func (s *Store) WriteState(id ipn.StateKey, bs []byte) error { secret, err := s.client.GetSecret(ctx, s.secretName) if err != nil { - if kube.IsNotFoundErr(err) { - return s.client.CreateSecret(ctx, &kube.Secret{ - TypeMeta: kube.TypeMeta{ + if kubeclient.IsNotFoundErr(err) { + return s.client.CreateSecret(ctx, &kubeapi.Secret{ + TypeMeta: kubeapi.TypeMeta{ APIVersion: "v1", Kind: "Secret", }, - ObjectMeta: kube.ObjectMeta{ + ObjectMeta: kubeapi.ObjectMeta{ Name: s.secretName, }, Data: map[string][]byte{ @@ -106,7 +107,7 @@ func (s *Store) WriteState(id ipn.StateKey, bs []byte) error { } if s.canPatch { if len(secret.Data) == 0 { // if user has pre-created a blank Secret - m := []kube.JSONPatch{ + m := []kubeclient.JSONPatch{ { Op: "add", Path: "/data", @@ -118,7 +119,7 @@ func (s *Store) WriteState(id ipn.StateKey, bs []byte) error { } return nil } - m := []kube.JSONPatch{ + m := []kubeclient.JSONPatch{ { Op: "add", Path: "/data/" + sanitizeKey(id), diff --git a/kube/api.go b/kube/api/api.go similarity index 96% rename from kube/api.go rename to kube/api/api.go index b49b76c34..661fbbba8 100644 --- a/kube/api.go +++ b/kube/api/api.go @@ -1,7 +1,11 @@ // Copyright (c) Tailscale Inc & AUTHORS // SPDX-License-Identifier: BSD-3-Clause -package kube +// Package api contains Kubernetes API types for internal consumption. +// These types are split into a separate package for consumption of +// non-Kubernetes shared libraries and binaries. Be mindful of not increasing +// dependency size for those consumers when adding anything new here. +package api import "time" diff --git a/kube/client.go b/kube/client/client.go similarity index 89% rename from kube/client.go rename to kube/client/client.go index 62daa366e..a70a9dbd3 100644 --- a/kube/client.go +++ b/kube/client/client.go @@ -1,10 +1,13 @@ // Copyright (c) Tailscale Inc & AUTHORS // SPDX-License-Identifier: BSD-3-Clause -// Package kube provides a client to interact with Kubernetes. +// Package client provides a client to interact with Kubernetes. // This package is Tailscale-internal and not meant for external consumption. // Further, the API should not be considered stable. -package kube +// Client is split into a separate package for consumption of +// non-Kubernetes shared libraries and binaries. Be mindful of not increasing +// dependency size for those consumers when adding anything new here. +package client import ( "bytes" @@ -23,6 +26,7 @@ import ( "sync" "time" + kubeapi "tailscale.com/kube/api" "tailscale.com/util/multierr" ) @@ -50,10 +54,10 @@ func readFile(n string) ([]byte, error) { // Client handles connections to Kubernetes. // It expects to be run inside a cluster. type Client interface { - GetSecret(context.Context, string) (*Secret, error) - UpdateSecret(context.Context, *Secret) error - CreateSecret(context.Context, *Secret) error - StrategicMergePatchSecret(context.Context, string, *Secret, string) error + GetSecret(context.Context, string) (*kubeapi.Secret, error) + UpdateSecret(context.Context, *kubeapi.Secret) error + CreateSecret(context.Context, *kubeapi.Secret) error + StrategicMergePatchSecret(context.Context, string, *kubeapi.Secret, string) error JSONPatchSecret(context.Context, string, []JSONPatch) error CheckSecretPermissions(context.Context, string) (bool, bool, error) SetDialer(dialer func(context.Context, string, string) (net.Conn, error)) @@ -144,7 +148,7 @@ func getError(resp *http.Response) error { // https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#http-status-codes return nil } - st := &Status{} + st := &kubeapi.Status{} if err := json.NewDecoder(resp.Body).Decode(st); err != nil { return err } @@ -178,7 +182,7 @@ func (c *client) doRequest(ctx context.Context, method, url string, in, out any, } defer resp.Body.Close() if err := getError(resp); err != nil { - if st, ok := err.(*Status); ok && st.Code == 401 { + if st, ok := err.(*kubeapi.Status); ok && st.Code == 401 { c.expireToken() } return err @@ -220,8 +224,8 @@ func (c *client) newRequest(ctx context.Context, method, url string, in any) (*h } // GetSecret fetches the secret from the Kubernetes API. -func (c *client) GetSecret(ctx context.Context, name string) (*Secret, error) { - s := &Secret{Data: make(map[string][]byte)} +func (c *client) GetSecret(ctx context.Context, name string) (*kubeapi.Secret, error) { + s := &kubeapi.Secret{Data: make(map[string][]byte)} if err := c.doRequest(ctx, "GET", c.secretURL(name), nil, s); err != nil { return nil, err } @@ -229,13 +233,13 @@ func (c *client) GetSecret(ctx context.Context, name string) (*Secret, error) { } // CreateSecret creates a secret in the Kubernetes API. -func (c *client) CreateSecret(ctx context.Context, s *Secret) error { +func (c *client) CreateSecret(ctx context.Context, s *kubeapi.Secret) error { s.Namespace = c.ns return c.doRequest(ctx, "POST", c.secretURL(""), s, nil) } // UpdateSecret updates a secret in the Kubernetes API. -func (c *client) UpdateSecret(ctx context.Context, s *Secret) error { +func (c *client) UpdateSecret(ctx context.Context, s *kubeapi.Secret) error { return c.doRequest(ctx, "PUT", c.secretURL(s.Name), s, nil) } @@ -263,7 +267,7 @@ func (c *client) JSONPatchSecret(ctx context.Context, name string, patch []JSONP // StrategicMergePatchSecret updates a secret in the Kubernetes API using a // strategic merge patch. // If a fieldManager is provided, it will be used to track the patch. -func (c *client) StrategicMergePatchSecret(ctx context.Context, name string, s *Secret, fieldManager string) error { +func (c *client) StrategicMergePatchSecret(ctx context.Context, name string, s *kubeapi.Secret, fieldManager string) error { surl := c.secretURL(name) if fieldManager != "" { uv := url.Values{ @@ -340,7 +344,7 @@ func (c *client) checkPermission(ctx context.Context, verb, secretName string) ( } func IsNotFoundErr(err error) bool { - if st, ok := err.(*Status); ok && st.Code == 404 { + if st, ok := err.(*kubeapi.Status); ok && st.Code == 404 { return true } return false diff --git a/kube/fake_client.go b/kube/client/fake_client.go similarity index 68% rename from kube/fake_client.go rename to kube/client/fake_client.go index ad5e8201d..f57bb0226 100644 --- a/kube/fake_client.go +++ b/kube/client/fake_client.go @@ -1,34 +1,36 @@ // Copyright (c) Tailscale Inc & AUTHORS // SPDX-License-Identifier: BSD-3-Clause -package kube +package client import ( "context" "net" + + kubeapi "tailscale.com/kube/api" ) var _ Client = &FakeClient{} type FakeClient struct { - GetSecretImpl func(context.Context, string) (*Secret, error) + GetSecretImpl func(context.Context, string) (*kubeapi.Secret, error) CheckSecretPermissionsImpl func(ctx context.Context, name string) (bool, bool, error) } func (fc *FakeClient) CheckSecretPermissions(ctx context.Context, name string) (bool, bool, error) { return fc.CheckSecretPermissionsImpl(ctx, name) } -func (fc *FakeClient) GetSecret(ctx context.Context, name string) (*Secret, error) { +func (fc *FakeClient) GetSecret(ctx context.Context, name string) (*kubeapi.Secret, error) { return fc.GetSecretImpl(ctx, name) } func (fc *FakeClient) SetURL(_ string) {} func (fc *FakeClient) SetDialer(dialer func(ctx context.Context, network, addr string) (net.Conn, error)) { } -func (fc *FakeClient) StrategicMergePatchSecret(context.Context, string, *Secret, string) error { +func (fc *FakeClient) StrategicMergePatchSecret(context.Context, string, *kubeapi.Secret, string) error { return nil } func (fc *FakeClient) JSONPatchSecret(context.Context, string, []JSONPatch) error { return nil } -func (fc *FakeClient) UpdateSecret(context.Context, *Secret) error { return nil } -func (fc *FakeClient) CreateSecret(context.Context, *Secret) error { return nil } +func (fc *FakeClient) UpdateSecret(context.Context, *kubeapi.Secret) error { return nil } +func (fc *FakeClient) CreateSecret(context.Context, *kubeapi.Secret) error { return nil } diff --git a/kube/grants.go b/kube/types/grants.go similarity index 89% rename from kube/grants.go rename to kube/types/grants.go index f87143054..ce7f205b9 100644 --- a/kube/grants.go +++ b/kube/types/grants.go @@ -1,7 +1,12 @@ // Copyright (c) Tailscale Inc & AUTHORS // SPDX-License-Identifier: BSD-3-Clause -package kube +// Package types contains types and constants related to the Tailscale +// Kubernetes Operator. +// These are split into a separate package for consumption of +// non-Kubernetes shared libraries and binaries. Be mindful of not increasing +// dependency size for those consumers when adding anything new here. +package types import "net/netip" diff --git a/kube/metrics.go b/kube/types/metrics.go similarity index 98% rename from kube/metrics.go rename to kube/types/metrics.go index a0e33f5f7..e348a6479 100644 --- a/kube/metrics.go +++ b/kube/types/metrics.go @@ -1,7 +1,7 @@ // Copyright (c) Tailscale Inc & AUTHORS // SPDX-License-Identifier: BSD-3-Clause -package kube +package types const ( // Hostinfo App values for the Tailscale Kubernetes Operator components.