Skip to content

Commit

Permalink
test: add more tests
Browse files Browse the repository at this point in the history
More to come.

Signed-off-by: Alexey Palazhchenko <alexey.palazhchenko@talos-systems.com>
  • Loading branch information
AlekSi committed Sep 9, 2021
1 parent bc4105d commit e5b7738
Show file tree
Hide file tree
Showing 7 changed files with 238 additions and 104 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ env-up: talosctl ## Start development environment.
--name=cabpt-env \
--kubernetes-version=$(K8S_VERSION) \
--mtu=1450 \
--skip-kubeconfig \
--crashdump
./talosctl kubeconfig kubeconfig \
--talosconfig=talosconfig \
Expand Down
1 change: 1 addition & 0 deletions controllers/talosconfig_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/source"

bootstrapv1alpha3 "github.com/talos-systems/cluster-api-bootstrap-provider-talos/api/v1alpha3"
// +kubebuilder:scaffold:imports
)

const (
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/talos-systems/cluster-api-bootstrap-provider-talos
go 1.16

require (
github.com/AlekSi/pointer v1.1.0
github.com/evanphx/json-patch v4.11.0+incompatible
github.com/go-logr/logr v0.1.0
github.com/spf13/pflag v1.0.5
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,7 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down
150 changes: 150 additions & 0 deletions internal/integration/helpers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package integration

import (
"context"
"flag"
"fmt"
"os"
"strconv"
"strings"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/talos-systems/talos/pkg/machinery/config"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/scheme"
capiv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

bootstrapv1alpha3 "github.com/talos-systems/cluster-api-bootstrap-provider-talos/api/v1alpha3"
// +kubebuilder:scaffold:imports
)

var skipCleanup bool

func init() {
const env = "INTEGRATION_SKIP_CLEANUP"
def, _ := strconv.ParseBool(os.Getenv(env))
flag.BoolVar(&skipCleanup, "skip-cleanup", def, fmt.Sprintf("Cleanup after tests [%s]", env))
}

// sleepCtx blocks until ctx is canceled or timeout passed.
func sleepCtx(ctx context.Context, timeout time.Duration) {
sCtx, sCancel := context.WithTimeout(ctx, timeout)
defer sCancel()
<-sCtx.Done()
}

// generateName generates a unique name.
func generateName(t *testing.T, kind string) string {
// use milliseconds since UTC midnight: unique enough, short enough, ordered
now := time.Now().UTC()
clock := time.Duration(now.Hour())*time.Hour +
time.Duration(now.Minute())*time.Minute +
time.Duration(now.Second())*time.Second +
time.Duration(now.Nanosecond())
n := clock / time.Microsecond

return fmt.Sprintf("%s-%s-%d", strings.ReplaceAll(strings.ToLower(t.Name()), "/", "-"), kind, n)
}

// createCluster creates a Cluster with "ready" infrastructure.
func createCluster(ctx context.Context, t *testing.T, c client.Client, namespaceName string) *capiv1.Cluster {
t.Helper()

clusterName := generateName(t, "cluster")
cluster := &capiv1.Cluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespaceName,
Name: clusterName,
},
Spec: capiv1.ClusterSpec{
ClusterNetwork: &capiv1.ClusterNetwork{},
},
}

require.NoError(t, c.Create(ctx, cluster), "can't create a cluster")

cluster.Status.InfrastructureReady = true
require.NoError(t, c.Status().Update(ctx, cluster))

return cluster
}

// createMachine creates a Machine owned by the Cluster.
func createMachine(ctx context.Context, t *testing.T, c client.Client, cluster *capiv1.Cluster) *capiv1.Machine {
t.Helper()

machineName := generateName(t, "machine")
dataSecretName := "my-test-secret"
machine := &capiv1.Machine{
ObjectMeta: metav1.ObjectMeta{
Namespace: cluster.Namespace,
Name: machineName,
},
Spec: capiv1.MachineSpec{
ClusterName: cluster.Name,
Bootstrap: capiv1.Bootstrap{
DataSecretName: &dataSecretName, // TODO
},
},
}

require.NoError(t, controllerutil.SetOwnerReference(cluster, machine, scheme.Scheme))

require.NoError(t, c.Create(ctx, machine))

return machine
}

// createTalosConfig creates a TalosConfig owned by the Machine.
func createTalosConfig(ctx context.Context, t *testing.T, c client.Client, machine *capiv1.Machine) *bootstrapv1alpha3.TalosConfig {
t.Helper()

talosConfigName := generateName(t, "talosconfig")
talosConfig := &bootstrapv1alpha3.TalosConfig{
ObjectMeta: metav1.ObjectMeta{
Namespace: machine.Namespace,
Name: talosConfigName,
},
Spec: bootstrapv1alpha3.TalosConfigSpec{
GenerateType: "init",
},
}

require.NoError(t, controllerutil.SetOwnerReference(machine, talosConfig, scheme.Scheme))

require.NoError(t, c.Create(ctx, talosConfig))

// TODO that should not be needed
if !skipCleanup {
t.Cleanup(func() {
t.Logf("Deleting TalosConfig %q ...", talosConfigName)
assert.NoError(t, c.Delete(context.Background(), talosConfig)) // not ctx because it can be already canceled
})
}

return talosConfig
}

type runtimeMode struct {
requiresInstall bool
}

func (m runtimeMode) String() string {
return fmt.Sprintf("runtimeMode(%v)", m.requiresInstall)
}

func (m runtimeMode) RequiresInstall() bool {
return m.requiresInstall
}

