Skip to content

Commit 9351d5e

Browse files
authored
Merge pull request #3433 from ntnn/test-integration-2
Rework test/integration framework
2 parents 89f3858 + e457ca3 commit 9351d5e

File tree

6 files changed

+293
-200
lines changed

6 files changed

+293
-200
lines changed

sdk/testing/server/config.go

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@ limitations under the License.
1616

1717
package server
1818

19-
import "path/filepath"
19+
import (
20+
"fmt"
21+
"path/filepath"
22+
"strconv"
23+
24+
utilfeature "k8s.io/apiserver/pkg/util/feature"
25+
)
2026

2127
// Config qualify a kcp server to start
2228
//
@@ -33,6 +39,43 @@ type Config struct {
3339
RunInProcess bool
3440
}
3541

42+
func (c Config) KubeconfigPath() string {
43+
return filepath.Join(c.DataDir, "admin.kubeconfig")
44+
}
45+
46+
func (c Config) BuildArgs(t TestingT) ([]string, error) {
47+
kcpListenPort, err := GetFreePort(t)
48+
if err != nil {
49+
return nil, err
50+
}
51+
etcdClientPort, err := GetFreePort(t)
52+
if err != nil {
53+
return nil, err
54+
}
55+
etcdPeerPort, err := GetFreePort(t)
56+
if err != nil {
57+
return nil, err
58+
}
59+
60+
args := []string{
61+
"--root-directory", c.DataDir,
62+
"--secure-port=" + kcpListenPort,
63+
"--embedded-etcd-client-port=" + etcdClientPort,
64+
"--embedded-etcd-peer-port=" + etcdPeerPort,
65+
"--embedded-etcd-wal-size-bytes=" + strconv.Itoa(5*1000), // 5KB
66+
"--kubeconfig-path=" + c.KubeconfigPath(),
67+
"--feature-gates=" + fmt.Sprintf("%s", utilfeature.DefaultFeatureGate),
68+
"--audit-log-path", filepath.Join(c.ArtifactDir, "kcp.audit"),
69+
"--v=4",
70+
}
71+
72+
if c.BindAddress != "" {
73+
args = append(args, "--bind-address="+c.BindAddress)
74+
}
75+
76+
return append(args, c.Args...), nil
77+
}
78+
3679
// Option a function that wish to modify a given kcp configuration.
3780
type Option func(*Config)
3881

sdk/testing/server/external.go

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ package server
1818

