| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- // Copyright (c) Tailscale Inc & AUTHORS
- // SPDX-License-Identifier: BSD-3-Clause
- //go:build linux
- package main
- import (
- "context"
- "errors"
- "testing"
- "time"
- "github.com/google/go-cmp/cmp"
- "tailscale.com/ipn"
- "tailscale.com/kube/kubeapi"
- "tailscale.com/kube/kubeclient"
- )
- func TestSetupKube(t *testing.T) {
- tests := []struct {
- name string
- cfg *settings
- wantErr bool
- wantCfg *settings
- kc *kubeClient
- }{
- {
- name: "TS_AUTHKEY set, state Secret exists",
- cfg: &settings{
- AuthKey: "foo",
- KubeSecret: "foo",
- },
- kc: &kubeClient{stateSecret: "foo", Client: &kubeclient.FakeClient{
- CheckSecretPermissionsImpl: func(context.Context, string) (bool, bool, error) {
- return false, false, nil
- },
- GetSecretImpl: func(context.Context, string) (*kubeapi.Secret, error) {
- return nil, nil
- },
- }},
- wantCfg: &settings{
- AuthKey: "foo",
- KubeSecret: "foo",
- },
- },
- {
- name: "TS_AUTHKEY set, state Secret does not exist, we have permissions to create it",
- cfg: &settings{
- AuthKey: "foo",
- KubeSecret: "foo",
- },
- kc: &kubeClient{stateSecret: "foo", Client: &kubeclient.FakeClient{
- CheckSecretPermissionsImpl: func(context.Context, string) (bool, bool, error) {
- return false, true, nil
- },
- GetSecretImpl: func(context.Context, string) (*kubeapi.Secret, error) {
- return nil, &kubeapi.Status{Code: 404}
- },
- }},
- wantCfg: &settings{
- AuthKey: "foo",
- KubeSecret: "foo",
- },
- },
- {
- name: "TS_AUTHKEY set, state Secret does not exist, we do not have permissions to create it",
- cfg: &settings{
- AuthKey: "foo",
- KubeSecret: "foo",
- },
- kc: &kubeClient{stateSecret: "foo", Client: &kubeclient.FakeClient{
- CheckSecretPermissionsImpl: func(context.Context, string) (bool, bool, error) {
- return false, false, nil
- },
- GetSecretImpl: func(context.Context, string) (*kubeapi.Secret, error) {
- return nil, &kubeapi.Status{Code: 404}
- },
- }},
- wantCfg: &settings{
- AuthKey: "foo",
- KubeSecret: "foo",
- },
- wantErr: true,
- },
- {
- name: "TS_AUTHKEY set, we encounter a non-404 error when trying to retrieve the state Secret",
- cfg: &settings{
- AuthKey: "foo",
- KubeSecret: "foo",
- },
- kc: &kubeClient{stateSecret: "foo", Client: &kubeclient.FakeClient{
- CheckSecretPermissionsImpl: func(context.Context, string) (bool, bool, error) {
- return false, false, nil
- },
- GetSecretImpl: func(context.Context, string) (*kubeapi.Secret, error) {
- return nil, &kubeapi.Status{Code: 403}
- },
- }},
- wantCfg: &settings{
- AuthKey: "foo",
- KubeSecret: "foo",
- },
- wantErr: true,
- },
- {
- name: "TS_AUTHKEY set, we encounter a non-404 error when trying to check Secret permissions",
- cfg: &settings{
- AuthKey: "foo",
- KubeSecret: "foo",
- },
- wantCfg: &settings{
- AuthKey: "foo",
- KubeSecret: "foo",
- },
- kc: &kubeClient{stateSecret: "foo", Client: &kubeclient.FakeClient{
- CheckSecretPermissionsImpl: func(context.Context, string) (bool, bool, error) {
- return false, false, errors.New("broken")
- },
- }},
- wantErr: true,
- },
- {
- // Interactive login using URL in Pod logs
- name: "TS_AUTHKEY not set, state Secret does not exist, we have permissions to create it",
- cfg: &settings{
- KubeSecret: "foo",
- },
- wantCfg: &settings{
- KubeSecret: "foo",
- },
- kc: &kubeClient{stateSecret: "foo", Client: &kubeclient.FakeClient{
- CheckSecretPermissionsImpl: func(context.Context, string) (bool, bool, error) {
- return false, true, nil
- },
- GetSecretImpl: func(context.Context, string) (*kubeapi.Secret, error) {
- return nil, &kubeapi.Status{Code: 404}
- },
- }},
- },
- {
- // Interactive login using URL in Pod logs
- name: "TS_AUTHKEY not set, state Secret exists, but does not contain auth key",
- cfg: &settings{
- KubeSecret: "foo",
- },
- wantCfg: &settings{
- KubeSecret: "foo",
- },
- kc: &kubeClient{stateSecret: "foo", Client: &kubeclient.FakeClient{
- CheckSecretPermissionsImpl: func(context.Context, string) (bool, bool, error) {
- return false, false, nil
- },
- GetSecretImpl: func(context.Context, string) (*kubeapi.Secret, error) {
- return &kubeapi.Secret{}, nil
- },
- }},
- },
- {
- name: "TS_AUTHKEY not set, state Secret contains auth key, we do not have RBAC to patch it",
- cfg: &settings{
- KubeSecret: "foo",
- },
- kc: &kubeClient{stateSecret: "foo", Client: &kubeclient.FakeClient{
- CheckSecretPermissionsImpl: func(context.Context, string) (bool, bool, error) {
- return false, false, nil
- },
- GetSecretImpl: func(context.Context, string) (*kubeapi.Secret, error) {
- return &kubeapi.Secret{Data: map[string][]byte{"authkey": []byte("foo")}}, nil
- },
- }},
- wantCfg: &settings{
- KubeSecret: "foo",
- },
- wantErr: true,
- },
- {
- name: "TS_AUTHKEY not set, state Secret contains auth key, we have RBAC to patch it",
- cfg: &settings{
- KubeSecret: "foo",
- },
- kc: &kubeClient{stateSecret: "foo", Client: &kubeclient.FakeClient{
- CheckSecretPermissionsImpl: func(context.Context, string) (bool, bool, error) {
- return true, false, nil
- },
- GetSecretImpl: func(context.Context, string) (*kubeapi.Secret, error) {
- return &kubeapi.Secret{Data: map[string][]byte{"authkey": []byte("foo")}}, nil
- },
- }},
- wantCfg: &settings{
- KubeSecret: "foo",
- AuthKey: "foo",
- KubernetesCanPatch: true,
- },
- },
- }
- for _, tt := range tests {
- kc := tt.kc
- t.Run(tt.name, func(t *testing.T) {
- if err := tt.cfg.setupKube(context.Background(), kc); (err != nil) != tt.wantErr {
- t.Errorf("settings.setupKube() error = %v, wantErr %v", err, tt.wantErr)
- }
- if diff := cmp.Diff(*tt.cfg, *tt.wantCfg); diff != "" {
- t.Errorf("unexpected contents of settings after running settings.setupKube()\n(-got +want):\n%s", diff)
- }
- })
- }
- }
- func TestWaitForConsistentState(t *testing.T) {
- data := map[string][]byte{
- // Missing _current-profile.
- string(ipn.KnownProfilesStateKey): []byte(""),
- string(ipn.MachineKeyStateKey): []byte(""),
- "profile-foo": []byte(""),
- }
- kc := &kubeClient{
- Client: &kubeclient.FakeClient{
- GetSecretImpl: func(context.Context, string) (*kubeapi.Secret, error) {
- return &kubeapi.Secret{
- Data: data,
- }, nil
- },
- },
- }
- ctx, cancel := context.WithTimeout(context.Background(), time.Second)
- defer cancel()
- if err := kc.waitForConsistentState(ctx); err != context.DeadlineExceeded {
- t.Fatalf("expected DeadlineExceeded, got %v", err)
- }
- ctx, cancel = context.WithTimeout(context.Background(), time.Second)
- defer cancel()
- data[string(ipn.CurrentProfileStateKey)] = []byte("")
- if err := kc.waitForConsistentState(ctx); err != nil {
- t.Fatalf("expected nil, got %v", err)
- }
- }
|