// check interface
var _ config.RuntimeMode = runtimeMode{}
143 changes: 71 additions & 72 deletions internal/integration/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,99 +8,98 @@ import (
"testing"
"time"

"github.com/AlekSi/pointer"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/talos-systems/talos/pkg/machinery/client"
clientconfig "github.com/talos-systems/talos/pkg/machinery/client/config"
"github.com/talos-systems/talos/pkg/machinery/config"
"github.com/talos-systems/talos/pkg/machinery/config/configloader"
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes/scheme"
capiv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

bootstrapv1alpha3 "github.com/talos-systems/cluster-api-bootstrap-provider-talos/api/v1alpha3"
// +kubebuilder:scaffold:imports
)

func TestIntegration(t *testing.T) {
ctx, c := setupSuite(t)

// namespaced objects
var (
clusterName = "test-cluster"
machineName = "test-machine"
dataSecretName = "test-secret"
talosConfigName = "test-config"
)

t.Run("Basic", func(t *testing.T) {
t.Parallel()
namespaceName := setupTest(ctx, t, c)

cluster := &capiv1.Cluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespaceName,
Name: clusterName,
},
Spec: capiv1.ClusterSpec{
ClusterNetwork: &capiv1.ClusterNetwork{
Pods: &capiv1.NetworkRanges{
CIDRBlocks: []string{"192.168.0.0/16"},
},
ServiceDomain: "cluster.local",
Services: &capiv1.NetworkRanges{
CIDRBlocks: []string{"10.128.0.0/12"},
},
},
},
}
require.NoError(t, c.Create(ctx, cluster), "can't create a cluster")

cluster.Status.InfrastructureReady = true
require.NoError(t, c.Status().Update(ctx, cluster))

machine := &capiv1.Machine{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespaceName,
Name: machineName,
},
Spec: capiv1.MachineSpec{
ClusterName: cluster.Name,
Bootstrap: capiv1.Bootstrap{
DataSecretName: &dataSecretName,
},
},
}

require.NoError(t, controllerutil.SetOwnerReference(cluster, machine, scheme.Scheme))
require.NoError(t, c.Create(ctx, machine))

config := &bootstrapv1alpha3.TalosConfig{
ObjectMeta: metav1.ObjectMeta{
Namespace: namespaceName,
Name: talosConfigName,
},
Spec: bootstrapv1alpha3.TalosConfigSpec{
GenerateType: "init",
},
}
require.NoError(t, controllerutil.SetOwnerReference(machine, config, scheme.Scheme))

err := c.Create(ctx, config)
require.NoError(t, err)
namespaceName := setupTest(ctx, t, c)
cluster := createCluster(ctx, t, c, namespaceName)
machine := createMachine(ctx, t, c, cluster)
talosConfig := createTalosConfig(ctx, t, c, machine)

// wait for TalosConfig to be reconciled
for ctx.Err() == nil {
key := types.NamespacedName{
Namespace: namespaceName,
Name: talosConfigName,
Name: talosConfig.Name,
}

err = c.Get(ctx, key, config)
err := c.Get(ctx, key, talosConfig)
require.NoError(t, err)

if config.Status.Ready {
if talosConfig.Status.Ready {
break
}

t.Logf("Config: %+v", config)
time.Sleep(5 * time.Second)
t.Log("Waiting ...")
sleepCtx(ctx, 5*time.Second)
}

assert.Equal(t, machine.Name+"-bootstrap-data", pointer.GetString(talosConfig.Status.DataSecretName), "%+v", talosConfig)

clientConfig, err := clientconfig.FromString(talosConfig.Status.TalosConfig)
require.NoError(t, err)
assert.Len(t, clientConfig.Contexts, 1)
assert.NotEmpty(t, clientConfig.Context)
context := clientConfig.Contexts[clientConfig.Context]
require.NotNil(t, context)

assert.Empty(t, context.Endpoints)
assert.Empty(t, context.Nodes)
creds, err := client.CredentialsFromConfigContext(context)
require.NoError(t, err)
assert.NotEmpty(t, creds.CA)

var caSecret corev1.Secret
key := types.NamespacedName{
Namespace: namespaceName,
Name: cluster.Name + "-ca",
}
require.NoError(t, c.Get(ctx, key, &caSecret))
assert.Len(t, caSecret.Data, 2)
assert.Equal(t, corev1.SecretTypeOpaque, caSecret.Type) // TODO why not SecretTypeTLS?
assert.NotEmpty(t, creds.Crt.Certificate, caSecret.Data[corev1.TLSCertKey]) // TODO decode and load
assert.NotEmpty(t, caSecret.Data[corev1.TLSPrivateKeyKey])

var talosSecret corev1.Secret
key = types.NamespacedName{
Namespace: namespaceName,
Name: cluster.Name + "-talos",
}
require.NoError(t, c.Get(ctx, key, &talosSecret))
assert.Len(t, talosSecret.Data, 3)
assert.NotEmpty(t, talosSecret.Data["certs"]) // TODO more tests
assert.NotEmpty(t, talosSecret.Data["kubeSecrets"])
assert.NotEmpty(t, talosSecret.Data["trustdInfo"])

var bootstrapDataSecret corev1.Secret
key = types.NamespacedName{
Namespace: namespaceName,
Name: machine.Name + "-bootstrap-data",
}
require.NoError(t, c.Get(ctx, key, &bootstrapDataSecret))
assert.Len(t, bootstrapDataSecret.Data, 1)
provider, err := configloader.NewFromBytes(bootstrapDataSecret.Data["value"])
require.NoError(t, err)

provider.(*v1alpha1.Config).ClusterConfig.ControlPlane.Endpoint.Host = "FIXME"

// TODO more tests
_, err = provider.Validate(runtimeMode{false}, config.WithStrict())
require.NoError(t, err)
})
}
Loading

0 comments on commit e5b7738

Please sign in to comment.