1919
import (
2020
"bytes"
21+
"context"
2122
cryptorand "crypto/rand"
2223
"crypto/rsa"
2324
"crypto/tls"
2425
"crypto/x509"
2526
"crypto/x509/pkix"
2627
"encoding/pem"
28+
"errors"
2729
"fmt"
2830
"math/big"
2931
"os"
@@ -34,6 +36,7 @@ import (
3436

3537
"k8s.io/apimachinery/pkg/runtime"
3638
"k8s.io/apimachinery/pkg/util/sets"
39+
"k8s.io/apimachinery/pkg/util/wait"
3740
"k8s.io/client-go/rest"
3841
"k8s.io/client-go/tools/clientcmd"
3942
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
@@ -48,14 +51,14 @@ import (
4851
// the configuration can be loaded synchronously and no locking is
4952
// required to subsequently access it.
5053
func NewExternalKCPServer(name, kubeconfigPath string, shardKubeconfigPaths map[string]string, clientCADir string) (RunningServer, error) {
51-
cfg, err := loadKubeConfig(kubeconfigPath, "base")
54+
cfg, err := LoadKubeConfig(kubeconfigPath, "base")
5255
if err != nil {
5356
return nil, err
5457
}
5558

5659
shardCfgs := map[string]clientcmd.ClientConfig{}
5760
for shard, path := range shardKubeconfigPaths {
58-
shardCfg, err := loadKubeConfig(path, "base")
61+
shardCfg, err := LoadKubeConfig(path, "base")
5962
if err != nil {
6063
return nil, err
6164
}
@@ -169,17 +172,19 @@ func (s *externalKCPServer) Stopped() bool {
169172
return false
170173
}
171174

175+
var ErrEmptyKubeConfig = fmt.Errorf("kubeconfig is empty")
176+
172177
// LoadKubeConfig loads a kubeconfig from disk. This method is
173178
// intended to be common between fixture for servers whose lifecycle
174179
// is test-managed and fixture for servers whose lifecycle is managed
175180
// separately from a test run.
176-
func loadKubeConfig(kubeconfigPath, contextName string) (clientcmd.ClientConfig, error) {
181+
func LoadKubeConfig(kubeconfigPath, contextName string) (clientcmd.ClientConfig, error) {
177182
fs, err := os.Stat(kubeconfigPath)
178183
if err != nil {
179184
return nil, err
180185
}
181186
if fs.Size() == 0 {
182-
return nil, fmt.Errorf("%s points to an empty file", kubeconfigPath)
187+
return nil, ErrEmptyKubeConfig
183188
}
184189

185190
rawConfig, err := clientcmd.LoadFromFile(kubeconfigPath)
@@ -190,6 +195,29 @@ func loadKubeConfig(kubeconfigPath, contextName string) (clientcmd.ClientConfig,
190195
return clientcmd.NewNonInteractiveClientConfig(*rawConfig, contextName, nil, nil), nil
191196
}
192197

198+
// WaitLoadKubeConfig wraps LoadKubeConfig and waits until the context
199+
// is cancelled, two minutes have passed, or the kubeconfig file is
200+
// loaded without error.
201+
func WaitLoadKubeConfig(ctx context.Context, kubeconfigPath, contextName string) (clientcmd.ClientConfig, error) {
202+
var config clientcmd.ClientConfig
203+
if err := wait.PollUntilContextTimeout(ctx, 100*time.Millisecond, 2*time.Minute, true,
204+
func(ctx context.Context) (bool, error) {
205+
loaded, err := LoadKubeConfig(kubeconfigPath, contextName)
206+
if err != nil {
207+
if os.IsNotExist(err) || errors.Is(ErrEmptyKubeConfig, err) {
208+
return false, nil
209+
}
210+
return false, err
211+
}
212+
config = loaded
213+
return true, nil
214+
},
215+
); err != nil {
216+
return nil, err
217+
}
218+
return config, nil
219+
}
220+
193221
// clientCAUserConfig returns a config based on a dynamically created client certificate.
194222
// The returned client CA is signed by "test/e2e/framework/client-ca.crt".
195223
func clientCAUserConfig(t TestingT, cfg *rest.Config, clientCAConfigDirectory, username string, groups ...string) *rest.Config {

sdk/testing/server/fixture.go

Lines changed: 18 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import (
2727
"path"
2828
"path/filepath"
2929
"runtime/debug"
30-
"strconv"
3130
"strings"
3231
"sync"
3332
"syscall"
@@ -41,7 +40,6 @@ import (
4140
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
4241
"k8s.io/apimachinery/pkg/runtime"
4342
"k8s.io/apimachinery/pkg/util/wait"
44-
utilfeature "k8s.io/apiserver/pkg/util/feature"
4543
kubernetesscheme "k8s.io/client-go/kubernetes/scheme"
4644
"k8s.io/client-go/rest"
4745
"k8s.io/client-go/tools/clientcmd"
@@ -190,37 +188,6 @@ func newKcpServer(t TestingT, cfg Config) (*kcpServer, error) {
190188
return nil, fmt.Errorf("could not create data dir: %w", err)
191189
}
192190

193-
kcpListenPort, err := GetFreePort(t)
194-
if err != nil {
195-
return nil, err
196-
}
197-
etcdClientPort, err := GetFreePort(t)
198-
if err != nil {
199-
return nil, err
200-
}
201-
etcdPeerPort, err := GetFreePort(t)
202-
if err != nil {
203-
return nil, err
204-
}
205-
206-
args := []string{
207-
"--root-directory", s.cfg.DataDir,
208-
"--secure-port=" + kcpListenPort,
209-
"--embedded-etcd-client-port=" + etcdClientPort,
210-
"--embedded-etcd-peer-port=" + etcdPeerPort,
211-
"--embedded-etcd-wal-size-bytes=" + strconv.Itoa(5*1000), // 5KB
212-
"--kubeconfig-path=" + s.KubeconfigPath(),
213-
"--feature-gates=" + fmt.Sprintf("%s", utilfeature.DefaultFeatureGate),
214-
"--audit-log-path", filepath.Join(s.cfg.ArtifactDir, "kcp.audit"),
215-
"--v=4",
216-
}
217-
218-
if cfg.BindAddress != "" {
219-
args = append(args, "--bind-address="+cfg.BindAddress)
220-
}
221-
222-
s.cfg.Args = append(args, s.cfg.Args...)
223-
224191
return s, nil
225192
}
226193

@@ -278,7 +245,11 @@ func (c *kcpServer) Run(t TestingT) error {
278245
runner = func(ctx context.Context, t TestingT, cfg Config) (<-chan struct{}, error) {
279246
t.Log("RunInProcessFunc is deprecated, please migrate to ContextRunInProcessFunc")
280247
t.Log("RunInProcessFunc is deprecated, stopping the server will not work")
281-
return RunInProcessFunc(t, cfg.DataDir, cfg.Args)
248+
args, err := cfg.BuildArgs(t)
249+
if err != nil {
250+
return nil, err
251+
}
252+
return RunInProcessFunc(t, cfg.DataDir, args)
282253
}
283254
}
284255
}
@@ -325,7 +296,12 @@ func (c *kcpServer) Stopped() bool {
325296
}
326297

327298
func runExternal(ctx context.Context, t TestingT, cfg Config) (<-chan struct{}, error) {
328-
commandLine := append(StartKcpCommand("KCP"), cfg.Args...)
299+
args, err := cfg.BuildArgs(t)
300+
if err != nil {
301+
return nil, fmt.Errorf("failed to build kcp args: %w", err)
302+
}
303+
304+
commandLine := append(StartKcpCommand("KCP"), args...)
329305

330306
t.Logf("running: %v", strings.Join(commandLine, " "))
331307

@@ -438,7 +414,7 @@ func (c *kcpServer) Name() string {
438414

439415
// KubeconfigPath exposes the path of the kubeconfig file of this kcp server.
440416
func (c *kcpServer) KubeconfigPath() string {
441-
return filepath.Join(c.cfg.DataDir, "admin.kubeconfig")
417+
return c.cfg.KubeconfigPath()
442418
}
443419

444420
// Config exposes a copy of the base client config for this server. Client-side throttling is disabled (QPS=-1).
@@ -515,35 +491,13 @@ func (c *kcpServer) RawConfig() (clientcmdapi.Config, error) {
515491
}
516492

517493
func (c *kcpServer) loadCfg(ctx context.Context) error {
518-
var lastError error
519-
if err := wait.PollUntilContextTimeout(ctx, 100*time.Millisecond, 2*time.Minute, true, func(ctx context.Context) (bool, error) {
520-
if c.Stopped() {
521-
return false, fmt.Errorf("failed to load admin kubeconfig: server has stopped")
522-
}
523-
524-
config, err := loadKubeConfig(c.KubeconfigPath(), "base")
525-
if err != nil {
526-
// A missing file is likely caused by the server not
527-
// having started up yet. Ignore these errors for the
528-
// purposes of logging.
529-
if !os.IsNotExist(err) {
530-
lastError = err
531-
}
532-
533-
return false, nil
534-
}
535-
536-
c.lock.Lock()
537-
c.clientCfg = config
538-
c.lock.Unlock()
539-
540-
return true, nil
541-
}); err != nil && lastError != nil {
542-
return fmt.Errorf("failed to load admin kubeconfig: %w", lastError)
543-
} else if err != nil {
544-
// should never happen
545-
return fmt.Errorf("failed to load admin kubeconfig: %w", err)
494+
config, err := WaitLoadKubeConfig(ctx, c.KubeconfigPath(), "base")
495+
if err != nil {
496+
return err
546497
}
498+
c.lock.Lock()
499+
c.clientCfg = config
500+
c.lock.Unlock()
547501
return nil
548502
}
549503

test/e2e/framework/inprocess.go

Lines changed: 0 additions & 102 deletions
This file was deleted.

0 commit comments

Comments
 (0)