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 <irbe@tailscale.com>
This commit is contained in:
Irbe Krumina 2024-09-08 21:06:07 +03:00 committed by GitHub
parent ecd64f6ed9
commit d6dfb7f242
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 143 additions and 122 deletions

View File

@ -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)
}

View File

@ -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{

View File

@ -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

View File

@ -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) {

View File

@ -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)

View File

@ -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

View File

@ -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) {

View File

@ -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}},

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)
}

View File

@ -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")
}

View File

@ -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 {

View File

@ -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+

View File

@ -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

View File

@ -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

View File

@ -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 ""

View File

@ -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),

View File

@ -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"

View File

@ -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

View File

@ -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 }

View File

@ -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"

View File

@ -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.