feat: update golangci-lint to 1.45.0 and gofumpt to 0.3.0

- Update golangci-lint to 1.45.0
- Update gofumpt to 0.3.0
- Fix gofumpt errors
- Add goimports and format imports since gofumports is removed
- Update Dockerfile
- Fix .golangci.yml configuration
- Fix linting errors

Signed-off-by: Dmitriy Matrenichev <dmitry.matrenichev@siderolabs.com>
This commit is contained in:
Dmitriy Matrenichev 2022-03-23 11:49:07 +04:00
parent a92c614b2f
commit e06e1473b0
No known key found for this signature in database
GPG Key ID: D3363CF894E68892
127 changed files with 7058 additions and 5010 deletions

View File

@ -119,7 +119,10 @@ linters-settings:
range-loops: true # Report preallocation suggestions on range loops, true by default range-loops: true # Report preallocation suggestions on range loops, true by default
for-loops: false # Report preallocation suggestions on for loops, false by default for-loops: false # Report preallocation suggestions on for loops, false by default
gci: gci:
local-prefixes: github.com/talos-systems/talos sections:
- standard # Captures all standard packages if they do not match another section.
- default # Contains all imports that could not be matched to another section type.
- prefix(github.com/talos-systems/talos) # Groups all imports with the specified Prefix.
cyclop: cyclop:
# the maximal code complexity to report # the maximal code complexity to report
max-complexity: 20 max-complexity: 20
@ -138,6 +141,7 @@ linters:
- errorlint - errorlint
- exhaustivestruct - exhaustivestruct
- forbidigo - forbidigo
- forcetypeassert
- funlen - funlen
- gas - gas
- gochecknoglobals - gochecknoglobals
@ -148,6 +152,7 @@ linters:
- gomnd - gomnd
- ifshort - ifshort
- ireturn # we return interfaces - ireturn # we return interfaces
- maintidx
- nestif - nestif
- nilnil # we return "nil, nil" - nilnil # we return "nil, nil"
- paralleltest - paralleltest
@ -199,10 +204,10 @@ issues:
exclude-use-default: false exclude-use-default: false
# Maximum issues count per one linter. Set to 0 to disable. Default is 50. # Maximum issues count per one linter. Set to 0 to disable. Default is 50.
max-per-linter: 0 max-issues-per-linter: 0
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3. # Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
max-same: 0 max-same-issues: 0
# Show only new issues: if there are unstaged changes or untracked files, # Show only new issues: if there are unstaged changes or untracked files,
# only those changes are analyzed, else only changes in HEAD~ are analyzed. # only those changes are analyzed, else only changes in HEAD~ are analyzed.

View File

@ -96,9 +96,12 @@ RUN ["/toolchain/bin/ln", "-svf", "/toolchain/bin/bash", "/bin/sh"]
RUN ["/toolchain/bin/ln", "-svf", "/toolchain/etc/ssl", "/etc/ssl"] RUN ["/toolchain/bin/ln", "-svf", "/toolchain/etc/ssl", "/etc/ssl"]
ARG GOLANGCILINT_VERSION ARG GOLANGCILINT_VERSION
RUN curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/${GOLANGCILINT_VERSION}/install.sh | bash -s -- -b /toolchain/bin ${GOLANGCILINT_VERSION} RUN curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/${GOLANGCILINT_VERSION}/install.sh | bash -s -- -b /toolchain/bin ${GOLANGCILINT_VERSION}
ARG GOIMPORTS_VERSION
RUN go install golang.org/x/tools/cmd/goimports@${GOIMPORTS_VERSION} \
&& mv /go/bin/goimports /toolchain/go/bin/goimports
ARG GOFUMPT_VERSION ARG GOFUMPT_VERSION
RUN go install mvdan.cc/gofumpt/gofumports@${GOFUMPT_VERSION} \ RUN go install mvdan.cc/gofumpt@${GOFUMPT_VERSION} \
&& mv /go/bin/gofumports /toolchain/go/bin/gofumports && mv /go/bin/gofumpt /toolchain/go/bin/gofumpt
ARG STRINGER_VERSION ARG STRINGER_VERSION
RUN go install golang.org/x/tools/cmd/stringer@${STRINGER_VERSION} \ RUN go install golang.org/x/tools/cmd/stringer@${STRINGER_VERSION} \
&& mv /go/bin/stringer /toolchain/go/bin/stringer && mv /go/bin/stringer /toolchain/go/bin/stringer
@ -190,18 +193,21 @@ COPY ./api/resource/secrets/secrets.proto /api/resource/secrets/secrets.proto
RUN protoc -I/api -I/api/vendor/ --go_out=paths=source_relative:/api --go-grpc_out=paths=source_relative:/api --go-vtproto_out=paths=source_relative:/api --go-vtproto_opt=features=marshal+unmarshal+size resource/secrets/secrets.proto RUN protoc -I/api -I/api/vendor/ --go_out=paths=source_relative:/api --go-grpc_out=paths=source_relative:/api --go-vtproto_out=paths=source_relative:/api --go-vtproto_opt=features=marshal+unmarshal+size resource/secrets/secrets.proto
COPY ./api/inspect/inspect.proto /api/inspect/inspect.proto COPY ./api/inspect/inspect.proto /api/inspect/inspect.proto
RUN protoc -I/api -I/api/vendor/ --go_out=paths=source_relative:/api --go-grpc_out=paths=source_relative:/api --go-vtproto_out=paths=source_relative:/api --go-vtproto_opt=features=marshal+unmarshal+size inspect/inspect.proto RUN protoc -I/api -I/api/vendor/ --go_out=paths=source_relative:/api --go-grpc_out=paths=source_relative:/api --go-vtproto_out=paths=source_relative:/api --go-vtproto_opt=features=marshal+unmarshal+size inspect/inspect.proto
# Gofumports generated files to adjust import order # Goimports and gofumpt generated files to adjust import order
RUN gofumports -w -local github.com/talos-systems/talos /api/ RUN goimports -w -local github.com/talos-systems/talos /api/
RUN gofumpt -w /api/
# run docgen for machinery config # run docgen for machinery config
FROM build-go AS go-generate FROM build-go AS go-generate
COPY ./pkg ./pkg COPY ./pkg ./pkg
COPY ./hack/boilerplate.txt ./hack/boilerplate.txt COPY ./hack/boilerplate.txt ./hack/boilerplate.txt
RUN --mount=type=cache,target=/.cache go generate ./pkg/... RUN --mount=type=cache,target=/.cache go generate ./pkg/...
RUN gofumports -w -local github.com/talos-systems/talos ./pkg/ RUN goimports -w -local github.com/talos-systems/talos ./pkg/
RUN gofumpt -w ./pkg/
WORKDIR /src/pkg/machinery WORKDIR /src/pkg/machinery
RUN --mount=type=cache,target=/.cache go generate ./... RUN --mount=type=cache,target=/.cache go generate ./...
RUN gofumports -w -local github.com/talos-systems/talos ./ RUN goimports -w -local github.com/talos-systems/talos ./
RUN gofumpt -w ./
FROM --platform=${BUILDPLATFORM} scratch AS generate FROM --platform=${BUILDPLATFORM} scratch AS generate
COPY --from=proto-format-build /src/api /api/ COPY --from=proto-format-build /src/api /api/
@ -660,8 +666,6 @@ WORKDIR /src/pkg/machinery
RUN --mount=type=cache,target=/.cache golangci-lint run --config ../../.golangci.yml RUN --mount=type=cache,target=/.cache golangci-lint run --config ../../.golangci.yml
WORKDIR /src WORKDIR /src
RUN --mount=type=cache,target=/.cache importvet github.com/talos-systems/talos/... RUN --mount=type=cache,target=/.cache importvet github.com/talos-systems/talos/...
RUN find . -name '*.pb.go' -o -name '*_string_*.go' | xargs rm
RUN --mount=type=cache,target=/.cache FILES="$(gofumports -l -local github.com/talos-systems/talos .)" && test -z "${FILES}" || (echo -e "Source code is not formatted with 'gofumports -w -local github.com/talos-systems/talos .':\n${FILES}"; exit 1)
# The protolint target performs linting on protobuf files. # The protolint target performs linting on protobuf files.

View File

@ -16,8 +16,9 @@ TOOLS ?= ghcr.io/siderolabs/tools:v1.1.0-alpha.0-1-g99be089
PKGS ?= v1.1.0-alpha.0-5-g58603ba PKGS ?= v1.1.0-alpha.0-5-g58603ba
EXTRAS ?= v1.0.0 EXTRAS ?= v1.0.0
GO_VERSION ?= 1.17 GO_VERSION ?= 1.17
GOFUMPT_VERSION ?= v0.1.1 GOIMPORTS_VERSION ?= v0.1.10
GOLANGCILINT_VERSION ?= v1.43.0 GOFUMPT_VERSION ?= v0.3.0
GOLANGCILINT_VERSION ?= v1.45.0
STRINGER_VERSION ?= v0.1.5 STRINGER_VERSION ?= v0.1.5
ENUMER_VERSION ?= v1.1.2 ENUMER_VERSION ?= v1.1.2
DEEPCOPY_GEN_VERSION ?= v0.21.3 DEEPCOPY_GEN_VERSION ?= v0.21.3
@ -85,6 +86,7 @@ COMMON_ARGS += --build-arg=TOOLS=$(TOOLS)
COMMON_ARGS += --build-arg=PKGS=$(PKGS) COMMON_ARGS += --build-arg=PKGS=$(PKGS)
COMMON_ARGS += --build-arg=EXTRAS=$(EXTRAS) COMMON_ARGS += --build-arg=EXTRAS=$(EXTRAS)
COMMON_ARGS += --build-arg=GOFUMPT_VERSION=$(GOFUMPT_VERSION) COMMON_ARGS += --build-arg=GOFUMPT_VERSION=$(GOFUMPT_VERSION)
COMMON_ARGS += --build-arg=GOIMPORTS_VERSION=$(GOIMPORTS_VERSION)
COMMON_ARGS += --build-arg=STRINGER_VERSION=$(STRINGER_VERSION) COMMON_ARGS += --build-arg=STRINGER_VERSION=$(STRINGER_VERSION)
COMMON_ARGS += --build-arg=ENUMER_VERSION=$(ENUMER_VERSION) COMMON_ARGS += --build-arg=ENUMER_VERSION=$(ENUMER_VERSION)
COMMON_ARGS += --build-arg=DEEPCOPY_GEN_VERSION=$(DEEPCOPY_GEN_VERSION) COMMON_ARGS += --build-arg=DEEPCOPY_GEN_VERSION=$(DEEPCOPY_GEN_VERSION)
@ -272,7 +274,7 @@ api-descriptors: ## Generates API descriptors used to detect breaking API change
@$(MAKE) local-api-descriptors DEST=./ PLATFORM=linux/amd64 @$(MAKE) local-api-descriptors DEST=./ PLATFORM=linux/amd64
fmt-go: ## Formats the source code. fmt-go: ## Formats the source code.
@docker run --rm -it -v $(PWD):/src -w /src golang:$(GO_VERSION) bash -c "go install mvdan.cc/gofumpt/gofumports@$(GOFUMPT_VERSION) && gofumports -w -local github.com/talos-systems/talos ." @docker run --rm -it -v $(PWD):/src -w /src golang:$(GO_VERSION) bash -c "go install golang.org/x/tools/cmd/goimports@$(GOIMPORTS_VERSION) && goimports -w -local github.com/talos-systems/talos . && go install mvdan.cc/gofumpt@$(GOFUMPT_VERSION) && gofumpt -w ."
fmt-protobuf: ## Formats protobuf files. fmt-protobuf: ## Formats protobuf files.
@$(MAKE) local-fmt-protobuf DEST=./ PLATFORM=linux/amd64 @$(MAKE) local-fmt-protobuf DEST=./ PLATFORM=linux/amd64

View File

@ -123,7 +123,8 @@ func GenV1Alpha1Config(genOptions []generate.GenOption,
kubernetesVersion string, kubernetesVersion string,
configPatch []string, configPatch []string,
configPatchControlPlane []string, configPatchControlPlane []string,
configPatchWorker []string) (*v1alpha1.ConfigBundle, error) { configPatchWorker []string,
) (*v1alpha1.ConfigBundle, error) {
configBundleOpts := []bundle.Option{ configBundleOpts := []bundle.Option{
bundle.WithInputOptions( bundle.WithInputOptions(
&bundle.InputOptions{ &bundle.InputOptions{

View File

@ -22,7 +22,7 @@ type APISource struct {
Interval time.Duration Interval time.Duration
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
wg sync.WaitGroup wg sync.WaitGroup

View File

@ -20,7 +20,7 @@ import (
"google.golang.org/grpc/peer" "google.golang.org/grpc/peer"
"github.com/talos-systems/talos/pkg/cli" "github.com/talos-systems/talos/pkg/cli"
_ "github.com/talos-systems/talos/pkg/grpc/codec" //nolint:gci // register codec _ "github.com/talos-systems/talos/pkg/grpc/codec" // register codec
"github.com/talos-systems/talos/pkg/machinery/api/common" "github.com/talos-systems/talos/pkg/machinery/api/common"
machineapi "github.com/talos-systems/talos/pkg/machinery/api/machine" machineapi "github.com/talos-systems/talos/pkg/machinery/api/machine"
"github.com/talos-systems/talos/pkg/machinery/client" "github.com/talos-systems/talos/pkg/machinery/client"
@ -44,90 +44,96 @@ const pathAutoCompleteLimit = 500
// //
// WithClientNoNodes doesn't set any node information on request context. // WithClientNoNodes doesn't set any node information on request context.
func WithClientNoNodes(action func(context.Context, *client.Client) error) error { func WithClientNoNodes(action func(context.Context, *client.Client) error) error {
return cli.WithContext(context.Background(), func(ctx context.Context) error { return cli.WithContext(
cfg, err := clientconfig.Open(Talosconfig) context.Background(), func(ctx context.Context) error {
if err != nil { cfg, err := clientconfig.Open(Talosconfig)
return fmt.Errorf("failed to open config file %q: %w", Talosconfig, err) if err != nil {
} return fmt.Errorf("failed to open config file %q: %w", Talosconfig, err)
}
opts := []client.OptionFunc{ opts := []client.OptionFunc{
client.WithConfig(cfg), client.WithConfig(cfg),
} }
if Cmdcontext != "" { if Cmdcontext != "" {
opts = append(opts, client.WithContextName(Cmdcontext)) opts = append(opts, client.WithContextName(Cmdcontext))
} }
if len(Endpoints) > 0 { if len(Endpoints) > 0 {
// override endpoints from command-line flags // override endpoints from command-line flags
opts = append(opts, client.WithEndpoints(Endpoints...)) opts = append(opts, client.WithEndpoints(Endpoints...))
} }
c, err := client.New(ctx, opts...) c, err := client.New(ctx, opts...)
if err != nil { if err != nil {
return fmt.Errorf("error constructing client: %w", err) return fmt.Errorf("error constructing client: %w", err)
} }
//nolint:errcheck //nolint:errcheck
defer c.Close() defer c.Close()
return action(ctx, c) return action(ctx, c)
}) },
)
} }
// WithClient builds upon WithClientNoNodes to provide set of nodes on request context based on config & flags. // WithClient builds upon WithClientNoNodes to provide set of nodes on request context based on config & flags.
func WithClient(action func(context.Context, *client.Client) error) error { func WithClient(action func(context.Context, *client.Client) error) error {
return WithClientNoNodes(func(ctx context.Context, c *client.Client) error { return WithClientNoNodes(
if len(Nodes) < 1 { func(ctx context.Context, c *client.Client) error {
configContext := c.GetConfigContext() if len(Nodes) < 1 {
if configContext == nil { configContext := c.GetConfigContext()
return fmt.Errorf("failed to resolve config context") if configContext == nil {
return fmt.Errorf("failed to resolve config context")
}
Nodes = configContext.Nodes
} }
Nodes = configContext.Nodes if len(Nodes) < 1 {
} return fmt.Errorf("nodes are not set for the command: please use `--nodes` flag or configuration file to set the nodes to run the command against")
}
if len(Nodes) < 1 { ctx = client.WithNodes(ctx, Nodes...)
return fmt.Errorf("nodes are not set for the command: please use `--nodes` flag or configuration file to set the nodes to run the command against")
}
ctx = client.WithNodes(ctx, Nodes...) return action(ctx, c)
},
return action(ctx, c) )
})
} }
// WithClientMaintenance wraps common code to initialize Talos client in maintenance (insecure mode). // WithClientMaintenance wraps common code to initialize Talos client in maintenance (insecure mode).
func WithClientMaintenance(enforceFingerprints []string, action func(context.Context, *client.Client) error) error { func WithClientMaintenance(enforceFingerprints []string, action func(context.Context, *client.Client) error) error {
return cli.WithContext(context.Background(), func(ctx context.Context) error { return cli.WithContext(
tlsConfig := &tls.Config{ context.Background(), func(ctx context.Context) error {
InsecureSkipVerify: true, tlsConfig := &tls.Config{
} InsecureSkipVerify: true,
if len(enforceFingerprints) > 0 {
fingerprints := make([]x509.Fingerprint, len(enforceFingerprints))
for i, stringFingerprint := range enforceFingerprints {
var err error
fingerprints[i], err = x509.ParseFingerprint(stringFingerprint)
if err != nil {
return fmt.Errorf("error parsing certificate fingerprint %q: %v", stringFingerprint, err)
}
} }
tlsConfig.VerifyConnection = x509.MatchSPKIFingerprints(fingerprints...) if len(enforceFingerprints) > 0 {
} fingerprints := make([]x509.Fingerprint, len(enforceFingerprints))
c, err := client.New(ctx, client.WithTLSConfig(tlsConfig), client.WithEndpoints(Nodes...)) for i, stringFingerprint := range enforceFingerprints {
if err != nil { var err error
return err
}
//nolint:errcheck fingerprints[i], err = x509.ParseFingerprint(stringFingerprint)
defer c.Close() if err != nil {
return fmt.Errorf("error parsing certificate fingerprint %q: %v", stringFingerprint, err)
}
}
return action(ctx, c) tlsConfig.VerifyConnection = x509.MatchSPKIFingerprints(fingerprints...)
}) }
c, err := client.New(ctx, client.WithTLSConfig(tlsConfig), client.WithEndpoints(Nodes...))
if err != nil {
return err
}
//nolint:errcheck
defer c.Close()
return action(ctx, c)
},
)
} }
// Commands is a list of commands published by the package. // Commands is a list of commands published by the package.
@ -170,61 +176,66 @@ func completePathFromNode(inputPath string) []string {
func getPathFromNode(path, filter string) map[string]struct{} { func getPathFromNode(path, filter string) map[string]struct{} {
paths := make(map[string]struct{}) paths := make(map[string]struct{})
WithClient(func(ctx context.Context, c *client.Client) error { //nolint:errcheck //nolint:errcheck
ctx, cancel := context.WithCancel(ctx) WithClient(
defer cancel() func(ctx context.Context, c *client.Client) error {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
stream, err := c.LS(ctx, &machineapi.ListRequest{ stream, err := c.LS(
Root: path, ctx, &machineapi.ListRequest{
}) Root: path,
if err != nil { },
return err )
}
for {
resp, err := stream.Recv()
if err != nil { if err != nil {
if err == io.EOF || client.StatusCode(err) == codes.Canceled { return err
}
for {
resp, err := stream.Recv()
if err != nil {
if err == io.EOF || client.StatusCode(err) == codes.Canceled {
return nil
}
return fmt.Errorf("error streaming results: %s", err)
}
if resp.Metadata != nil && resp.Metadata.Error != "" {
continue
}
if resp.Error != "" {
continue
}
// skip reference to the same directory
if resp.RelativeName == "." {
continue
}
// limit the results to a reasonable amount
if len(paths) > pathAutoCompleteLimit {
return nil return nil
} }
return fmt.Errorf("error streaming results: %s", err) // directories have a trailing slash
} if resp.IsDir {
fullPath := path + resp.RelativeName + "/"
if resp.Metadata != nil && resp.Metadata.Error != "" { if relativeTo(fullPath, filter) {
continue paths[fullPath] = struct{}{}
} }
} else {
fullPath := path + resp.RelativeName
if resp.Error != "" { if relativeTo(fullPath, filter) {
continue paths[fullPath] = struct{}{}
} }
// skip reference to the same directory
if resp.RelativeName == "." {
continue
}
// limit the results to a reasonable amount
if len(paths) > pathAutoCompleteLimit {
return nil
}
// directories have a trailing slash
if resp.IsDir {
fullPath := path + resp.RelativeName + "/"
if relativeTo(fullPath, filter) {
paths[fullPath] = struct{}{}
}
} else {
fullPath := path + resp.RelativeName
if relativeTo(fullPath, filter) {
paths[fullPath] = struct{}{}
} }
} }
} },
}) )
return paths return paths
} }
@ -232,23 +243,26 @@ func getPathFromNode(path, filter string) map[string]struct{} {
func getServiceFromNode() []string { func getServiceFromNode() []string {
var svcIds []string var svcIds []string
WithClient(func(ctx context.Context, c *client.Client) error { //nolint:errcheck //nolint:errcheck
var remotePeer peer.Peer WithClient(
func(ctx context.Context, c *client.Client) error {
var remotePeer peer.Peer
resp, err := c.ServiceList(ctx, grpc.Peer(&remotePeer)) resp, err := c.ServiceList(ctx, grpc.Peer(&remotePeer))
if err != nil { if err != nil {
return err return err
}
for _, msg := range resp.Messages {
for _, s := range msg.Services {
svc := cli.ServiceInfoWrapper{ServiceInfo: s}
svcIds = append(svcIds, svc.Id)
} }
}
return nil for _, msg := range resp.Messages {
}) for _, s := range msg.Services {
svc := cli.ServiceInfoWrapper{ServiceInfo: s}
svcIds = append(svcIds, svc.Id)
}
}
return nil
},
)
return svcIds return svcIds
} }
@ -256,41 +270,44 @@ func getServiceFromNode() []string {
func getContainersFromNode(kubernetes bool) []string { func getContainersFromNode(kubernetes bool) []string {
var containerIds []string var containerIds []string
WithClient(func(ctx context.Context, c *client.Client) error { //nolint:errcheck //nolint:errcheck
var ( WithClient(
namespace string func(ctx context.Context, c *client.Client) error {
driver common.ContainerDriver var (
) namespace string
driver common.ContainerDriver
)
if kubernetes { if kubernetes {
namespace = criconstants.K8sContainerdNamespace namespace = criconstants.K8sContainerdNamespace
driver = common.ContainerDriver_CRI driver = common.ContainerDriver_CRI
} else { } else {
namespace = constants.SystemContainerdNamespace namespace = constants.SystemContainerdNamespace
driver = common.ContainerDriver_CONTAINERD driver = common.ContainerDriver_CONTAINERD
}
resp, err := c.Containers(ctx, namespace, driver)
if err != nil {
return err
}
for _, msg := range resp.Messages {
for _, p := range msg.Containers {
if p.Pid == 0 {
continue
}
if kubernetes && p.Id == p.PodId {
continue
}
containerIds = append(containerIds, p.Id)
} }
}
return nil resp, err := c.Containers(ctx, namespace, driver)
}) if err != nil {
return err
}
for _, msg := range resp.Messages {
for _, p := range msg.Containers {
if p.Pid == 0 {
continue
}
if kubernetes && p.Id == p.PodId {
continue
}
containerIds = append(containerIds, p.Id)
}
}
return nil
},
)
return containerIds return containerIds
} }

View File

@ -17,7 +17,7 @@ import (
"github.com/talos-systems/grpc-proxy/proxy" "github.com/talos-systems/grpc-proxy/proxy"
"google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
protobuf "google.golang.org/protobuf/proto" //nolint:depguard,gci protobuf "google.golang.org/protobuf/proto" //nolint:depguard
"google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/descriptorpb" "google.golang.org/protobuf/types/descriptorpb"
@ -71,38 +71,45 @@ func (suite *APIDSuite) TestGetConnection() {
suite.Assert().Equal([]string{"127.0.0.2"}, mdOut1.Get("proxyfrom")) suite.Assert().Equal([]string{"127.0.0.2"}, mdOut1.Get("proxyfrom"))
suite.Assert().Equal([]string{"os:admin"}, mdOut1.Get("talos-role")) suite.Assert().Equal([]string{"os:admin"}, mdOut1.Get("talos-role"))
suite.Run("Same context", func() { suite.Run(
ctx2 := ctx1 "Same context", func() {
outCtx2, conn2, err2 := suite.b.GetConnection(ctx2) ctx2 := ctx1
suite.Require().NoError(err2) outCtx2, conn2, err2 := suite.b.GetConnection(ctx2)
suite.Assert().Equal(conn1, conn2) // connection is cached suite.Require().NoError(err2)
suite.Assert().Equal(role.MakeSet(role.Admin), authz.GetRoles(outCtx2)) suite.Assert().Equal(conn1, conn2) // connection is cached
suite.Assert().Equal(role.MakeSet(role.Admin), authz.GetRoles(outCtx2))
mdOut2, ok2 := metadata.FromOutgoingContext(outCtx2) mdOut2, ok2 := metadata.FromOutgoingContext(outCtx2)
suite.Require().True(ok2) suite.Require().True(ok2)
suite.Assert().Equal([]string{"value1", "value2"}, mdOut2.Get("key")) suite.Assert().Equal([]string{"value1", "value2"}, mdOut2.Get("key"))
suite.Assert().Equal([]string{"127.0.0.2"}, mdOut2.Get("proxyfrom")) suite.Assert().Equal([]string{"127.0.0.2"}, mdOut2.Get("proxyfrom"))
suite.Assert().Equal([]string{"os:admin"}, mdOut2.Get("talos-role")) suite.Assert().Equal([]string{"os:admin"}, mdOut2.Get("talos-role"))
}) },
)
suite.Run("Other context", func() { suite.Run(
md3 := metadata.New(nil) "Other context", func() {
md3.Set(":authority", "127.0.0.2") md3 := metadata.New(nil)
md3.Set("nodes", "127.0.0.1") md3.Set(":authority", "127.0.0.2")
md3.Set("key", "value3", "value4") md3.Set("nodes", "127.0.0.1")
ctx3 := metadata.NewIncomingContext(authz.ContextWithRoles(context.Background(), role.MakeSet(role.Reader)), md3) md3.Set("key", "value3", "value4")
ctx3 := metadata.NewIncomingContext(
authz.ContextWithRoles(context.Background(), role.MakeSet(role.Reader)),
md3,
)
outCtx3, conn3, err3 := suite.b.GetConnection(ctx3) outCtx3, conn3, err3 := suite.b.GetConnection(ctx3)
suite.Require().NoError(err3) suite.Require().NoError(err3)
suite.Assert().Equal(conn1, conn3) // connection is cached suite.Assert().Equal(conn1, conn3) // connection is cached
suite.Assert().Equal(role.MakeSet(role.Reader), authz.GetRoles(outCtx3)) suite.Assert().Equal(role.MakeSet(role.Reader), authz.GetRoles(outCtx3))
mdOut3, ok3 := metadata.FromOutgoingContext(outCtx3) mdOut3, ok3 := metadata.FromOutgoingContext(outCtx3)
suite.Require().True(ok3) suite.Require().True(ok3)
suite.Assert().Equal([]string{"value3", "value4"}, mdOut3.Get("key")) suite.Assert().Equal([]string{"value3", "value4"}, mdOut3.Get("key"))
suite.Assert().Equal([]string{"127.0.0.2"}, mdOut3.Get("proxyfrom")) suite.Assert().Equal([]string{"127.0.0.2"}, mdOut3.Get("proxyfrom"))
suite.Assert().Equal([]string{"os:reader"}, mdOut3.Get("talos-role")) suite.Assert().Equal([]string{"os:reader"}, mdOut3.Get("talos-role"))
}) },
)
} }
func (suite *APIDSuite) TestAppendInfoUnary() { func (suite *APIDSuite) TestAppendInfoUnary() {
@ -221,30 +228,37 @@ func TestAPIIdiosyncrasies(t *testing.T) {
for j := 0; j < methods.Len(); j++ { for j := 0; j < methods.Len(); j++ {
method := methods.Get(j) method := methods.Get(j)
t.Run(string(method.FullName()), func(t *testing.T) { t.Run(
response := method.Output() string(method.FullName()), func(t *testing.T) {
responseFields := response.Fields() response := method.Output()
responseFields := response.Fields()
if method.IsStreamingServer() { if method.IsStreamingServer() {
metadata := responseFields.Get(0) metadata := responseFields.Get(0)
assert.Equal(t, "metadata", metadata.TextName()) assert.Equal(t, "metadata", metadata.TextName())
assert.Equal(t, 1, int(metadata.Number())) assert.Equal(t, 1, int(metadata.Number()))
} else { } else {
require.Equal(t, 1, responseFields.Len(), "unary responses should have exactly one field") require.Equal(t, 1, responseFields.Len(), "unary responses should have exactly one field")
messages := responseFields.Get(0) messages := responseFields.Get(0)
assert.Equal(t, "messages", messages.TextName()) assert.Equal(t, "messages", messages.TextName())
assert.Equal(t, 1, int(messages.Number())) assert.Equal(t, 1, int(messages.Number()))
reply := messages.Message() reply := messages.Message()
replyFields := reply.Fields() replyFields := reply.Fields()
require.GreaterOrEqual(t, replyFields.Len(), 1, "unary replies should have at least one field") require.GreaterOrEqual(
t,
replyFields.Len(),
1,
"unary replies should have at least one field",
)
metadata := replyFields.Get(0) metadata := replyFields.Get(0)
assert.Equal(t, "metadata", metadata.TextName()) assert.Equal(t, "metadata", metadata.TextName())
assert.Equal(t, 1, int(metadata.Number())) assert.Equal(t, 1, int(metadata.Number()))
} }
}) },
)
} }
} }
} }
@ -294,8 +308,10 @@ func getOptions(t *testing.T, descriptor protoreflect.Descriptor) (deprecated bo
func testDeprecated(t *testing.T, descriptor protoreflect.Descriptor, currentVersion *config.VersionContract) { func testDeprecated(t *testing.T, descriptor protoreflect.Descriptor, currentVersion *config.VersionContract) {
deprecated, version := getOptions(t, descriptor) deprecated, version := getOptions(t, descriptor)
assert.Equal(t, deprecated, version != "", assert.Equal(
"%s: `deprecated` and `remove_deprecated_XXX_in` options should be used together", descriptor.FullName()) t, deprecated, version != "",
"%s: `deprecated` and `remove_deprecated_XXX_in` options should be used together", descriptor.FullName(),
)
if !deprecated || version == "" { if !deprecated || version == "" {
return return

View File

@ -47,7 +47,6 @@ func (s *InspectServer) ControllerRuntimeDependencies(ctx context.Context, in *e
} }
edges = append(edges, &inspectapi.ControllerDependencyEdge{ edges = append(edges, &inspectapi.ControllerDependencyEdge{
ControllerName: graph.Edges[i].ControllerName, ControllerName: graph.Edges[i].ControllerName,
EdgeType: edgeType, EdgeType: edgeType,

View File

@ -263,25 +263,32 @@ func run() error {
} }
// Watch and handle runtime events. // Watch and handle runtime events.
_ = c.Runtime().Events().Watch(func(events <-chan runtime.EventInfo) { //nolint:errcheck //nolint:errcheck
for { _ = c.Runtime().Events().Watch(
for event := range events { func(events <-chan runtime.EventInfo) {
switch msg := event.Payload.(type) { for {
case *machine.SequenceEvent: for event := range events {
if msg.Error != nil { switch msg := event.Payload.(type) {
if msg.Error.GetCode() == common.Code_LOCKED { case *machine.SequenceEvent:
// ignore sequence lock errors, they're not fatal if msg.Error != nil {
continue if msg.Error.GetCode() == common.Code_LOCKED {
} // ignore sequence lock errors, they're not fatal
continue
}
errCh <- fmt.Errorf("fatal sequencer error in %q sequence: %v", msg.GetSequence(), msg.GetError().String()) errCh <- fmt.Errorf(
"fatal sequencer error in %q sequence: %v",
msg.GetSequence(),
msg.GetError().String(),
)
}
case *machine.RestartEvent:
errCh <- runtime.RebootError{Cmd: int(msg.Cmd)}
} }
case *machine.RestartEvent:
errCh <- runtime.RebootError{Cmd: int(msg.Cmd)}
} }
} }
} },
}) )
return <-errCh return <-errCh
} }

View File

@ -31,7 +31,7 @@ type ClusterSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -96,10 +96,14 @@ func (suite *ClusterSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ err := suite.state.Create(
ConfigVersion: "v1alpha1", context.Background(), config.NewMachineConfig(
MachineConfig: &v1alpha1.MachineConfig{}, &v1alpha1.Config{
})) ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{},
},
),
)
if state.IsConflictError(err) { if state.IsConflictError(err) {
err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata())
} }

View File

@ -38,6 +38,7 @@ type K8sAddressFilterSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
//nolint:containedctx
ctx context.Context ctx context.Context
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -67,7 +68,10 @@ func (suite *K8sAddressFilterSuite) startRuntime() {
}() }()
} }
func (suite *K8sAddressFilterSuite) assertResource(md resource.Metadata, check func(res resource.Resource) error) func() error { func (suite *K8sAddressFilterSuite) assertResource(
md resource.Metadata,
check func(res resource.Resource) error,
) func() error {
return func() error { return func() error {
r, err := suite.state.Get(suite.ctx, md) r, err := suite.state.Get(suite.ctx, md)
if err != nil { if err != nil {
@ -86,56 +90,78 @@ func (suite *K8sAddressFilterSuite) TestReconcile() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{}, ConfigVersion: "v1alpha1",
ClusterConfig: &v1alpha1.ClusterConfig{ MachineConfig: &v1alpha1.MachineConfig{},
ControlPlane: &v1alpha1.ControlPlaneConfig{ ClusterConfig: &v1alpha1.ClusterConfig{
Endpoint: &v1alpha1.Endpoint{ ControlPlane: &v1alpha1.ControlPlaneConfig{
URL: u, Endpoint: &v1alpha1.Endpoint{
URL: u,
},
}, },
}, ClusterNetwork: &v1alpha1.ClusterNetworkConfig{
ClusterNetwork: &v1alpha1.ClusterNetworkConfig{ ServiceSubnet: []string{
ServiceSubnet: []string{ "10.200.0.0/22",
"10.200.0.0/22", "fd40:10:200::/112",
"fd40:10:200::/112", },
}, PodSubnet: []string{
PodSubnet: []string{ "10.32.0.0/12",
"10.32.0.0/12", "fd00:10:32::/102",
"fd00:10:32::/102", },
}, },
}, },
}, },
}) )
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
suite.assertResource( retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
resource.NewMetadata(network.NamespaceName, network.NodeAddressFilterType, k8s.NodeAddressFilterOnlyK8s, resource.VersionUndefined), suite.assertResource(
func(res resource.Resource) error { resource.NewMetadata(
spec := res.(*network.NodeAddressFilter).TypedSpec() network.NamespaceName,
network.NodeAddressFilterType,
k8s.NodeAddressFilterOnlyK8s,
resource.VersionUndefined,
),
func(res resource.Resource) error {
spec := res.(*network.NodeAddressFilter).TypedSpec()
suite.Assert().Equal("[10.32.0.0/12 fd00:10:32::/102 10.200.0.0/22 fd40:10:200::/112]", fmt.Sprintf("%s", spec.IncludeSubnets)) suite.Assert().Equal(
suite.Assert().Empty(spec.ExcludeSubnets) "[10.32.0.0/12 fd00:10:32::/102 10.200.0.0/22 fd40:10:200::/112]",
fmt.Sprintf("%s", spec.IncludeSubnets),
)
suite.Assert().Empty(spec.ExcludeSubnets)
return nil return nil
}, },
),
), ),
)) )
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
suite.assertResource( retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
resource.NewMetadata(network.NamespaceName, network.NodeAddressFilterType, k8s.NodeAddressFilterNoK8s, resource.VersionUndefined), suite.assertResource(
func(res resource.Resource) error { resource.NewMetadata(
spec := res.(*network.NodeAddressFilter).TypedSpec() network.NamespaceName,
network.NodeAddressFilterType,
k8s.NodeAddressFilterNoK8s,
resource.VersionUndefined,
),
func(res resource.Resource) error {
spec := res.(*network.NodeAddressFilter).TypedSpec()
suite.Assert().Empty(spec.IncludeSubnets) suite.Assert().Empty(spec.IncludeSubnets)
suite.Assert().Equal("[10.32.0.0/12 fd00:10:32::/102 10.200.0.0/22 fd40:10:200::/112]", fmt.Sprintf("%s", spec.ExcludeSubnets)) suite.Assert().Equal(
"[10.32.0.0/12 fd00:10:32::/102 10.200.0.0/22 fd40:10:200::/112]",
fmt.Sprintf("%s", spec.ExcludeSubnets),
)
return nil return nil
}, },
),
), ),
)) )
} }
func (suite *K8sAddressFilterSuite) TearDownTest() { func (suite *K8sAddressFilterSuite) TearDownTest() {

View File

@ -40,7 +40,7 @@ type K8sControlPlaneSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -70,7 +70,10 @@ func (suite *K8sControlPlaneSuite) startRuntime() {
} }
func (suite *K8sControlPlaneSuite) assertK8sControlPlanes(manifests []string) error { func (suite *K8sControlPlaneSuite) assertK8sControlPlanes(manifests []string) error {
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(config.NamespaceName, config.K8sControlPlaneType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(config.NamespaceName, config.K8sControlPlaneType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -97,20 +100,22 @@ func (suite *K8sControlPlaneSuite) setupMachine(cfg *config.MachineConfig) confi
suite.Require().NoError(suite.state.Create(suite.ctx, machineType)) suite.Require().NoError(suite.state.Create(suite.ctx, machineType))
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertK8sControlPlanes( func() error {
[]string{ return suite.assertK8sControlPlanes(
config.K8sAdmissionControlID, []string{
config.K8sExtraManifestsID, config.K8sAdmissionControlID,
config.K8sControlPlaneAPIServerID, config.K8sExtraManifestsID,
config.K8sControlPlaneControllerManagerID, config.K8sControlPlaneAPIServerID,
config.K8sControlPlaneSchedulerID, config.K8sControlPlaneControllerManagerID,
config.K8sManifestsID, config.K8sControlPlaneSchedulerID,
}, config.K8sManifestsID,
) },
}, )
)) },
),
)
r, err := suite.state.Get(suite.ctx, config.NewK8sControlPlaneAPIServer().Metadata()) r, err := suite.state.Get(suite.ctx, config.NewK8sControlPlaneAPIServer().Metadata())
suite.Require().NoError(err) suite.Require().NoError(err)
@ -125,17 +130,19 @@ func (suite *K8sControlPlaneSuite) TestReconcileDefaults() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{}, ConfigVersion: "v1alpha1",
ClusterConfig: &v1alpha1.ClusterConfig{ MachineConfig: &v1alpha1.MachineConfig{},
ControlPlane: &v1alpha1.ControlPlaneConfig{ ClusterConfig: &v1alpha1.ClusterConfig{
Endpoint: &v1alpha1.Endpoint{ ControlPlane: &v1alpha1.ControlPlaneConfig{
URL: u, Endpoint: &v1alpha1.Endpoint{
URL: u,
},
}, },
}, },
}, },
}) )
apiServerCfg := suite.setupMachine(cfg) apiServerCfg := suite.setupMachine(cfg)
suite.Assert().Empty(apiServerCfg.CloudProvider) suite.Assert().Empty(apiServerCfg.CloudProvider)
@ -149,86 +156,96 @@ func (suite *K8sControlPlaneSuite) TestReconcileExtraVolumes() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{}, ConfigVersion: "v1alpha1",
ClusterConfig: &v1alpha1.ClusterConfig{ MachineConfig: &v1alpha1.MachineConfig{},
ControlPlane: &v1alpha1.ControlPlaneConfig{ ClusterConfig: &v1alpha1.ClusterConfig{
Endpoint: &v1alpha1.Endpoint{ ControlPlane: &v1alpha1.ControlPlaneConfig{
URL: u, Endpoint: &v1alpha1.Endpoint{
URL: u,
},
}, },
}, APIServerConfig: &v1alpha1.APIServerConfig{
APIServerConfig: &v1alpha1.APIServerConfig{ ExtraVolumesConfig: []v1alpha1.VolumeMountConfig{
ExtraVolumesConfig: []v1alpha1.VolumeMountConfig{ {
{ VolumeHostPath: "/var/lib",
VolumeHostPath: "/var/lib", VolumeMountPath: "/var/foo/",
VolumeMountPath: "/var/foo/", },
}, },
}, },
}, },
}, },
}) )
apiServerCfg := suite.setupMachine(cfg) apiServerCfg := suite.setupMachine(cfg)
suite.Assert().Equal([]config.K8sExtraVolume{ suite.Assert().Equal(
{ []config.K8sExtraVolume{
Name: "var-foo", {
HostPath: "/var/lib", Name: "var-foo",
MountPath: "/var/foo/", HostPath: "/var/lib",
ReadOnly: false, MountPath: "/var/foo/",
}, ReadOnly: false,
}, apiServerCfg.ExtraVolumes) },
}, apiServerCfg.ExtraVolumes,
)
} }
func (suite *K8sControlPlaneSuite) TestReconcileEnvironment() { func (suite *K8sControlPlaneSuite) TestReconcileEnvironment() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{}, ConfigVersion: "v1alpha1",
ClusterConfig: &v1alpha1.ClusterConfig{ MachineConfig: &v1alpha1.MachineConfig{},
ControlPlane: &v1alpha1.ControlPlaneConfig{ ClusterConfig: &v1alpha1.ClusterConfig{
Endpoint: &v1alpha1.Endpoint{ ControlPlane: &v1alpha1.ControlPlaneConfig{
URL: u, Endpoint: &v1alpha1.Endpoint{
URL: u,
},
}, },
}, APIServerConfig: &v1alpha1.APIServerConfig{
APIServerConfig: &v1alpha1.APIServerConfig{ EnvConfig: v1alpha1.Env{
EnvConfig: v1alpha1.Env{ "HTTP_PROXY": "foo",
"HTTP_PROXY": "foo", },
}, },
}, },
}, },
}) )
apiServerCfg := suite.setupMachine(cfg) apiServerCfg := suite.setupMachine(cfg)
suite.Assert().Equal(map[string]string{ suite.Assert().Equal(
"HTTP_PROXY": "foo", map[string]string{
}, apiServerCfg.EnvironmentVariables) "HTTP_PROXY": "foo",
}, apiServerCfg.EnvironmentVariables,
)
} }
func (suite *K8sControlPlaneSuite) TestReconcileExternalCloudProvider() { func (suite *K8sControlPlaneSuite) TestReconcileExternalCloudProvider() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{}, ConfigVersion: "v1alpha1",
ClusterConfig: &v1alpha1.ClusterConfig{ MachineConfig: &v1alpha1.MachineConfig{},
ControlPlane: &v1alpha1.ControlPlaneConfig{ ClusterConfig: &v1alpha1.ClusterConfig{
Endpoint: &v1alpha1.Endpoint{ ControlPlane: &v1alpha1.ControlPlaneConfig{
URL: u, Endpoint: &v1alpha1.Endpoint{
URL: u,
},
}, },
}, ExternalCloudProviderConfig: &v1alpha1.ExternalCloudProviderConfig{
ExternalCloudProviderConfig: &v1alpha1.ExternalCloudProviderConfig{ ExternalEnabled: true,
ExternalEnabled: true, ExternalManifests: []string{
ExternalManifests: []string{ "https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/rbac.yaml",
"https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/rbac.yaml", "https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/aws-cloud-controller-manager-daemonset.yaml",
"https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/aws-cloud-controller-manager-daemonset.yaml", },
}, },
}, },
}, },
}) )
apiServerCfg := suite.setupMachine(cfg) apiServerCfg := suite.setupMachine(cfg)
suite.Assert().Equal("external", apiServerCfg.CloudProvider) suite.Assert().Equal("external", apiServerCfg.CloudProvider)
@ -240,63 +257,71 @@ func (suite *K8sControlPlaneSuite) TestReconcileExternalCloudProvider() {
r, err = suite.state.Get(suite.ctx, config.NewK8sExtraManifests().Metadata()) r, err = suite.state.Get(suite.ctx, config.NewK8sExtraManifests().Metadata())
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().Equal(config.K8sExtraManifestsSpec{ suite.Assert().Equal(
ExtraManifests: []config.ExtraManifest{ config.K8sExtraManifestsSpec{
{ ExtraManifests: []config.ExtraManifest{
Name: "https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/rbac.yaml", {
URL: "https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/rbac.yaml", Name: "https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/rbac.yaml",
Priority: "30", URL: "https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/rbac.yaml",
Priority: "30",
},
{
Name: "https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/aws-cloud-controller-manager-daemonset.yaml",
URL: "https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/aws-cloud-controller-manager-daemonset.yaml",
Priority: "30",
},
}, },
{ }, r.(*config.K8sControlPlane).ExtraManifests(),
Name: "https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/aws-cloud-controller-manager-daemonset.yaml", )
URL: "https://raw.githubusercontent.com/kubernetes/cloud-provider-aws/v1.20.0-alpha.0/manifests/aws-cloud-controller-manager-daemonset.yaml",
Priority: "30",
},
},
}, r.(*config.K8sControlPlane).ExtraManifests())
} }
func (suite *K8sControlPlaneSuite) TestReconcileInlineManifests() { func (suite *K8sControlPlaneSuite) TestReconcileInlineManifests() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{}, ConfigVersion: "v1alpha1",
ClusterConfig: &v1alpha1.ClusterConfig{ MachineConfig: &v1alpha1.MachineConfig{},
ControlPlane: &v1alpha1.ControlPlaneConfig{ ClusterConfig: &v1alpha1.ClusterConfig{
Endpoint: &v1alpha1.Endpoint{ ControlPlane: &v1alpha1.ControlPlaneConfig{
URL: u, Endpoint: &v1alpha1.Endpoint{
URL: u,
},
}, },
}, ClusterInlineManifests: v1alpha1.ClusterInlineManifests{
ClusterInlineManifests: v1alpha1.ClusterInlineManifests{ {
{ InlineManifestName: "namespace-ci",
InlineManifestName: "namespace-ci", InlineManifestContents: strings.TrimSpace(
InlineManifestContents: strings.TrimSpace(` `
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: ci name: ci
`), `,
),
},
}, },
}, },
}, },
}) )
suite.setupMachine(cfg) suite.setupMachine(cfg)
r, err := suite.state.Get(suite.ctx, config.NewK8sExtraManifests().Metadata()) r, err := suite.state.Get(suite.ctx, config.NewK8sExtraManifests().Metadata())
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().Equal(config.K8sExtraManifestsSpec{ suite.Assert().Equal(
ExtraManifests: []config.ExtraManifest{ config.K8sExtraManifestsSpec{
{ ExtraManifests: []config.ExtraManifest{
Name: "namespace-ci", {
Priority: "99", Name: "namespace-ci",
InlineManifest: "apiVersion: v1\nkind: Namespace\nmetadata:\n\tname: ci", Priority: "99",
InlineManifest: "apiVersion: v1\nkind: Namespace\nmetadata:\n\tname: ci",
},
}, },
}, }, r.(*config.K8sControlPlane).ExtraManifests(),
}, r.(*config.K8sControlPlane).ExtraManifests()) )
} }
func (suite *K8sControlPlaneSuite) TearDownTest() { func (suite *K8sControlPlaneSuite) TearDownTest() {
@ -307,8 +332,19 @@ func (suite *K8sControlPlaneSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
suite.Assert().NoError(suite.state.Create(context.Background(), k8s.NewSecretsStatus(k8s.ControlPlaneNamespaceName, "-"))) suite.Assert().NoError(
suite.Assert().NoError(suite.state.Destroy(context.Background(), config.NewK8sControlPlaneAPIServer().Metadata(), state.WithDestroyOwner("config.K8sControlPlaneController"))) suite.state.Create(
context.Background(),
k8s.NewSecretsStatus(k8s.ControlPlaneNamespaceName, "-"),
),
)
suite.Assert().NoError(
suite.state.Destroy(
context.Background(),
config.NewK8sControlPlaneAPIServer().Metadata(),
state.WithDestroyOwner("config.K8sControlPlaneController"),
),
)
} }
func TestK8sControlPlaneSuite(t *testing.T) { func TestK8sControlPlaneSuite(t *testing.T) {

View File

@ -35,7 +35,7 @@ type EtcFileSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
etcPath string etcPath string
@ -57,10 +57,14 @@ func (suite *EtcFileSuite) SetupTest() {
suite.etcPath = suite.T().TempDir() suite.etcPath = suite.T().TempDir()
suite.shadowPath = suite.T().TempDir() suite.shadowPath = suite.T().TempDir()
suite.Require().NoError(suite.runtime.RegisterController(&filesctrl.EtcFileController{ suite.Require().NoError(
EtcPath: suite.etcPath, suite.runtime.RegisterController(
ShadowPath: suite.shadowPath, &filesctrl.EtcFileController{
})) EtcPath: suite.etcPath,
ShadowPath: suite.shadowPath,
},
),
)
} }
func (suite *EtcFileSuite) startRuntime() { func (suite *EtcFileSuite) startRuntime() {
@ -83,7 +87,10 @@ func (suite *EtcFileSuite) assertEtcFile(filename, contents string, expectedVers
return retry.ExpectedErrorf("contents don't match %q != %q", string(b), contents) return retry.ExpectedErrorf("contents don't match %q != %q", string(b), contents)
} }
r, err := suite.state.Get(suite.ctx, resource.NewMetadata(files.NamespaceName, files.EtcFileStatusType, filename, resource.VersionUndefined)) r, err := suite.state.Get(
suite.ctx,
resource.NewMetadata(files.NamespaceName, files.EtcFileStatusType, filename, resource.VersionUndefined),
)
if err != nil { if err != nil {
if state.IsNotFoundError(err) { if state.IsNotFoundError(err) {
return retry.ExpectedError(err) return retry.ExpectedError(err)
@ -118,10 +125,13 @@ func (suite *EtcFileSuite) TestFiles() {
suite.Require().NoError(suite.state.Create(suite.ctx, etcFileSpec)) suite.Require().NoError(suite.state.Create(suite.ctx, etcFileSpec))
suite.Assert().NoError(retry.Constant(5*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(5*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertEtcFile("test1", "foo", etcFileSpec.Metadata().Version()) func() error {
})) return suite.assertEtcFile("test1", "foo", etcFileSpec.Metadata().Version())
},
),
)
for _, r := range []resource.Resource{etcFileSpec} { for _, r := range []resource.Resource{etcFileSpec} {
for { for {

View File

@ -276,7 +276,8 @@ func envVars(environment map[string]string) []v1.EnvVar {
} }
func (ctrl *ControlPlaneStaticPodController) manageAPIServer(ctx context.Context, r controller.Runtime, logger *zap.Logger, func (ctrl *ControlPlaneStaticPodController) manageAPIServer(ctx context.Context, r controller.Runtime, logger *zap.Logger,
configResource *config.K8sControlPlane, secretsVersion, configVersion string) (string, error) { configResource *config.K8sControlPlane, secretsVersion, configVersion string,
) (string, error) {
cfg := configResource.APIServer() cfg := configResource.APIServer()
enabledAdmissionPlugins := []string{"NodeRestriction"} enabledAdmissionPlugins := []string{"NodeRestriction"}
@ -465,7 +466,8 @@ func (ctrl *ControlPlaneStaticPodController) manageAPIServer(ctx context.Context
} }
func (ctrl *ControlPlaneStaticPodController) manageControllerManager(ctx context.Context, r controller.Runtime, func (ctrl *ControlPlaneStaticPodController) manageControllerManager(ctx context.Context, r controller.Runtime,
logger *zap.Logger, configResource *config.K8sControlPlane, secretsVersion, configVersion string) (string, error) { logger *zap.Logger, configResource *config.K8sControlPlane, secretsVersion, configVersion string,
) (string, error) {
cfg := configResource.ControllerManager() cfg := configResource.ControllerManager()
if !cfg.Enabled { if !cfg.Enabled {
@ -594,7 +596,8 @@ func (ctrl *ControlPlaneStaticPodController) manageControllerManager(ctx context
} }
func (ctrl *ControlPlaneStaticPodController) manageScheduler(ctx context.Context, r controller.Runtime, func (ctrl *ControlPlaneStaticPodController) manageScheduler(ctx context.Context, r controller.Runtime,
logger *zap.Logger, configResource *config.K8sControlPlane, secretsVersion, configVersion string) (string, error) { logger *zap.Logger, configResource *config.K8sControlPlane, secretsVersion, configVersion string,
) (string, error) {
cfg := configResource.Scheduler() cfg := configResource.Scheduler()
if !cfg.Enabled { if !cfg.Enabled {

View File

@ -41,7 +41,7 @@ type ControlPlaneStaticPodSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -78,7 +78,10 @@ func (suite *ControlPlaneStaticPodSuite) startRuntime() {
//nolint:dupl //nolint:dupl
func (suite *ControlPlaneStaticPodSuite) assertControlPlaneStaticPods(manifests []string) error { func (suite *ControlPlaneStaticPodSuite) assertControlPlaneStaticPods(manifests []string) error {
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -109,51 +112,60 @@ func (suite *ControlPlaneStaticPodSuite) TestReconcileDefaults() {
suite.Require().NoError(suite.state.Create(suite.ctx, configControllerManager)) suite.Require().NoError(suite.state.Create(suite.ctx, configControllerManager))
suite.Require().NoError(suite.state.Create(suite.ctx, configScheduler)) suite.Require().NoError(suite.state.Create(suite.ctx, configScheduler))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertControlPlaneStaticPods( func() error {
[]string{ return suite.assertControlPlaneStaticPods(
"kube-apiserver", []string{
"kube-controller-manager", "kube-apiserver",
"kube-scheduler", "kube-controller-manager",
}, "kube-scheduler",
) },
}, )
)) },
),
)
// tear down etcd service // tear down etcd service
suite.Require().NoError(suite.state.Destroy(suite.ctx, v1alpha1.NewService("etcd").Metadata())) suite.Require().NoError(suite.state.Destroy(suite.ctx, v1alpha1.NewService("etcd").Metadata()))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
list, err := suite.state.List(suite.ctx, resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodType, "", resource.VersionUndefined)) func() error {
if err != nil { list, err := suite.state.List(
return err suite.ctx,
} resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodType, "", resource.VersionUndefined),
)
if err != nil {
return err
}
if len(list.Items) > 0 { if len(list.Items) > 0 {
return retry.ExpectedErrorf("expected no pods, got %d", len(list.Items)) return retry.ExpectedErrorf("expected no pods, got %d", len(list.Items))
} }
return nil return nil
}, },
)) ),
)
} }
func (suite *ControlPlaneStaticPodSuite) TestReconcileExtraMounts() { func (suite *ControlPlaneStaticPodSuite) TestReconcileExtraMounts() {
secretStatus := k8s.NewSecretsStatus(k8s.ControlPlaneNamespaceName, k8s.StaticPodSecretsStaticPodID) secretStatus := k8s.NewSecretsStatus(k8s.ControlPlaneNamespaceName, k8s.StaticPodSecretsStaticPodID)
configStatus := k8s.NewConfigStatus(k8s.ControlPlaneNamespaceName, k8s.ConfigStatusStaticPodID) configStatus := k8s.NewConfigStatus(k8s.ControlPlaneNamespaceName, k8s.ConfigStatusStaticPodID)
configAPIServer := config.NewK8sControlPlaneAPIServer() configAPIServer := config.NewK8sControlPlaneAPIServer()
configAPIServer.SetAPIServer(config.K8sControlPlaneAPIServerSpec{ configAPIServer.SetAPIServer(
ExtraVolumes: []config.K8sExtraVolume{ config.K8sControlPlaneAPIServerSpec{
{ ExtraVolumes: []config.K8sExtraVolume{
Name: "foo", {
HostPath: "/var/lib", Name: "foo",
MountPath: "/var/foo", HostPath: "/var/lib",
ReadOnly: true, MountPath: "/var/foo",
ReadOnly: true,
},
}, },
}, },
}) )
configControllerManager := config.NewK8sControlPlaneControllerManager() configControllerManager := config.NewK8sControlPlaneControllerManager()
configScheduler := config.NewK8sControlPlaneScheduler() configScheduler := config.NewK8sControlPlaneScheduler()
@ -164,19 +176,24 @@ func (suite *ControlPlaneStaticPodSuite) TestReconcileExtraMounts() {
suite.Require().NoError(suite.state.Create(suite.ctx, configControllerManager)) suite.Require().NoError(suite.state.Create(suite.ctx, configControllerManager))
suite.Require().NoError(suite.state.Create(suite.ctx, configScheduler)) suite.Require().NoError(suite.state.Create(suite.ctx, configScheduler))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertControlPlaneStaticPods( func() error {
[]string{ return suite.assertControlPlaneStaticPods(
"kube-apiserver", []string{
"kube-controller-manager", "kube-apiserver",
"kube-scheduler", "kube-controller-manager",
}, "kube-scheduler",
) },
}, )
)) },
),
)
r, err := suite.state.Get(suite.ctx, resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodType, "kube-apiserver", resource.VersionUndefined)) r, err := suite.state.Get(
suite.ctx,
resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodType, "kube-apiserver", resource.VersionUndefined),
)
suite.Require().NoError(err) suite.Require().NoError(err)
apiServerPod, err := k8sadapter.StaticPod(r.(*k8s.StaticPod)).Pod() apiServerPod, err := k8sadapter.StaticPod(r.(*k8s.StaticPod)).Pod()
@ -185,65 +202,81 @@ func (suite *ControlPlaneStaticPodSuite) TestReconcileExtraMounts() {
suite.Assert().Len(apiServerPod.Spec.Volumes, 4) suite.Assert().Len(apiServerPod.Spec.Volumes, 4)
suite.Assert().Len(apiServerPod.Spec.Containers[0].VolumeMounts, 4) suite.Assert().Len(apiServerPod.Spec.Containers[0].VolumeMounts, 4)
suite.Assert().Equal(v1.Volume{ suite.Assert().Equal(
Name: "secrets", v1.Volume{
VolumeSource: v1.VolumeSource{ Name: "secrets",
HostPath: &v1.HostPathVolumeSource{ VolumeSource: v1.VolumeSource{
Path: constants.KubernetesAPIServerSecretsDir, HostPath: &v1.HostPathVolumeSource{
Path: constants.KubernetesAPIServerSecretsDir,
},
}, },
}, }, apiServerPod.Spec.Volumes[0],
}, apiServerPod.Spec.Volumes[0]) )
suite.Assert().Equal(v1.Volume{ suite.Assert().Equal(
Name: "config", v1.Volume{
VolumeSource: v1.VolumeSource{ Name: "config",
HostPath: &v1.HostPathVolumeSource{ VolumeSource: v1.VolumeSource{
Path: constants.KubernetesAPIServerConfigDir, HostPath: &v1.HostPathVolumeSource{
Path: constants.KubernetesAPIServerConfigDir,
},
}, },
}, }, apiServerPod.Spec.Volumes[1],
}, apiServerPod.Spec.Volumes[1]) )
suite.Assert().Equal(v1.Volume{ suite.Assert().Equal(
Name: "audit", v1.Volume{
VolumeSource: v1.VolumeSource{ Name: "audit",
HostPath: &v1.HostPathVolumeSource{ VolumeSource: v1.VolumeSource{
Path: constants.KubernetesAuditLogDir, HostPath: &v1.HostPathVolumeSource{
Path: constants.KubernetesAuditLogDir,
},
}, },
}, }, apiServerPod.Spec.Volumes[2],
}, apiServerPod.Spec.Volumes[2]) )
suite.Assert().Equal(v1.Volume{ suite.Assert().Equal(
Name: "foo", v1.Volume{
VolumeSource: v1.VolumeSource{ Name: "foo",
HostPath: &v1.HostPathVolumeSource{ VolumeSource: v1.VolumeSource{
Path: "/var/lib", HostPath: &v1.HostPathVolumeSource{
Path: "/var/lib",
},
}, },
}, }, apiServerPod.Spec.Volumes[3],
}, apiServerPod.Spec.Volumes[3]) )
suite.Assert().Equal(v1.VolumeMount{ suite.Assert().Equal(
Name: "secrets", v1.VolumeMount{
MountPath: constants.KubernetesAPIServerSecretsDir, Name: "secrets",
ReadOnly: true, MountPath: constants.KubernetesAPIServerSecretsDir,
}, apiServerPod.Spec.Containers[0].VolumeMounts[0]) ReadOnly: true,
}, apiServerPod.Spec.Containers[0].VolumeMounts[0],
)
suite.Assert().Equal(v1.VolumeMount{ suite.Assert().Equal(
Name: "config", v1.VolumeMount{
MountPath: constants.KubernetesAPIServerConfigDir, Name: "config",
ReadOnly: true, MountPath: constants.KubernetesAPIServerConfigDir,
}, apiServerPod.Spec.Containers[0].VolumeMounts[1]) ReadOnly: true,
}, apiServerPod.Spec.Containers[0].VolumeMounts[1],
)
suite.Assert().Equal(v1.VolumeMount{ suite.Assert().Equal(
Name: "audit", v1.VolumeMount{
MountPath: constants.KubernetesAuditLogDir, Name: "audit",
ReadOnly: false, MountPath: constants.KubernetesAuditLogDir,
}, apiServerPod.Spec.Containers[0].VolumeMounts[2]) ReadOnly: false,
}, apiServerPod.Spec.Containers[0].VolumeMounts[2],
)
suite.Assert().Equal(v1.VolumeMount{ suite.Assert().Equal(
Name: "foo", v1.VolumeMount{
MountPath: "/var/foo", Name: "foo",
ReadOnly: true, MountPath: "/var/foo",
}, apiServerPod.Spec.Containers[0].VolumeMounts[3]) ReadOnly: true,
}, apiServerPod.Spec.Containers[0].VolumeMounts[3],
)
} }
func (suite *ControlPlaneStaticPodSuite) TestReconcileExtraArgs() { func (suite *ControlPlaneStaticPodSuite) TestReconcileExtraArgs() {
@ -278,9 +311,11 @@ func (suite *ControlPlaneStaticPodSuite) TestReconcileExtraArgs() {
secretStatus := k8s.NewSecretsStatus(k8s.ControlPlaneNamespaceName, k8s.StaticPodSecretsStaticPodID) secretStatus := k8s.NewSecretsStatus(k8s.ControlPlaneNamespaceName, k8s.StaticPodSecretsStaticPodID)
configAPIServer := config.NewK8sControlPlaneAPIServer() configAPIServer := config.NewK8sControlPlaneAPIServer()
configAPIServer.SetAPIServer(config.K8sControlPlaneAPIServerSpec{ configAPIServer.SetAPIServer(
ExtraArgs: test.args, config.K8sControlPlaneAPIServerSpec{
}) ExtraArgs: test.args,
},
)
suite.Require().NoError(suite.state.Create(suite.ctx, configStatus)) suite.Require().NoError(suite.state.Create(suite.ctx, configStatus))
suite.Require().NoError(suite.state.Create(suite.ctx, secretStatus)) suite.Require().NoError(suite.state.Create(suite.ctx, secretStatus))
@ -290,23 +325,31 @@ func (suite *ControlPlaneStaticPodSuite) TestReconcileExtraArgs() {
// wait for some time to ensure that controller has picked the input // wait for some time to ensure that controller has picked the input
time.Sleep(500 * time.Millisecond) time.Sleep(500 * time.Millisecond)
_, err := suite.state.Get(suite.ctx, resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodType, "kube-apiserver", resource.VersionUndefined)) _, err := suite.state.Get(
suite.ctx,
resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodType, "kube-apiserver", resource.VersionUndefined),
)
suite.Require().Error(err) suite.Require().Error(err)
continue continue
} }
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertControlPlaneStaticPods( func() error {
[]string{ return suite.assertControlPlaneStaticPods(
"kube-apiserver", []string{
}, "kube-apiserver",
) },
}, )
)) },
),
)
r, err := suite.state.Get(suite.ctx, resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodType, "kube-apiserver", resource.VersionUndefined)) r, err := suite.state.Get(
suite.ctx,
resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodType, "kube-apiserver", resource.VersionUndefined),
)
suite.Require().NoError(err) suite.Require().NoError(err)
apiServerPod, err := k8sadapter.StaticPod(r.(*k8s.StaticPod)).Pod() apiServerPod, err := k8sadapter.StaticPod(r.(*k8s.StaticPod)).Pod()
@ -332,20 +375,25 @@ func (suite *ControlPlaneStaticPodSuite) TestReconcileExtraArgs() {
suite.Require().NoError(suite.state.Destroy(suite.ctx, secretStatus.Metadata())) suite.Require().NoError(suite.state.Destroy(suite.ctx, secretStatus.Metadata()))
suite.Require().NoError(suite.state.Destroy(suite.ctx, configAPIServer.Metadata())) suite.Require().NoError(suite.state.Destroy(suite.ctx, configAPIServer.Metadata()))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
list, err := suite.state.List(suite.ctx, resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodType, "", resource.VersionUndefined)) func() error {
if err != nil { list, err := suite.state.List(
return err suite.ctx,
} resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodType, "", resource.VersionUndefined),
)
if err != nil {
return err
}
if len(list.Items) > 0 { if len(list.Items) > 0 {
return retry.ExpectedErrorf("expected no pods, got %d", len(list.Items)) return retry.ExpectedErrorf("expected no pods, got %d", len(list.Items))
} }
return nil return nil
}, },
)) ),
)
} }
} }
@ -401,23 +449,30 @@ func (suite *ControlPlaneStaticPodSuite) TestReconcileEnvironmentVariables() {
for _, test := range tests { for _, test := range tests {
configAPIServer := config.NewK8sControlPlaneAPIServer() configAPIServer := config.NewK8sControlPlaneAPIServer()
configAPIServer.SetAPIServer(config.K8sControlPlaneAPIServerSpec{ configAPIServer.SetAPIServer(
EnvironmentVariables: test.env, config.K8sControlPlaneAPIServerSpec{
}) EnvironmentVariables: test.env,
},
)
suite.Require().NoError(suite.state.Create(suite.ctx, configAPIServer)) suite.Require().NoError(suite.state.Create(suite.ctx, configAPIServer))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertControlPlaneStaticPods( func() error {
[]string{ return suite.assertControlPlaneStaticPods(
"kube-apiserver", []string{
}, "kube-apiserver",
) },
}, )
)) },
),
)
r, err := suite.state.Get(suite.ctx, resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodType, "kube-apiserver", resource.VersionUndefined)) r, err := suite.state.Get(
suite.ctx,
resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodType, "kube-apiserver", resource.VersionUndefined),
)
suite.Require().NoError(err) suite.Require().NoError(err)
apiServerPod, err := k8sadapter.StaticPod(r.(*k8s.StaticPod)).Pod() apiServerPod, err := k8sadapter.StaticPod(r.(*k8s.StaticPod)).Pod()
@ -429,20 +484,25 @@ func (suite *ControlPlaneStaticPodSuite) TestReconcileEnvironmentVariables() {
suite.Require().NoError(suite.state.Destroy(suite.ctx, configAPIServer.Metadata())) suite.Require().NoError(suite.state.Destroy(suite.ctx, configAPIServer.Metadata()))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
list, err := suite.state.List(suite.ctx, resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodType, "", resource.VersionUndefined)) func() error {
if err != nil { list, err := suite.state.List(
return err suite.ctx,
} resource.NewMetadata(k8s.NamespaceName, k8s.StaticPodType, "", resource.VersionUndefined),
)
if err != nil {
return err
}
if len(list.Items) > 0 { if len(list.Items) > 0 {
return retry.ExpectedErrorf("expected no pods, got %d", len(list.Items)) return retry.ExpectedErrorf("expected no pods, got %d", len(list.Items))
} }
return nil return nil
}, },
)) ),
)
} }
} }
@ -459,40 +519,46 @@ func (suite *ControlPlaneStaticPodSuite) TestControlPlaneStaticPodsExceptSchedul
suite.Require().NoError(suite.state.Create(suite.ctx, configControllerManager)) suite.Require().NoError(suite.state.Create(suite.ctx, configControllerManager))
suite.Require().NoError(suite.state.Create(suite.ctx, configScheduler)) suite.Require().NoError(suite.state.Create(suite.ctx, configScheduler))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertControlPlaneStaticPods( func() error {
[]string{ return suite.assertControlPlaneStaticPods(
"kube-apiserver", []string{
"kube-controller-manager", "kube-apiserver",
"kube-scheduler", "kube-controller-manager",
}, "kube-scheduler",
) },
}, )
)) },
),
)
// flip enabled to disable scheduler // flip enabled to disable scheduler
_, err := suite.state.UpdateWithConflicts(suite.ctx, configScheduler.Metadata(), func(r resource.Resource) error { _, err := suite.state.UpdateWithConflicts(
spec := r.(*config.K8sControlPlane).Scheduler() suite.ctx, configScheduler.Metadata(), func(r resource.Resource) error {
spec.Enabled = false spec := r.(*config.K8sControlPlane).Scheduler()
r.(*config.K8sControlPlane).SetScheduler(spec) spec.Enabled = false
r.(*config.K8sControlPlane).SetScheduler(spec)
return nil return nil
}) },
)
suite.Require().NoError(err) suite.Require().NoError(err)
configScheduler.SetScheduler(config.K8sControlPlaneSchedulerSpec{Enabled: false}) configScheduler.SetScheduler(config.K8sControlPlaneSchedulerSpec{Enabled: false})
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertControlPlaneStaticPods( func() error {
[]string{ return suite.assertControlPlaneStaticPods(
"kube-apiserver", []string{
"kube-controller-manager", "kube-apiserver",
}, "kube-controller-manager",
) },
}, )
)) },
),
)
} }
func (suite *ControlPlaneStaticPodSuite) TearDownTest() { func (suite *ControlPlaneStaticPodSuite) TearDownTest() {
@ -503,7 +569,12 @@ func (suite *ControlPlaneStaticPodSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
suite.Assert().NoError(suite.state.Create(context.Background(), k8s.NewSecretsStatus(k8s.ControlPlaneNamespaceName, "-"))) suite.Assert().NoError(
suite.state.Create(
context.Background(),
k8s.NewSecretsStatus(k8s.ControlPlaneNamespaceName, "-"),
),
)
suite.Assert().NoError(suite.state.Create(context.Background(), config.NewK8sManifests())) suite.Assert().NoError(suite.state.Create(context.Background(), config.NewK8sManifests()))
} }

View File

@ -40,7 +40,7 @@ type ExtraManifestSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -71,7 +71,10 @@ func (suite *ExtraManifestSuite) startRuntime() {
//nolint:dupl //nolint:dupl
func (suite *ExtraManifestSuite) assertExtraManifests(manifests []string) error { func (suite *ExtraManifestSuite) assertExtraManifests(manifests []string) error {
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.ManifestType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.ManifestType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -91,12 +94,14 @@ func (suite *ExtraManifestSuite) assertExtraManifests(manifests []string) error
func (suite *ExtraManifestSuite) TestReconcileInlineManifests() { func (suite *ExtraManifestSuite) TestReconcileInlineManifests() {
configExtraManifests := config.NewK8sExtraManifests() configExtraManifests := config.NewK8sExtraManifests()
configExtraManifests.SetExtraManifests(config.K8sExtraManifestsSpec{ configExtraManifests.SetExtraManifests(
ExtraManifests: []config.ExtraManifest{ config.K8sExtraManifestsSpec{
{ ExtraManifests: []config.ExtraManifest{
Name: "namespaces", {
Priority: "99", Name: "namespaces",
InlineManifest: strings.TrimSpace(` Priority: "99",
InlineManifest: strings.TrimSpace(
`
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
@ -106,10 +111,12 @@ apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: build name: build
`), `,
),
},
}, },
}, },
}) )
statusNetwork := network.NewStatus(network.NamespaceName, network.StatusID) statusNetwork := network.NewStatus(network.NamespaceName, network.StatusID)
statusNetwork.TypedSpec().AddressReady = true statusNetwork.TypedSpec().AddressReady = true
@ -118,17 +125,27 @@ metadata:
suite.Require().NoError(suite.state.Create(suite.ctx, configExtraManifests)) suite.Require().NoError(suite.state.Create(suite.ctx, configExtraManifests))
suite.Require().NoError(suite.state.Create(suite.ctx, statusNetwork)) suite.Require().NoError(suite.state.Create(suite.ctx, statusNetwork))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertExtraManifests( func() error {
[]string{ return suite.assertExtraManifests(
"99-namespaces", []string{
}, "99-namespaces",
) },
}, )
)) },
),
)
r, err := suite.state.Get(suite.ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.ManifestType, "99-namespaces", resource.VersionUndefined)) r, err := suite.state.Get(
suite.ctx,
resource.NewMetadata(
k8s.ControlPlaneNamespaceName,
k8s.ManifestType,
"99-namespaces",
resource.VersionUndefined,
),
)
suite.Require().NoError(err) suite.Require().NoError(err)
manifest := r.(*k8s.Manifest) //nolint:errcheck,forcetypeassert manifest := r.(*k8s.Manifest) //nolint:errcheck,forcetypeassert

View File

@ -38,7 +38,7 @@ type KubeletConfigSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -71,139 +71,165 @@ func (suite *KubeletConfigSuite) TestReconcile() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{ ConfigVersion: "v1alpha1",
MachineKubelet: &v1alpha1.KubeletConfig{ MachineConfig: &v1alpha1.MachineConfig{
KubeletImage: "kubelet", MachineKubelet: &v1alpha1.KubeletConfig{
KubeletClusterDNS: []string{"10.0.0.1"}, KubeletImage: "kubelet",
KubeletExtraArgs: map[string]string{ KubeletClusterDNS: []string{"10.0.0.1"},
"enable-feature": "foo", KubeletExtraArgs: map[string]string{
"enable-feature": "foo",
},
KubeletExtraMounts: []v1alpha1.ExtraMount{
{
Mount: specs.Mount{
Destination: "/tmp",
Source: "/var",
Type: "tmpfs",
},
},
},
KubeletExtraConfig: v1alpha1.Unstructured{
Object: map[string]interface{}{
"serverTLSBootstrap": true,
},
},
}, },
KubeletExtraMounts: []v1alpha1.ExtraMount{ },
{ ClusterConfig: &v1alpha1.ClusterConfig{
Mount: specs.Mount{ ControlPlane: &v1alpha1.ControlPlaneConfig{
Endpoint: &v1alpha1.Endpoint{
URL: u,
},
},
ExternalCloudProviderConfig: &v1alpha1.ExternalCloudProviderConfig{
ExternalEnabled: true,
},
ClusterNetwork: &v1alpha1.ClusterNetworkConfig{
DNSDomain: "service.svc",
},
},
},
)
suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(
retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
func() error {
kubeletConfig, err := suite.state.Get(
suite.ctx,
resource.NewMetadata(
k8s.NamespaceName,
k8s.KubeletConfigType,
k8s.KubeletID,
resource.VersionUndefined,
),
)
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
}
return err
}
spec := kubeletConfig.(*k8s.KubeletConfig).TypedSpec()
suite.Assert().Equal("kubelet", spec.Image)
suite.Assert().Equal([]string{"10.0.0.1"}, spec.ClusterDNS)
suite.Assert().Equal("service.svc", spec.ClusterDomain)
suite.Assert().Equal(
map[string]string{
"enable-feature": "foo",
},
spec.ExtraArgs,
)
suite.Assert().Equal(
[]specs.Mount{
{
Destination: "/tmp", Destination: "/tmp",
Source: "/var", Source: "/var",
Type: "tmpfs", Type: "tmpfs",
}, },
}, },
}, spec.ExtraMounts,
KubeletExtraConfig: v1alpha1.Unstructured{ )
Object: map[string]interface{}{ suite.Assert().Equal(
map[string]interface{}{
"serverTLSBootstrap": true, "serverTLSBootstrap": true,
}, },
}, spec.ExtraConfig,
)
suite.Assert().True(spec.CloudProviderExternal)
return nil
}, },
}, ),
ClusterConfig: &v1alpha1.ClusterConfig{ )
ControlPlane: &v1alpha1.ControlPlaneConfig{
Endpoint: &v1alpha1.Endpoint{
URL: u,
},
},
ExternalCloudProviderConfig: &v1alpha1.ExternalCloudProviderConfig{
ExternalEnabled: true,
},
ClusterNetwork: &v1alpha1.ClusterNetworkConfig{
DNSDomain: "service.svc",
},
},
})
suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
func() error {
kubeletConfig, err := suite.state.Get(suite.ctx, resource.NewMetadata(k8s.NamespaceName, k8s.KubeletConfigType, k8s.KubeletID, resource.VersionUndefined))
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
}
return err
}
spec := kubeletConfig.(*k8s.KubeletConfig).TypedSpec()
suite.Assert().Equal("kubelet", spec.Image)
suite.Assert().Equal([]string{"10.0.0.1"}, spec.ClusterDNS)
suite.Assert().Equal("service.svc", spec.ClusterDomain)
suite.Assert().Equal(
map[string]string{
"enable-feature": "foo",
},
spec.ExtraArgs)
suite.Assert().Equal(
[]specs.Mount{
{
Destination: "/tmp",
Source: "/var",
Type: "tmpfs",
},
},
spec.ExtraMounts)
suite.Assert().Equal(
map[string]interface{}{
"serverTLSBootstrap": true,
},
spec.ExtraConfig,
)
suite.Assert().True(spec.CloudProviderExternal)
return nil
},
))
} }
func (suite *KubeletConfigSuite) TestReconcileDefaults() { func (suite *KubeletConfigSuite) TestReconcileDefaults() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{ ConfigVersion: "v1alpha1",
MachineKubelet: &v1alpha1.KubeletConfig{ MachineConfig: &v1alpha1.MachineConfig{
KubeletImage: "kubelet", MachineKubelet: &v1alpha1.KubeletConfig{
}, KubeletImage: "kubelet",
},
ClusterConfig: &v1alpha1.ClusterConfig{
ControlPlane: &v1alpha1.ControlPlaneConfig{
Endpoint: &v1alpha1.Endpoint{
URL: u,
}, },
}, },
ClusterNetwork: &v1alpha1.ClusterNetworkConfig{ ClusterConfig: &v1alpha1.ClusterConfig{
ServiceSubnet: []string{constants.DefaultIPv4ServiceNet}, ControlPlane: &v1alpha1.ControlPlaneConfig{
Endpoint: &v1alpha1.Endpoint{
URL: u,
},
},
ClusterNetwork: &v1alpha1.ClusterNetworkConfig{
ServiceSubnet: []string{constants.DefaultIPv4ServiceNet},
},
}, },
}, },
}) )
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
kubeletConfig, err := suite.state.Get(suite.ctx, resource.NewMetadata(k8s.NamespaceName, k8s.KubeletConfigType, k8s.KubeletID, resource.VersionUndefined)) func() error {
if err != nil { kubeletConfig, err := suite.state.Get(
if state.IsNotFoundError(err) { suite.ctx,
return retry.ExpectedError(err) resource.NewMetadata(
k8s.NamespaceName,
k8s.KubeletConfigType,
k8s.KubeletID,
resource.VersionUndefined,
),
)
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
}
return err
} }
return err spec := kubeletConfig.(*k8s.KubeletConfig).TypedSpec()
}
spec := kubeletConfig.(*k8s.KubeletConfig).TypedSpec() suite.Assert().Equal("kubelet", spec.Image)
suite.Assert().Equal([]string{"10.96.0.10"}, spec.ClusterDNS)
suite.Assert().Equal("", spec.ClusterDomain)
suite.Assert().Empty(spec.ExtraArgs)
suite.Assert().Empty(spec.ExtraMounts)
suite.Assert().False(spec.CloudProviderExternal)
suite.Assert().Equal("kubelet", spec.Image) return nil
suite.Assert().Equal([]string{"10.96.0.10"}, spec.ClusterDNS) },
suite.Assert().Equal("", spec.ClusterDomain) ),
suite.Assert().Empty(spec.ExtraArgs) )
suite.Assert().Empty(spec.ExtraMounts)
suite.Assert().False(spec.CloudProviderExternal)
return nil
},
))
} }
func (suite *KubeletConfigSuite) TearDownTest() { func (suite *KubeletConfigSuite) TearDownTest() {

View File

@ -43,7 +43,7 @@ type KubeletSpecSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -99,41 +99,52 @@ func (suite *KubeletSpecSuite) TestReconcileDefault() {
suite.Require().NoError(suite.state.Create(suite.ctx, nodename)) suite.Require().NoError(suite.state.Create(suite.ctx, nodename))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
kubeletSpec, err := suite.state.Get(suite.ctx, resource.NewMetadata(k8s.NamespaceName, k8s.KubeletSpecType, k8s.KubeletID, resource.VersionUndefined)) func() error {
if err != nil { kubeletSpec, err := suite.state.Get(
if state.IsNotFoundError(err) { suite.ctx,
return retry.ExpectedError(err) resource.NewMetadata(
k8s.NamespaceName,
k8s.KubeletSpecType,
k8s.KubeletID,
resource.VersionUndefined,
),
)
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
}
return err
} }
return err spec := kubeletSpec.(*k8s.KubeletSpec).TypedSpec()
}
spec := kubeletSpec.(*k8s.KubeletSpec).TypedSpec() suite.Assert().Equal(cfg.TypedSpec().Image, spec.Image)
suite.Assert().Equal(
[]string{
"--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubeconfig",
"--cert-dir=/var/lib/kubelet/pki",
"--cloud-provider=external",
"--config=/etc/kubernetes/kubelet.yaml",
"--container-runtime=remote",
"--container-runtime-endpoint=unix:///run/containerd/containerd.sock",
"--foo=bar",
"--hostname-override=example.com",
"--kubeconfig=/etc/kubernetes/kubeconfig-kubelet",
"--node-ip=172.20.0.2",
}, spec.Args,
)
suite.Assert().Equal(cfg.TypedSpec().ExtraMounts, spec.ExtraMounts)
suite.Assert().Equal(cfg.TypedSpec().Image, spec.Image) suite.Assert().Equal([]interface{}{"10.96.0.10"}, spec.Config["clusterDNS"])
suite.Assert().Equal( suite.Assert().Equal("cluster.local", spec.Config["clusterDomain"])
[]string{
"--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubeconfig",
"--cert-dir=/var/lib/kubelet/pki",
"--cloud-provider=external",
"--config=/etc/kubernetes/kubelet.yaml",
"--container-runtime=remote",
"--container-runtime-endpoint=unix:///run/containerd/containerd.sock",
"--foo=bar",
"--hostname-override=example.com",
"--kubeconfig=/etc/kubernetes/kubeconfig-kubelet",
"--node-ip=172.20.0.2",
}, spec.Args)
suite.Assert().Equal(cfg.TypedSpec().ExtraMounts, spec.ExtraMounts)
suite.Assert().Equal([]interface{}{"10.96.0.10"}, spec.Config["clusterDNS"]) return nil
suite.Assert().Equal("cluster.local", spec.Config["clusterDomain"]) },
),
return nil )
},
))
} }
func (suite *KubeletSpecSuite) TestReconcileWithExplicitNodeIP() { func (suite *KubeletSpecSuite) TestReconcileWithExplicitNodeIP() {
@ -150,35 +161,46 @@ func (suite *KubeletSpecSuite) TestReconcileWithExplicitNodeIP() {
suite.Require().NoError(suite.state.Create(suite.ctx, nodename)) suite.Require().NoError(suite.state.Create(suite.ctx, nodename))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
kubeletSpec, err := suite.state.Get(suite.ctx, resource.NewMetadata(k8s.NamespaceName, k8s.KubeletSpecType, k8s.KubeletID, resource.VersionUndefined)) func() error {
if err != nil { kubeletSpec, err := suite.state.Get(
if state.IsNotFoundError(err) { suite.ctx,
return retry.ExpectedError(err) resource.NewMetadata(
k8s.NamespaceName,
k8s.KubeletSpecType,
k8s.KubeletID,
resource.VersionUndefined,
),
)
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
}
return err
} }
return err spec := kubeletSpec.(*k8s.KubeletSpec).TypedSpec()
}
spec := kubeletSpec.(*k8s.KubeletSpec).TypedSpec() suite.Assert().Equal(cfg.TypedSpec().Image, spec.Image)
suite.Assert().Equal(
[]string{
"--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubeconfig",
"--cert-dir=/var/lib/kubelet/pki",
"--config=/etc/kubernetes/kubelet.yaml",
"--container-runtime=remote",
"--container-runtime-endpoint=unix:///run/containerd/containerd.sock",
"--hostname-override=example.com",
"--kubeconfig=/etc/kubernetes/kubeconfig-kubelet",
"--node-ip=10.0.0.1",
}, spec.Args,
)
suite.Assert().Equal(cfg.TypedSpec().Image, spec.Image) return nil
suite.Assert().Equal( },
[]string{ ),
"--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubeconfig", )
"--cert-dir=/var/lib/kubelet/pki",
"--config=/etc/kubernetes/kubelet.yaml",
"--container-runtime=remote",
"--container-runtime-endpoint=unix:///run/containerd/containerd.sock",
"--hostname-override=example.com",
"--kubeconfig=/etc/kubernetes/kubeconfig-kubelet",
"--node-ip=10.0.0.1",
}, spec.Args)
return nil
},
))
} }
func (suite *KubeletSpecSuite) TestReconcileWithExtraConfig() { func (suite *KubeletSpecSuite) TestReconcileWithExtraConfig() {
@ -202,32 +224,45 @@ func (suite *KubeletSpecSuite) TestReconcileWithExtraConfig() {
suite.Require().NoError(suite.state.Create(suite.ctx, nodeIP)) suite.Require().NoError(suite.state.Create(suite.ctx, nodeIP))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
kubeletSpec, err := suite.state.Get(suite.ctx, resource.NewMetadata(k8s.NamespaceName, k8s.KubeletSpecType, k8s.KubeletID, resource.VersionUndefined)) func() error {
if err != nil { kubeletSpec, err := suite.state.Get(
if state.IsNotFoundError(err) { suite.ctx,
return retry.ExpectedError(err) resource.NewMetadata(
k8s.NamespaceName,
k8s.KubeletSpecType,
k8s.KubeletID,
resource.VersionUndefined,
),
)
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
}
return err
} }
return err spec := kubeletSpec.(*k8s.KubeletSpec).TypedSpec()
}
spec := kubeletSpec.(*k8s.KubeletSpec).TypedSpec() var kubeletConfiguration kubeletconfig.KubeletConfiguration
var kubeletConfiguration kubeletconfig.KubeletConfiguration if err := k8sruntime.DefaultUnstructuredConverter.FromUnstructured(
spec.Config,
&kubeletConfiguration,
); err != nil {
return err
}
if err := k8sruntime.DefaultUnstructuredConverter.FromUnstructured(spec.Config, &kubeletConfiguration); err != nil { suite.Assert().Equal("/", kubeletConfiguration.CgroupRoot)
return err suite.Assert().Equal(cfg.TypedSpec().ClusterDomain, kubeletConfiguration.ClusterDomain)
} suite.Assert().True(kubeletConfiguration.ServerTLSBootstrap)
suite.Assert().Equal("/", kubeletConfiguration.CgroupRoot) return nil
suite.Assert().Equal(cfg.TypedSpec().ClusterDomain, kubeletConfiguration.ClusterDomain) },
suite.Assert().True(kubeletConfiguration.ServerTLSBootstrap) ),
)
return nil
},
))
} }
func (suite *KubeletSpecSuite) TearDownTest() { func (suite *KubeletSpecSuite) TearDownTest() {
@ -276,68 +311,74 @@ func TestNewKubeletConfigurationFail(t *testing.T) {
} { } {
tt := tt tt := tt
t.Run(tt.name, func(t *testing.T) { t.Run(
_, err := k8sctrl.NewKubeletConfiguration([]string{"10.96.0.10"}, "cluster.svc", tt.extraConfig) tt.name, func(t *testing.T) {
require.Error(t, err) _, err := k8sctrl.NewKubeletConfiguration([]string{"10.96.0.10"}, "cluster.svc", tt.extraConfig)
require.Error(t, err)
assert.EqualError(t, err, tt.expectedErr) assert.EqualError(t, err, tt.expectedErr)
}) },
)
} }
} }
func TestNewKubeletConfigurationSuccess(t *testing.T) { func TestNewKubeletConfigurationSuccess(t *testing.T) {
config, err := k8sctrl.NewKubeletConfiguration([]string{"10.0.0.5"}, "cluster.local", map[string]interface{}{ config, err := k8sctrl.NewKubeletConfiguration(
"oomScoreAdj": -300, []string{"10.0.0.5"}, "cluster.local", map[string]interface{}{
"enableDebuggingHandlers": true, "oomScoreAdj": -300,
}) "enableDebuggingHandlers": true,
},
)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, &kubeletconfig.KubeletConfiguration{ assert.Equal(
TypeMeta: metav1.TypeMeta{ t, &kubeletconfig.KubeletConfiguration{
APIVersion: kubeletconfig.SchemeGroupVersion.String(), TypeMeta: metav1.TypeMeta{
Kind: "KubeletConfiguration", APIVersion: kubeletconfig.SchemeGroupVersion.String(),
}, Kind: "KubeletConfiguration",
StaticPodPath: constants.ManifestsDirectory,
Port: constants.KubeletPort,
Authentication: kubeletconfig.KubeletAuthentication{
X509: kubeletconfig.KubeletX509Authentication{
ClientCAFile: constants.KubernetesCACert,
}, },
Webhook: kubeletconfig.KubeletWebhookAuthentication{ StaticPodPath: constants.ManifestsDirectory,
Enabled: pointer.ToBool(true), Port: constants.KubeletPort,
Authentication: kubeletconfig.KubeletAuthentication{
X509: kubeletconfig.KubeletX509Authentication{
ClientCAFile: constants.KubernetesCACert,
},
Webhook: kubeletconfig.KubeletWebhookAuthentication{
Enabled: pointer.ToBool(true),
},
Anonymous: kubeletconfig.KubeletAnonymousAuthentication{
Enabled: pointer.ToBool(false),
},
}, },
Anonymous: kubeletconfig.KubeletAnonymousAuthentication{ Authorization: kubeletconfig.KubeletAuthorization{
Enabled: pointer.ToBool(false), Mode: kubeletconfig.KubeletAuthorizationModeWebhook,
}, },
CgroupRoot: "/",
SystemCgroups: constants.CgroupSystem,
KubeletCgroups: constants.CgroupKubelet,
RotateCertificates: true,
ProtectKernelDefaults: true,
Address: "0.0.0.0",
OOMScoreAdj: pointer.ToInt32(-300),
ClusterDomain: "cluster.local",
ClusterDNS: []string{"10.0.0.5"},
SerializeImagePulls: pointer.ToBool(false),
FailSwapOn: pointer.ToBool(false),
SystemReserved: map[string]string{
"cpu": constants.KubeletSystemReservedCPU,
"memory": constants.KubeletSystemReservedMemory,
"pid": constants.KubeletSystemReservedPid,
"ephemeral-storage": constants.KubeletSystemReservedEphemeralStorage,
},
Logging: v1alpha1.LoggingConfiguration{
Format: "json",
},
ShutdownGracePeriod: metav1.Duration{Duration: constants.KubeletShutdownGracePeriod},
ShutdownGracePeriodCriticalPods: metav1.Duration{Duration: constants.KubeletShutdownGracePeriodCriticalPods},
StreamingConnectionIdleTimeout: metav1.Duration{Duration: 5 * time.Minute},
TLSMinVersion: "VersionTLS13",
EnableDebuggingHandlers: pointer.ToBool(true),
}, },
Authorization: kubeletconfig.KubeletAuthorization{ config,
Mode: kubeletconfig.KubeletAuthorizationModeWebhook, )
},
CgroupRoot: "/",
SystemCgroups: constants.CgroupSystem,
KubeletCgroups: constants.CgroupKubelet,
RotateCertificates: true,
ProtectKernelDefaults: true,
Address: "0.0.0.0",
OOMScoreAdj: pointer.ToInt32(-300),
ClusterDomain: "cluster.local",
ClusterDNS: []string{"10.0.0.5"},
SerializeImagePulls: pointer.ToBool(false),
FailSwapOn: pointer.ToBool(false),
SystemReserved: map[string]string{
"cpu": constants.KubeletSystemReservedCPU,
"memory": constants.KubeletSystemReservedMemory,
"pid": constants.KubeletSystemReservedPid,
"ephemeral-storage": constants.KubeletSystemReservedEphemeralStorage,
},
Logging: v1alpha1.LoggingConfiguration{
Format: "json",
},
ShutdownGracePeriod: metav1.Duration{Duration: constants.KubeletShutdownGracePeriod},
ShutdownGracePeriodCriticalPods: metav1.Duration{Duration: constants.KubeletShutdownGracePeriodCriticalPods},
StreamingConnectionIdleTimeout: metav1.Duration{Duration: 5 * time.Minute},
TLSMinVersion: "VersionTLS13",
EnableDebuggingHandlers: pointer.ToBool(true),
},
config)
} }

View File

@ -39,7 +39,7 @@ type ManifestSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -70,7 +70,10 @@ func (suite *ManifestSuite) startRuntime() {
//nolint:dupl //nolint:dupl
func (suite *ManifestSuite) assertManifests(manifests []string) error { func (suite *ManifestSuite) assertManifests(manifests []string) error {
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.ManifestType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.ManifestType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -124,25 +127,27 @@ func (suite *ManifestSuite) TestReconcileDefaults() {
suite.Require().NoError(suite.state.Create(suite.ctx, rootSecrets)) suite.Require().NoError(suite.state.Create(suite.ctx, rootSecrets))
suite.Require().NoError(suite.state.Create(suite.ctx, manifestConfig)) suite.Require().NoError(suite.state.Create(suite.ctx, manifestConfig))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertManifests( func() error {
[]string{ return suite.assertManifests(
"00-kubelet-bootstrapping-token", []string{
"01-csr-approver-role-binding", "00-kubelet-bootstrapping-token",
"01-csr-node-bootstrap", "01-csr-approver-role-binding",
"01-csr-renewal-role-binding", "01-csr-node-bootstrap",
"02-kube-system-sa-role-binding", "01-csr-renewal-role-binding",
"03-default-pod-security-policy", "02-kube-system-sa-role-binding",
"05-flannel", "03-default-pod-security-policy",
"10-kube-proxy", "05-flannel",
"11-core-dns", "10-kube-proxy",
"11-core-dns-svc", "11-core-dns",
"11-kube-config-in-cluster", "11-core-dns-svc",
}, "11-kube-config-in-cluster",
) },
}, )
)) },
),
)
} }
func (suite *ManifestSuite) TestReconcileDisableKubeProxy() { func (suite *ManifestSuite) TestReconcileDisableKubeProxy() {
@ -155,24 +160,26 @@ func (suite *ManifestSuite) TestReconcileDisableKubeProxy() {
suite.Require().NoError(suite.state.Create(suite.ctx, rootSecrets)) suite.Require().NoError(suite.state.Create(suite.ctx, rootSecrets))
suite.Require().NoError(suite.state.Create(suite.ctx, manifestConfig)) suite.Require().NoError(suite.state.Create(suite.ctx, manifestConfig))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertManifests( func() error {
[]string{ return suite.assertManifests(
"00-kubelet-bootstrapping-token", []string{
"01-csr-approver-role-binding", "00-kubelet-bootstrapping-token",
"01-csr-node-bootstrap", "01-csr-approver-role-binding",
"01-csr-renewal-role-binding", "01-csr-node-bootstrap",
"02-kube-system-sa-role-binding", "01-csr-renewal-role-binding",
"03-default-pod-security-policy", "02-kube-system-sa-role-binding",
"05-flannel", "03-default-pod-security-policy",
"11-core-dns", "05-flannel",
"11-core-dns-svc", "11-core-dns",
"11-kube-config-in-cluster", "11-core-dns-svc",
}, "11-kube-config-in-cluster",
) },
}, )
)) },
),
)
} }
func (suite *ManifestSuite) TestReconcileKubeProxyExtraArgs() { func (suite *ManifestSuite) TestReconcileKubeProxyExtraArgs() {
@ -185,27 +192,37 @@ func (suite *ManifestSuite) TestReconcileKubeProxyExtraArgs() {
suite.Require().NoError(suite.state.Create(suite.ctx, rootSecrets)) suite.Require().NoError(suite.state.Create(suite.ctx, rootSecrets))
suite.Require().NoError(suite.state.Create(suite.ctx, manifestConfig)) suite.Require().NoError(suite.state.Create(suite.ctx, manifestConfig))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertManifests( func() error {
[]string{ return suite.assertManifests(
"00-kubelet-bootstrapping-token", []string{
"01-csr-approver-role-binding", "00-kubelet-bootstrapping-token",
"01-csr-node-bootstrap", "01-csr-approver-role-binding",
"01-csr-renewal-role-binding", "01-csr-node-bootstrap",
"02-kube-system-sa-role-binding", "01-csr-renewal-role-binding",
"03-default-pod-security-policy", "02-kube-system-sa-role-binding",
"05-flannel", "03-default-pod-security-policy",
"10-kube-proxy", "05-flannel",
"11-core-dns", "10-kube-proxy",
"11-core-dns-svc", "11-core-dns",
"11-kube-config-in-cluster", "11-core-dns-svc",
}, "11-kube-config-in-cluster",
) },
}, )
)) },
),
)
r, err := suite.state.Get(suite.ctx, resource.NewMetadata(k8s.ControlPlaneNamespaceName, k8s.ManifestType, "10-kube-proxy", resource.VersionUndefined)) r, err := suite.state.Get(
suite.ctx,
resource.NewMetadata(
k8s.ControlPlaneNamespaceName,
k8s.ManifestType,
"10-kube-proxy",
resource.VersionUndefined,
),
)
suite.Require().NoError(err) suite.Require().NoError(err)
manifest := r.(*k8s.Manifest) //nolint:errcheck,forcetypeassert manifest := r.(*k8s.Manifest) //nolint:errcheck,forcetypeassert
@ -230,24 +247,26 @@ func (suite *ManifestSuite) TestReconcileDisablePSP() {
suite.Require().NoError(suite.state.Create(suite.ctx, rootSecrets)) suite.Require().NoError(suite.state.Create(suite.ctx, rootSecrets))
suite.Require().NoError(suite.state.Create(suite.ctx, manifestConfig)) suite.Require().NoError(suite.state.Create(suite.ctx, manifestConfig))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertManifests( func() error {
[]string{ return suite.assertManifests(
"00-kubelet-bootstrapping-token", []string{
"01-csr-approver-role-binding", "00-kubelet-bootstrapping-token",
"01-csr-node-bootstrap", "01-csr-approver-role-binding",
"01-csr-renewal-role-binding", "01-csr-node-bootstrap",
"02-kube-system-sa-role-binding", "01-csr-renewal-role-binding",
"05-flannel", "02-kube-system-sa-role-binding",
"10-kube-proxy", "05-flannel",
"11-core-dns", "10-kube-proxy",
"11-core-dns-svc", "11-core-dns",
"11-kube-config-in-cluster", "11-core-dns-svc",
}, "11-kube-config-in-cluster",
) },
}, )
)) },
),
)
} }
func (suite *ManifestSuite) TearDownTest() { func (suite *ManifestSuite) TearDownTest() {

View File

@ -37,7 +37,7 @@ type NodeIPConfigSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -70,109 +70,139 @@ func (suite *NodeIPConfigSuite) TestReconcileWithSubnets() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{ ConfigVersion: "v1alpha1",
MachineKubelet: &v1alpha1.KubeletConfig{ MachineConfig: &v1alpha1.MachineConfig{
KubeletNodeIP: v1alpha1.KubeletNodeIPConfig{ MachineKubelet: &v1alpha1.KubeletConfig{
KubeletNodeIPValidSubnets: []string{"10.0.0.0/24"}, KubeletNodeIP: v1alpha1.KubeletNodeIPConfig{
KubeletNodeIPValidSubnets: []string{"10.0.0.0/24"},
},
}, },
}, MachineNetwork: &v1alpha1.NetworkConfig{
MachineNetwork: &v1alpha1.NetworkConfig{ NetworkInterfaces: []*v1alpha1.Device{
NetworkInterfaces: []*v1alpha1.Device{ {
{ DeviceVIPConfig: &v1alpha1.DeviceVIPConfig{
DeviceVIPConfig: &v1alpha1.DeviceVIPConfig{ SharedIP: "1.2.3.4",
SharedIP: "1.2.3.4", },
}, DeviceVlans: []*v1alpha1.Vlan{
DeviceVlans: []*v1alpha1.Vlan{ {
{ VlanID: 100,
VlanID: 100, VlanVIP: &v1alpha1.DeviceVIPConfig{
VlanVIP: &v1alpha1.DeviceVIPConfig{ SharedIP: "5.6.7.8",
SharedIP: "5.6.7.8", },
}, },
}, },
}, },
}, },
}, },
}, },
}, ClusterConfig: &v1alpha1.ClusterConfig{
ClusterConfig: &v1alpha1.ClusterConfig{ ControlPlane: &v1alpha1.ControlPlaneConfig{
ControlPlane: &v1alpha1.ControlPlaneConfig{ Endpoint: &v1alpha1.Endpoint{
Endpoint: &v1alpha1.Endpoint{ URL: u,
URL: u, },
},
ClusterNetwork: &v1alpha1.ClusterNetworkConfig{
ServiceSubnet: []string{constants.DefaultIPv4ServiceNet},
PodSubnet: []string{constants.DefaultIPv4PodNet},
}, },
}, },
ClusterNetwork: &v1alpha1.ClusterNetworkConfig{
ServiceSubnet: []string{constants.DefaultIPv4ServiceNet},
PodSubnet: []string{constants.DefaultIPv4PodNet},
},
}, },
}) )
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
NodeIPConfig, err := suite.state.Get(suite.ctx, resource.NewMetadata(k8s.NamespaceName, k8s.NodeIPConfigType, k8s.KubeletID, resource.VersionUndefined)) func() error {
if err != nil { NodeIPConfig, err := suite.state.Get(
if state.IsNotFoundError(err) { suite.ctx,
return retry.ExpectedError(err) resource.NewMetadata(
k8s.NamespaceName,
k8s.NodeIPConfigType,
k8s.KubeletID,
resource.VersionUndefined,
),
)
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
}
return err
} }
return err spec := NodeIPConfig.(*k8s.NodeIPConfig).TypedSpec()
}
spec := NodeIPConfig.(*k8s.NodeIPConfig).TypedSpec() suite.Assert().Equal([]string{"10.0.0.0/24"}, spec.ValidSubnets)
suite.Assert().Equal(
[]string{"10.244.0.0/16", "10.96.0.0/12", "1.2.3.4", "5.6.7.8"},
spec.ExcludeSubnets,
)
suite.Assert().Equal([]string{"10.0.0.0/24"}, spec.ValidSubnets) return nil
suite.Assert().Equal([]string{"10.244.0.0/16", "10.96.0.0/12", "1.2.3.4", "5.6.7.8"}, spec.ExcludeSubnets) },
),
return nil )
},
))
} }
func (suite *NodeIPConfigSuite) TestReconcileDefaults() { func (suite *NodeIPConfigSuite) TestReconcileDefaults() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{}, ConfigVersion: "v1alpha1",
ClusterConfig: &v1alpha1.ClusterConfig{ MachineConfig: &v1alpha1.MachineConfig{},
ControlPlane: &v1alpha1.ControlPlaneConfig{ ClusterConfig: &v1alpha1.ClusterConfig{
Endpoint: &v1alpha1.Endpoint{ ControlPlane: &v1alpha1.ControlPlaneConfig{
URL: u, Endpoint: &v1alpha1.Endpoint{
URL: u,
},
},
ClusterNetwork: &v1alpha1.ClusterNetworkConfig{
ServiceSubnet: []string{constants.DefaultIPv4ServiceNet, constants.DefaultIPv6ServiceNet},
PodSubnet: []string{constants.DefaultIPv4PodNet, constants.DefaultIPv6PodNet},
}, },
}, },
ClusterNetwork: &v1alpha1.ClusterNetworkConfig{
ServiceSubnet: []string{constants.DefaultIPv4ServiceNet, constants.DefaultIPv6ServiceNet},
PodSubnet: []string{constants.DefaultIPv4PodNet, constants.DefaultIPv6PodNet},
},
}, },
}) )
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
NodeIPConfig, err := suite.state.Get(suite.ctx, resource.NewMetadata(k8s.NamespaceName, k8s.NodeIPConfigType, k8s.KubeletID, resource.VersionUndefined)) func() error {
if err != nil { NodeIPConfig, err := suite.state.Get(
if state.IsNotFoundError(err) { suite.ctx,
return retry.ExpectedError(err) resource.NewMetadata(
k8s.NamespaceName,
k8s.NodeIPConfigType,
k8s.KubeletID,
resource.VersionUndefined,
),
)
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
}
return err
} }
return err spec := NodeIPConfig.(*k8s.NodeIPConfig).TypedSpec()
}
spec := NodeIPConfig.(*k8s.NodeIPConfig).TypedSpec() suite.Assert().Equal([]string{"0.0.0.0/0", "::/0"}, spec.ValidSubnets)
suite.Assert().Equal(
[]string{"10.244.0.0/16", "fc00:db8:10::/56", "10.96.0.0/12", "fc00:db8:20::/112"},
spec.ExcludeSubnets,
)
suite.Assert().Equal([]string{"0.0.0.0/0", "::/0"}, spec.ValidSubnets) return nil
suite.Assert().Equal([]string{"10.244.0.0/16", "fc00:db8:10::/56", "10.96.0.0/12", "fc00:db8:20::/112"}, spec.ExcludeSubnets) },
),
return nil )
},
))
} }
func (suite *NodeIPConfigSuite) TearDownTest() { func (suite *NodeIPConfigSuite) TearDownTest() {

View File

@ -36,7 +36,7 @@ type NodeIPSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -75,7 +75,10 @@ func (suite *NodeIPSuite) TestReconcileIPv4() {
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
addresses := network.NewNodeAddress(network.NamespaceName, network.FilteredNodeAddressID(network.NodeAddressCurrentID, k8s.NodeAddressFilterNoK8s)) addresses := network.NewNodeAddress(
network.NamespaceName,
network.FilteredNodeAddressID(network.NodeAddressCurrentID, k8s.NodeAddressFilterNoK8s),
)
addresses.TypedSpec().Addresses = []netaddr.IPPrefix{ addresses.TypedSpec().Addresses = []netaddr.IPPrefix{
netaddr.MustParseIPPrefix("10.0.0.2/32"), // excluded explicitly netaddr.MustParseIPPrefix("10.0.0.2/32"), // excluded explicitly
@ -85,24 +88,29 @@ func (suite *NodeIPSuite) TestReconcileIPv4() {
suite.Require().NoError(suite.state.Create(suite.ctx, addresses)) suite.Require().NoError(suite.state.Create(suite.ctx, addresses))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
NodeIP, err := suite.state.Get(suite.ctx, resource.NewMetadata(k8s.NamespaceName, k8s.NodeIPType, k8s.KubeletID, resource.VersionUndefined)) func() error {
if err != nil { NodeIP, err := suite.state.Get(
if state.IsNotFoundError(err) { suite.ctx,
return retry.ExpectedError(err) resource.NewMetadata(k8s.NamespaceName, k8s.NodeIPType, k8s.KubeletID, resource.VersionUndefined),
)
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
}
return err
} }
return err spec := NodeIP.(*k8s.NodeIP).TypedSpec()
}
spec := NodeIP.(*k8s.NodeIP).TypedSpec() suite.Assert().Equal("[10.0.0.5]", fmt.Sprintf("%s", spec.Addresses))
suite.Assert().Equal("[10.0.0.5]", fmt.Sprintf("%s", spec.Addresses)) return nil
},
return nil ),
}, )
))
} }
func (suite *NodeIPSuite) TestReconcileDefaultSubnets() { func (suite *NodeIPSuite) TestReconcileDefaultSubnets() {
@ -114,7 +122,10 @@ func (suite *NodeIPSuite) TestReconcileDefaultSubnets() {
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
addresses := network.NewNodeAddress(network.NamespaceName, network.FilteredNodeAddressID(network.NodeAddressCurrentID, k8s.NodeAddressFilterNoK8s)) addresses := network.NewNodeAddress(
network.NamespaceName,
network.FilteredNodeAddressID(network.NodeAddressCurrentID, k8s.NodeAddressFilterNoK8s),
)
addresses.TypedSpec().Addresses = []netaddr.IPPrefix{ addresses.TypedSpec().Addresses = []netaddr.IPPrefix{
netaddr.MustParseIPPrefix("10.0.0.5/24"), netaddr.MustParseIPPrefix("10.0.0.5/24"),
@ -125,24 +136,29 @@ func (suite *NodeIPSuite) TestReconcileDefaultSubnets() {
suite.Require().NoError(suite.state.Create(suite.ctx, addresses)) suite.Require().NoError(suite.state.Create(suite.ctx, addresses))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
NodeIP, err := suite.state.Get(suite.ctx, resource.NewMetadata(k8s.NamespaceName, k8s.NodeIPType, k8s.KubeletID, resource.VersionUndefined)) func() error {
if err != nil { NodeIP, err := suite.state.Get(
if state.IsNotFoundError(err) { suite.ctx,
return retry.ExpectedError(err) resource.NewMetadata(k8s.NamespaceName, k8s.NodeIPType, k8s.KubeletID, resource.VersionUndefined),
)
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
}
return err
} }
return err spec := NodeIP.(*k8s.NodeIP).TypedSpec()
}
spec := NodeIP.(*k8s.NodeIP).TypedSpec() suite.Assert().Equal("[10.0.0.5 2001:db8:85a3::8a2e:370:7334]", fmt.Sprintf("%s", spec.Addresses))
suite.Assert().Equal("[10.0.0.5 2001:db8:85a3::8a2e:370:7334]", fmt.Sprintf("%s", spec.Addresses)) return nil
},
return nil ),
}, )
))
} }
func (suite *NodeIPSuite) TearDownTest() { func (suite *NodeIPSuite) TearDownTest() {

View File

@ -38,7 +38,7 @@ type NodenameSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -69,7 +69,10 @@ func (suite *NodenameSuite) startRuntime() {
//nolint:dupl //nolint:dupl
func (suite *NodenameSuite) assertNodename(expected string) error { func (suite *NodenameSuite) assertNodename(expected string) error {
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(k8s.NamespaceName, k8s.NodenameType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(k8s.NamespaceName, k8s.NodenameType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -83,7 +86,11 @@ func (suite *NodenameSuite) assertNodename(expected string) error {
} }
if resources.Items[0].(*k8s.Nodename).TypedSpec().Nodename != expected { if resources.Items[0].(*k8s.Nodename).TypedSpec().Nodename != expected {
return retry.ExpectedErrorf("expected %q, got %q", expected, resources.Items[0].(*k8s.Nodename).TypedSpec().Nodename) return retry.ExpectedErrorf(
"expected %q, got %q",
expected,
resources.Items[0].(*k8s.Nodename).TypedSpec().Nodename,
)
} }
return nil return nil
@ -93,17 +100,19 @@ func (suite *NodenameSuite) TestDefault() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{}, ConfigVersion: "v1alpha1",
ClusterConfig: &v1alpha1.ClusterConfig{ MachineConfig: &v1alpha1.MachineConfig{},
ControlPlane: &v1alpha1.ControlPlaneConfig{ ClusterConfig: &v1alpha1.ClusterConfig{
Endpoint: &v1alpha1.Endpoint{ ControlPlane: &v1alpha1.ControlPlaneConfig{
URL: u, Endpoint: &v1alpha1.Endpoint{
URL: u,
},
}, },
}, },
}, },
}) )
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
@ -113,32 +122,36 @@ func (suite *NodenameSuite) TestDefault() {
suite.Require().NoError(suite.state.Create(suite.ctx, hostnameStatus)) suite.Require().NoError(suite.state.Create(suite.ctx, hostnameStatus))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNodename("foo") func() error {
}, return suite.assertNodename("foo")
)) },
),
)
} }
func (suite *NodenameSuite) TestFQDN() { func (suite *NodenameSuite) TestFQDN() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{ ConfigVersion: "v1alpha1",
MachineKubelet: &v1alpha1.KubeletConfig{ MachineConfig: &v1alpha1.MachineConfig{
KubeletRegisterWithFQDN: true, MachineKubelet: &v1alpha1.KubeletConfig{
KubeletRegisterWithFQDN: true,
},
}, },
}, ClusterConfig: &v1alpha1.ClusterConfig{
ClusterConfig: &v1alpha1.ClusterConfig{ ControlPlane: &v1alpha1.ControlPlaneConfig{
ControlPlane: &v1alpha1.ControlPlaneConfig{ Endpoint: &v1alpha1.Endpoint{
Endpoint: &v1alpha1.Endpoint{ URL: u,
URL: u, },
}, },
}, },
}, },
}) )
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
@ -148,11 +161,13 @@ func (suite *NodenameSuite) TestFQDN() {
suite.Require().NoError(suite.state.Create(suite.ctx, hostnameStatus)) suite.Require().NoError(suite.state.Create(suite.ctx, hostnameStatus))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNodename("foo.bar.ltd") func() error {
}, return suite.assertNodename("foo.bar.ltd")
)) },
),
)
} }
func (suite *NodenameSuite) TearDownTest() { func (suite *NodenameSuite) TearDownTest() {
@ -163,17 +178,26 @@ func (suite *NodenameSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ err := suite.state.Create(
ConfigVersion: "v1alpha1", context.Background(), config.NewMachineConfig(
MachineConfig: &v1alpha1.MachineConfig{}, &v1alpha1.Config{
})) ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{},
},
),
)
if state.IsConflictError(err) { if state.IsConflictError(err) {
err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata())
} }
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewHostnameStatus(network.NamespaceName, "bar"))) suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewHostnameStatus(network.NamespaceName, "bar"),
),
)
} }
func TestNodenameSuite(t *testing.T) { func TestNodenameSuite(t *testing.T) {

View File

@ -36,7 +36,7 @@ type StaticPodConfigSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -65,7 +65,10 @@ func (suite *StaticPodConfigSuite) startRuntime() {
}() }()
} }
func (suite *StaticPodConfigSuite) assertResource(md resource.Metadata, check func(res resource.Resource) error) func() error { func (suite *StaticPodConfigSuite) assertResource(
md resource.Metadata,
check func(res resource.Resource) error,
) func() error {
return func() error { return func() error {
r, err := suite.state.Get(suite.ctx, md) r, err := suite.state.Get(suite.ctx, md)
if err != nil { if err != nil {
@ -96,47 +99,51 @@ func (suite *StaticPodConfigSuite) assertNoResource(md resource.Metadata) func()
} }
func (suite *StaticPodConfigSuite) TestReconcile() { func (suite *StaticPodConfigSuite) TestReconcile() {
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{ ConfigVersion: "v1alpha1",
MachinePods: []v1alpha1.Unstructured{ MachineConfig: &v1alpha1.MachineConfig{
{ MachinePods: []v1alpha1.Unstructured{
Object: map[string]interface{}{ {
"apiVersion": "v1", Object: map[string]interface{}{
"kind": "pod", "apiVersion": "v1",
"metadata": map[string]interface{}{ "kind": "pod",
"name": "nginx", "metadata": map[string]interface{}{
}, "name": "nginx",
"spec": map[string]interface{}{ },
"containers": []interface{}{ "spec": map[string]interface{}{
map[string]interface{}{ "containers": []interface{}{
"name": "nginx", map[string]interface{}{
"image": "nginx", "name": "nginx",
"image": "nginx",
},
}, },
}, },
}, },
}, },
}, },
}, },
ClusterConfig: &v1alpha1.ClusterConfig{},
}, },
ClusterConfig: &v1alpha1.ClusterConfig{}, )
})
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
suite.assertResource( retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
*k8s.NewStaticPod(k8s.NamespaceName, "default-nginx").Metadata(), suite.assertResource(
func(res resource.Resource) error { *k8s.NewStaticPod(k8s.NamespaceName, "default-nginx").Metadata(),
v, ok, err := unstructured.NestedString(res.(*k8s.StaticPod).TypedSpec().Pod, "kind") func(res resource.Resource) error {
suite.Require().NoError(err) v, ok, err := unstructured.NestedString(res.(*k8s.StaticPod).TypedSpec().Pod, "kind")
suite.Assert().True(ok) suite.Require().NoError(err)
suite.Assert().Equal("pod", v) suite.Assert().True(ok)
suite.Assert().Equal("pod", v)
return nil return nil
}, },
),
), ),
)) )
// update the pod changing the namespace // update the pod changing the namespace
cfg.Config().Raw().(*v1alpha1.Config).MachineConfig.MachinePods[0].Object["metadata"].(map[string]interface{})["namespace"] = "custom" cfg.Config().Raw().(*v1alpha1.Config).MachineConfig.MachinePods[0].Object["metadata"].(map[string]interface{})["namespace"] = "custom"
@ -144,24 +151,32 @@ func (suite *StaticPodConfigSuite) TestReconcile() {
cfg.Metadata().BumpVersion() cfg.Metadata().BumpVersion()
suite.Require().NoError(suite.state.Update(suite.ctx, oldVersion, cfg)) suite.Require().NoError(suite.state.Update(suite.ctx, oldVersion, cfg))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
suite.assertNoResource( retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
*k8s.NewStaticPod(k8s.NamespaceName, "default-nginx").Metadata(), suite.assertNoResource(
*k8s.NewStaticPod(k8s.NamespaceName, "default-nginx").Metadata(),
),
), ),
)) )
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
suite.assertResource( retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
*k8s.NewStaticPod(k8s.NamespaceName, "custom-nginx").Metadata(), suite.assertResource(
func(res resource.Resource) error { *k8s.NewStaticPod(k8s.NamespaceName, "custom-nginx").Metadata(),
v, ok, err := unstructured.NestedString(res.(*k8s.StaticPod).TypedSpec().Pod, "metadata", "namespace") func(res resource.Resource) error {
suite.Require().NoError(err) v, ok, err := unstructured.NestedString(
suite.Assert().True(ok) res.(*k8s.StaticPod).TypedSpec().Pod,
suite.Assert().Equal("custom", v) "metadata",
"namespace",
)
suite.Require().NoError(err)
suite.Assert().True(ok)
suite.Assert().Equal("custom", v)
return nil return nil
}, },
),
), ),
)) )
// remove all pods // remove all pods
cfg.Config().Raw().(*v1alpha1.Config).MachineConfig.MachinePods = nil cfg.Config().Raw().(*v1alpha1.Config).MachineConfig.MachinePods = nil
@ -169,11 +184,13 @@ func (suite *StaticPodConfigSuite) TestReconcile() {
cfg.Metadata().BumpVersion() cfg.Metadata().BumpVersion()
suite.Require().NoError(suite.state.Update(suite.ctx, oldVersion, cfg)) suite.Require().NoError(suite.state.Update(suite.ctx, oldVersion, cfg))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
suite.assertNoResource( retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
*k8s.NewStaticPod(k8s.NamespaceName, "custom-nginx").Metadata(), suite.assertNoResource(
*k8s.NewStaticPod(k8s.NamespaceName, "custom-nginx").Metadata(),
),
), ),
)) )
} }
func (suite *StaticPodConfigSuite) TearDownTest() { func (suite *StaticPodConfigSuite) TearDownTest() {

View File

@ -33,7 +33,7 @@ type KubeSpanSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -136,10 +136,14 @@ func (suite *KubeSpanSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ err := suite.state.Create(
ConfigVersion: "v1alpha1", context.Background(), config.NewMachineConfig(
MachineConfig: &v1alpha1.MachineConfig{}, &v1alpha1.Config{
})) ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{},
},
),
)
if state.IsConflictError(err) { if state.IsConflictError(err) {
err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata())
} }

View File

@ -40,10 +40,12 @@ func (suite *ManagerSuite) TestDisabled() {
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
suite.assertNoResourceType( retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
resource.NewMetadata(kubespan.NamespaceName, kubespan.PeerStatusType, "", resource.VersionUndefined), suite.assertNoResourceType(
)), resource.NewMetadata(kubespan.NamespaceName, kubespan.PeerStatusType, "", resource.VersionUndefined),
),
),
) )
} }
@ -114,18 +116,22 @@ func (suite *ManagerSuite) TestReconcile() {
mockWireguard := &mockWireguardClient{} mockWireguard := &mockWireguardClient{}
mockNfTables := &mockNftablesManager{} mockNfTables := &mockNftablesManager{}
suite.Require().NoError(suite.runtime.RegisterController(&kubespanctrl.ManagerController{ suite.Require().NoError(
WireguardClientFactory: func() (kubespanctrl.WireguardClient, error) { suite.runtime.RegisterController(
return mockWireguard, nil &kubespanctrl.ManagerController{
}, WireguardClientFactory: func() (kubespanctrl.WireguardClient, error) {
RulesManagerFactory: func(_, _ int) kubespanctrl.RulesManager { return mockWireguard, nil
return mockRulesManager{} },
}, RulesManagerFactory: func(_, _ int) kubespanctrl.RulesManager {
NfTablesManagerFactory: func(_, _ uint32) kubespanctrl.NfTablesManager { return mockRulesManager{}
return mockNfTables },
}, NfTablesManagerFactory: func(_, _ uint32) kubespanctrl.NfTablesManager {
PeerReconcileInterval: time.Second, return mockNfTables
})) },
PeerReconcileInterval: time.Second,
},
),
)
suite.startRuntime() suite.startRuntime()
@ -140,82 +146,116 @@ func (suite *ManagerSuite) TestReconcile() {
localIdentity := kubespan.NewIdentity(kubespan.NamespaceName, kubespan.LocalIdentity) localIdentity := kubespan.NewIdentity(kubespan.NamespaceName, kubespan.LocalIdentity)
suite.Require().NoError(kubespanadapter.IdentitySpec(localIdentity.TypedSpec()).GenerateKey()) suite.Require().NoError(kubespanadapter.IdentitySpec(localIdentity.TypedSpec()).GenerateKey())
suite.Require().NoError(kubespanadapter.IdentitySpec(localIdentity.TypedSpec()).UpdateAddress("v16UCWpO2iOm82n6F8dGCJ41ZXXBvDrjRDs2su7C_zs=", mac)) suite.Require().NoError(
kubespanadapter.IdentitySpec(localIdentity.TypedSpec()).UpdateAddress(
"v16UCWpO2iOm82n6F8dGCJ41ZXXBvDrjRDs2su7C_zs=",
mac,
),
)
suite.Require().NoError(suite.state.Create(suite.ctx, localIdentity)) suite.Require().NoError(suite.state.Create(suite.ctx, localIdentity))
// initial setup: link should be created without any peers // initial setup: link should be created without any peers
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
suite.assertResource( retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
resource.NewMetadata( suite.assertResource(
network.ConfigNamespaceName, resource.NewMetadata(
network.LinkSpecType, network.ConfigNamespaceName,
network.LayeredID(network.ConfigOperator, network.LinkID(constants.KubeSpanLinkName)), network.LinkSpecType,
resource.VersionUndefined, network.LayeredID(network.ConfigOperator, network.LinkID(constants.KubeSpanLinkName)),
resource.VersionUndefined,
),
func(res resource.Resource) error {
spec := res.(*network.LinkSpec).TypedSpec()
suite.Assert().Equal(network.ConfigOperator, spec.ConfigLayer)
suite.Assert().Equal(constants.KubeSpanLinkName, spec.Name)
suite.Assert().Equal(nethelpers.LinkNone, spec.Type)
suite.Assert().Equal("wireguard", spec.Kind)
suite.Assert().True(spec.Up)
suite.Assert().True(spec.Logical)
suite.Assert().Equal(localIdentity.TypedSpec().PrivateKey, spec.Wireguard.PrivateKey)
suite.Assert().Equal(constants.KubeSpanDefaultPort, spec.Wireguard.ListenPort)
suite.Assert().Equal(constants.KubeSpanDefaultFirewallMark, spec.Wireguard.FirewallMark)
suite.Assert().Len(spec.Wireguard.Peers, 0)
return nil
},
), ),
func(res resource.Resource) error {
spec := res.(*network.LinkSpec).TypedSpec()
suite.Assert().Equal(network.ConfigOperator, spec.ConfigLayer)
suite.Assert().Equal(constants.KubeSpanLinkName, spec.Name)
suite.Assert().Equal(nethelpers.LinkNone, spec.Type)
suite.Assert().Equal("wireguard", spec.Kind)
suite.Assert().True(spec.Up)
suite.Assert().True(spec.Logical)
suite.Assert().Equal(localIdentity.TypedSpec().PrivateKey, spec.Wireguard.PrivateKey)
suite.Assert().Equal(constants.KubeSpanDefaultPort, spec.Wireguard.ListenPort)
suite.Assert().Equal(constants.KubeSpanDefaultFirewallMark, spec.Wireguard.FirewallMark)
suite.Assert().Len(spec.Wireguard.Peers, 0)
return nil
},
), ),
)) )
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
suite.assertResource( retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
resource.NewMetadata( suite.assertResource(
network.ConfigNamespaceName, resource.NewMetadata(
network.AddressSpecType, network.ConfigNamespaceName,
network.LayeredID(network.ConfigOperator, network.AddressID(constants.KubeSpanLinkName, localIdentity.TypedSpec().Address)), network.AddressSpecType,
resource.VersionUndefined, network.LayeredID(
network.ConfigOperator,
network.AddressID(constants.KubeSpanLinkName, localIdentity.TypedSpec().Address),
),
resource.VersionUndefined,
),
func(res resource.Resource) error {
spec := res.(*network.AddressSpec).TypedSpec()
suite.Assert().Equal(localIdentity.TypedSpec().Address.IP(), spec.Address.IP())
suite.Assert().Equal(localIdentity.TypedSpec().Subnet.Bits(), spec.Address.Bits())
suite.Assert().Equal(network.ConfigOperator, spec.ConfigLayer)
suite.Assert().Equal(nethelpers.FamilyInet6, spec.Family)
suite.Assert().Equal(nethelpers.AddressFlags(nethelpers.AddressPermanent), spec.Flags)
suite.Assert().Equal(constants.KubeSpanLinkName, spec.LinkName)
suite.Assert().Equal(nethelpers.ScopeGlobal, spec.Scope)
return nil
},
), ),
func(res resource.Resource) error {
spec := res.(*network.AddressSpec).TypedSpec()
suite.Assert().Equal(localIdentity.TypedSpec().Address.IP(), spec.Address.IP())
suite.Assert().Equal(localIdentity.TypedSpec().Subnet.Bits(), spec.Address.Bits())
suite.Assert().Equal(network.ConfigOperator, spec.ConfigLayer)
suite.Assert().Equal(nethelpers.FamilyInet6, spec.Family)
suite.Assert().Equal(nethelpers.AddressFlags(nethelpers.AddressPermanent), spec.Flags)
suite.Assert().Equal(constants.KubeSpanLinkName, spec.LinkName)
suite.Assert().Equal(nethelpers.ScopeGlobal, spec.Scope)
return nil
},
), ),
)) )
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
suite.assertResourceIDs( retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
resource.NewMetadata( suite.assertResourceIDs(
network.ConfigNamespaceName, resource.NewMetadata(
network.RouteSpecType, network.ConfigNamespaceName,
"", network.RouteSpecType,
resource.VersionUndefined, "",
resource.VersionUndefined,
),
[]resource.ID{
network.LayeredID(
network.ConfigOperator,
network.RouteID(
constants.KubeSpanDefaultRoutingTable,
nethelpers.FamilyInet4,
netaddr.IPPrefix{},
netaddr.IP{},
1,
),
),
network.LayeredID(
network.ConfigOperator,
network.RouteID(
constants.KubeSpanDefaultRoutingTable,
nethelpers.FamilyInet6,
netaddr.IPPrefix{},
netaddr.IP{},
1,
),
),
},
), ),
[]resource.ID{
network.LayeredID(network.ConfigOperator, network.RouteID(constants.KubeSpanDefaultRoutingTable, nethelpers.FamilyInet4, netaddr.IPPrefix{}, netaddr.IP{}, 1)),
network.LayeredID(network.ConfigOperator, network.RouteID(constants.KubeSpanDefaultRoutingTable, nethelpers.FamilyInet6, netaddr.IPPrefix{}, netaddr.IP{}, 1)),
},
), ),
)) )
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
suite.assertNoResourceType( retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
resource.NewMetadata(kubespan.NamespaceName, kubespan.PeerStatusType, "", resource.VersionUndefined), suite.assertNoResourceType(
resource.NewMetadata(kubespan.NamespaceName, kubespan.PeerStatusType, "", resource.VersionUndefined),
),
), ),
)) )
// add two peers, they should be added to the wireguard link spec and should be tracked in peer statuses // add two peers, they should be added to the wireguard link spec and should be tracked in peer statuses
peer1 := kubespan.NewPeerSpec(kubespan.NamespaceName, "3FxU7UuwektMjbyuJBs7i1hDj2rQA6tHnbNB6WrQxww=") peer1 := kubespan.NewPeerSpec(kubespan.NamespaceName, "3FxU7UuwektMjbyuJBs7i1hDj2rQA6tHnbNB6WrQxww=")
@ -246,72 +286,83 @@ func (suite *ManagerSuite) TestReconcile() {
key2, err := wgtypes.ParseKey(peer2.Metadata().ID()) key2, err := wgtypes.ParseKey(peer2.Metadata().ID())
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
suite.assertResource( retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
resource.NewMetadata( suite.assertResource(
network.ConfigNamespaceName, resource.NewMetadata(
network.LinkSpecType, network.ConfigNamespaceName,
network.LayeredID(network.ConfigOperator, network.LinkID(constants.KubeSpanLinkName)), network.LinkSpecType,
resource.VersionUndefined, network.LayeredID(network.ConfigOperator, network.LinkID(constants.KubeSpanLinkName)),
), resource.VersionUndefined,
func(res resource.Resource) error { ),
spec := res.(*network.LinkSpec).TypedSpec() func(res resource.Resource) error {
spec := res.(*network.LinkSpec).TypedSpec()
if len(spec.Wireguard.Peers) != 2 { if len(spec.Wireguard.Peers) != 2 {
return retry.ExpectedErrorf("peers not set up yet") return retry.ExpectedErrorf("peers not set up yet")
}
for i, peer := range []*kubespan.PeerSpec{peer1, peer2} {
suite.Assert().Equal(peer.Metadata().ID(), spec.Wireguard.Peers[i].PublicKey)
suite.Assert().Equal(cfg.TypedSpec().SharedSecret, spec.Wireguard.Peers[i].PresharedKey)
suite.Assert().Equal(peer.TypedSpec().AllowedIPs, spec.Wireguard.Peers[i].AllowedIPs)
suite.Assert().Equal(peer.TypedSpec().Endpoints[0].String(), spec.Wireguard.Peers[i].Endpoint)
}
return nil
},
),
),
)
for _, peer := range []*kubespan.PeerSpec{peer1, peer2} {
peer := peer
suite.Assert().NoError(
retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
suite.assertResource(
resource.NewMetadata(
kubespan.NamespaceName,
kubespan.PeerStatusType,
peer.Metadata().ID(),
resource.VersionUndefined,
),
func(res resource.Resource) error {
spec := res.(*kubespan.PeerStatus).TypedSpec()
suite.Assert().Equal(peer.TypedSpec().Label, spec.Label)
suite.Assert().Equal(kubespan.PeerStateUnknown, spec.State)
suite.Assert().Equal(peer.TypedSpec().Endpoints[0], spec.Endpoint)
suite.Assert().Equal(peer.TypedSpec().Endpoints[0], spec.LastUsedEndpoint)
suite.Assert().WithinDuration(time.Now(), spec.LastEndpointChange, 3*time.Second)
return nil
},
),
),
)
}
suite.Assert().NoError(
retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
func() error {
ipSet := mockNfTables.IPSet()
if ipSet == nil {
return retry.ExpectedErrorf("ipset is nil")
} }
for i, peer := range []*kubespan.PeerSpec{peer1, peer2} { ranges := fmt.Sprintf("%v", ipSet.Ranges())
suite.Assert().Equal(peer.Metadata().ID(), spec.Wireguard.Peers[i].PublicKey) expected := "[10.244.1.0-10.244.2.255]"
suite.Assert().Equal(cfg.TypedSpec().SharedSecret, spec.Wireguard.Peers[i].PresharedKey)
suite.Assert().Equal(peer.TypedSpec().AllowedIPs, spec.Wireguard.Peers[i].AllowedIPs) if ranges != expected {
suite.Assert().Equal(peer.TypedSpec().Endpoints[0].String(), spec.Wireguard.Peers[i].Endpoint) return retry.ExpectedErrorf("ranges %s != expected %s", ranges, expected)
} }
return nil return nil
}, },
), ),
)) )
for _, peer := range []*kubespan.PeerSpec{peer1, peer2} {
peer := peer
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
suite.assertResource(
resource.NewMetadata(kubespan.NamespaceName, kubespan.PeerStatusType, peer.Metadata().ID(), resource.VersionUndefined),
func(res resource.Resource) error {
spec := res.(*kubespan.PeerStatus).TypedSpec()
suite.Assert().Equal(peer.TypedSpec().Label, spec.Label)
suite.Assert().Equal(kubespan.PeerStateUnknown, spec.State)
suite.Assert().Equal(peer.TypedSpec().Endpoints[0], spec.Endpoint)
suite.Assert().Equal(peer.TypedSpec().Endpoints[0], spec.LastUsedEndpoint)
suite.Assert().WithinDuration(time.Now(), spec.LastEndpointChange, 3*time.Second)
return nil
},
),
))
}
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
func() error {
ipSet := mockNfTables.IPSet()
if ipSet == nil {
return retry.ExpectedErrorf("ipset is nil")
}
ranges := fmt.Sprintf("%v", ipSet.Ranges())
expected := "[10.244.1.0-10.244.2.255]"
if ranges != expected {
return retry.ExpectedErrorf("ranges %s != expected %s", ranges, expected)
}
return nil
},
))
// update config and disable force routing, nothing should be routed // update config and disable force routing, nothing should be routed
oldVersion := cfg.Metadata().Version() oldVersion := cfg.Metadata().Version()
@ -319,76 +370,89 @@ func (suite *ManagerSuite) TestReconcile() {
cfg.Metadata().BumpVersion() cfg.Metadata().BumpVersion()
suite.Require().NoError(suite.state.Update(suite.ctx, oldVersion, cfg)) suite.Require().NoError(suite.state.Update(suite.ctx, oldVersion, cfg))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
ipSet := mockNfTables.IPSet() func() error {
ipSet := mockNfTables.IPSet()
if ipSet == nil { if ipSet == nil {
return retry.ExpectedErrorf("ipset is nil") return retry.ExpectedErrorf("ipset is nil")
} }
if len(ipSet.Prefixes()) != 0 { if len(ipSet.Prefixes()) != 0 {
return retry.ExpectedErrorf("expected empty ipset: %v", ipSet.Ranges()) return retry.ExpectedErrorf("expected empty ipset: %v", ipSet.Ranges())
} }
return nil return nil
}, },
)) ),
)
// report up status via wireguard mock // report up status via wireguard mock
mockWireguard.update(&wgtypes.Device{ mockWireguard.update(
Peers: []wgtypes.Peer{ &wgtypes.Device{
{ Peers: []wgtypes.Peer{
PublicKey: key1, {
Endpoint: peer1.TypedSpec().Endpoints[0].UDPAddr(), PublicKey: key1,
LastHandshakeTime: time.Now(), Endpoint: peer1.TypedSpec().Endpoints[0].UDPAddr(),
}, LastHandshakeTime: time.Now(),
{ },
PublicKey: key2, {
Endpoint: peer2.TypedSpec().Endpoints[0].UDPAddr(), PublicKey: key2,
LastHandshakeTime: time.Now(), Endpoint: peer2.TypedSpec().Endpoints[0].UDPAddr(),
LastHandshakeTime: time.Now(),
},
}, },
}, },
}) )
for _, peer := range []*kubespan.PeerSpec{peer1, peer2} { for _, peer := range []*kubespan.PeerSpec{peer1, peer2} {
peer := peer peer := peer
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
suite.assertResource( retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
resource.NewMetadata(kubespan.NamespaceName, kubespan.PeerStatusType, peer.Metadata().ID(), resource.VersionUndefined), suite.assertResource(
func(res resource.Resource) error { resource.NewMetadata(
spec := res.(*kubespan.PeerStatus).TypedSpec() kubespan.NamespaceName,
kubespan.PeerStatusType,
peer.Metadata().ID(),
resource.VersionUndefined,
),
func(res resource.Resource) error {
spec := res.(*kubespan.PeerStatus).TypedSpec()
if spec.State != kubespan.PeerStateUp { if spec.State != kubespan.PeerStateUp {
return retry.ExpectedErrorf("peer state is not up yet: %s", spec.State) return retry.ExpectedErrorf("peer state is not up yet: %s", spec.State)
} }
return nil return nil
}, },
),
), ),
)) )
} }
// as the peers are now up, all traffic should be routed via KubeSpan // as the peers are now up, all traffic should be routed via KubeSpan
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
ipSet := mockNfTables.IPSet() func() error {
ipSet := mockNfTables.IPSet()
if ipSet == nil { if ipSet == nil {
return retry.ExpectedErrorf("ipset is nil") return retry.ExpectedErrorf("ipset is nil")
} }
ranges := fmt.Sprintf("%v", ipSet.Ranges()) ranges := fmt.Sprintf("%v", ipSet.Ranges())
expected := "[10.244.1.0-10.244.2.255]" expected := "[10.244.1.0-10.244.2.255]"
if ranges != expected { if ranges != expected {
return retry.ExpectedErrorf("ranges %s != expected %s", ranges, expected) return retry.ExpectedErrorf("ranges %s != expected %s", ranges, expected)
} }
return nil return nil
}, },
)) ),
)
// update config and disable wireguard, everything should be cleaned up // update config and disable wireguard, everything should be cleaned up
oldVersion = cfg.Metadata().Version() oldVersion = cfg.Metadata().Version()
@ -396,11 +460,18 @@ func (suite *ManagerSuite) TestReconcile() {
cfg.Metadata().BumpVersion() cfg.Metadata().BumpVersion()
suite.Require().NoError(suite.state.Update(suite.ctx, oldVersion, cfg)) suite.Require().NoError(suite.state.Update(suite.ctx, oldVersion, cfg))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
suite.assertNoResource( retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
resource.NewMetadata(network.ConfigNamespaceName, network.LinkSpecType, network.LayeredID(network.ConfigOperator, network.LinkID(constants.KubeSpanLinkName)), resource.VersionUndefined), suite.assertNoResource(
resource.NewMetadata(
network.ConfigNamespaceName,
network.LinkSpecType,
network.LayeredID(network.ConfigOperator, network.LinkID(constants.KubeSpanLinkName)),
resource.VersionUndefined,
),
),
), ),
)) )
} }
func TestManagerSuite(t *testing.T) { func TestManagerSuite(t *testing.T) {

View File

@ -41,7 +41,7 @@ type AddressConfigSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -73,7 +73,10 @@ func (suite *AddressConfigSuite) assertAddresses(requiredIDs []string, check fun
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.ConfigNamespaceName, network.AddressSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.ConfigNamespaceName, network.AddressSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -103,42 +106,60 @@ func (suite *AddressConfigSuite) TestLoopback() {
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertAddresses([]string{ func() error {
"default/lo/127.0.0.1/8", return suite.assertAddresses(
}, func(r *network.AddressSpec) error { []string{
suite.Assert().Equal("lo", r.TypedSpec().LinkName) "default/lo/127.0.0.1/8",
suite.Assert().Equal(nethelpers.ScopeHost, r.TypedSpec().Scope) }, func(r *network.AddressSpec) error {
suite.Assert().Equal("lo", r.TypedSpec().LinkName)
suite.Assert().Equal(nethelpers.ScopeHost, r.TypedSpec().Scope)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *AddressConfigSuite) TestCmdline() { func (suite *AddressConfigSuite) TestCmdline() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.AddressConfigController{ suite.Require().NoError(
Cmdline: procfs.NewCmdline("ip=172.20.0.2::172.20.0.1:255.255.255.0::eth1:::::"), suite.runtime.RegisterController(
})) &netctrl.AddressConfigController{
Cmdline: procfs.NewCmdline("ip=172.20.0.2::172.20.0.1:255.255.255.0::eth1:::::"),
},
),
)
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertAddresses([]string{ func() error {
"cmdline/eth1/172.20.0.2/24", return suite.assertAddresses(
}, func(r *network.AddressSpec) error { []string{
suite.Assert().Equal("eth1", r.TypedSpec().LinkName) "cmdline/eth1/172.20.0.2/24",
}, func(r *network.AddressSpec) error {
suite.Assert().Equal("eth1", r.TypedSpec().LinkName)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *AddressConfigSuite) TestCmdlineNoNetmask() { func (suite *AddressConfigSuite) TestCmdlineNoNetmask() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.AddressConfigController{ suite.Require().NoError(
Cmdline: procfs.NewCmdline("ip=172.20.0.2::172.20.0.1"), suite.runtime.RegisterController(
})) &netctrl.AddressConfigController{
Cmdline: procfs.NewCmdline("ip=172.20.0.2::172.20.0.1"),
},
),
)
suite.startRuntime() suite.startRuntime()
@ -160,17 +181,22 @@ func (suite *AddressConfigSuite) TestCmdlineNoNetmask() {
suite.Assert().NotEmpty(ifaceName) suite.Assert().NotEmpty(ifaceName)
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertAddresses([]string{ func() error {
fmt.Sprintf("cmdline/%s/172.20.0.2/32", ifaceName), return suite.assertAddresses(
}, func(r *network.AddressSpec) error { []string{
suite.Assert().Equal(ifaceName, r.TypedSpec().LinkName) fmt.Sprintf("cmdline/%s/172.20.0.2/32", ifaceName),
suite.Assert().Equal(network.ConfigCmdline, r.TypedSpec().ConfigLayer) }, func(r *network.AddressSpec) error {
suite.Assert().Equal(ifaceName, r.TypedSpec().LinkName)
suite.Assert().Equal(network.ConfigCmdline, r.TypedSpec().ConfigLayer)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *AddressConfigSuite) TestMachineConfiguration() { func (suite *AddressConfigSuite) TestMachineConfiguration() {
@ -181,78 +207,85 @@ func (suite *AddressConfigSuite) TestMachineConfiguration() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{ ConfigVersion: "v1alpha1",
MachineNetwork: &v1alpha1.NetworkConfig{ MachineConfig: &v1alpha1.MachineConfig{
NetworkInterfaces: []*v1alpha1.Device{ MachineNetwork: &v1alpha1.NetworkConfig{
{ NetworkInterfaces: []*v1alpha1.Device{
DeviceInterface: "eth3", {
DeviceCIDR: "192.168.0.24/28", DeviceInterface: "eth3",
}, DeviceCIDR: "192.168.0.24/28",
{
DeviceIgnore: true,
DeviceInterface: "eth4",
DeviceCIDR: "192.168.0.24/28",
},
{
DeviceInterface: "eth2",
DeviceCIDR: "2001:470:6d:30e:8ed2:b60c:9d2f:803a/64",
},
{
DeviceInterface: "eth5",
DeviceCIDR: "10.5.0.7",
},
{
DeviceInterface: "eth6",
DeviceAddresses: []string{
"10.5.0.8",
"2001:470:6d:30e:8ed2:b60c:9d2f:803b/64",
}, },
}, {
{ DeviceIgnore: true,
DeviceInterface: "eth0", DeviceInterface: "eth4",
DeviceVlans: []*v1alpha1.Vlan{ DeviceCIDR: "192.168.0.24/28",
{ },
VlanID: 24, {
VlanCIDR: "10.0.0.1/8", DeviceInterface: "eth2",
DeviceCIDR: "2001:470:6d:30e:8ed2:b60c:9d2f:803a/64",
},
{
DeviceInterface: "eth5",
DeviceCIDR: "10.5.0.7",
},
{
DeviceInterface: "eth6",
DeviceAddresses: []string{
"10.5.0.8",
"2001:470:6d:30e:8ed2:b60c:9d2f:803b/64",
}, },
{ },
VlanID: 25, {
VlanAddresses: []string{ DeviceInterface: "eth0",
"11.0.0.1/8", DeviceVlans: []*v1alpha1.Vlan{
{
VlanID: 24,
VlanCIDR: "10.0.0.1/8",
},
{
VlanID: 25,
VlanAddresses: []string{
"11.0.0.1/8",
},
}, },
}, },
}, },
}, },
}, },
}, },
}, ClusterConfig: &v1alpha1.ClusterConfig{
ClusterConfig: &v1alpha1.ClusterConfig{ ControlPlane: &v1alpha1.ControlPlaneConfig{
ControlPlane: &v1alpha1.ControlPlaneConfig{ Endpoint: &v1alpha1.Endpoint{
Endpoint: &v1alpha1.Endpoint{ URL: u,
URL: u, },
}, },
}, },
}, },
}) )
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertAddresses([]string{ func() error {
"configuration/eth2/2001:470:6d:30e:8ed2:b60c:9d2f:803a/64", return suite.assertAddresses(
"configuration/eth3/192.168.0.24/28", []string{
"configuration/eth5/10.5.0.7/32", "configuration/eth2/2001:470:6d:30e:8ed2:b60c:9d2f:803a/64",
"configuration/eth6/10.5.0.8/32", "configuration/eth3/192.168.0.24/28",
"configuration/eth6/2001:470:6d:30e:8ed2:b60c:9d2f:803b/64", "configuration/eth5/10.5.0.7/32",
"configuration/eth0.24/10.0.0.1/8", "configuration/eth6/10.5.0.8/32",
"configuration/eth0.25/11.0.0.1/8", "configuration/eth6/2001:470:6d:30e:8ed2:b60c:9d2f:803b/64",
}, func(r *network.AddressSpec) error { "configuration/eth0.24/10.0.0.1/8",
return nil "configuration/eth0.25/11.0.0.1/8",
}) }, func(r *network.AddressSpec) error {
})) return nil
},
)
},
),
)
} }
func (suite *AddressConfigSuite) TearDownTest() { func (suite *AddressConfigSuite) TearDownTest() {
@ -263,10 +296,14 @@ func (suite *AddressConfigSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ err := suite.state.Create(
ConfigVersion: "v1alpha1", context.Background(), config.NewMachineConfig(
MachineConfig: &v1alpha1.MachineConfig{}, &v1alpha1.Config{
})) ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{},
},
),
)
if state.IsConflictError(err) { if state.IsConflictError(err) {
err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata())
} }

View File

@ -49,7 +49,7 @@ type AddressEventsSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -67,9 +67,13 @@ func (suite *AddressEventsSuite) SetupTest() {
suite.runtime, err = runtime.NewRuntime(suite.state, logging.Wrap(log.Writer())) suite.runtime, err = runtime.NewRuntime(suite.state, logging.Wrap(log.Writer()))
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Require().NoError(suite.runtime.RegisterController(&network.AddressEventController{ suite.Require().NoError(
V1Alpha1Events: suite.events, suite.runtime.RegisterController(
})) &network.AddressEventController{
V1Alpha1Events: suite.events,
},
),
)
suite.startRuntime() suite.startRuntime()
} }
@ -92,38 +96,42 @@ func (suite *AddressEventsSuite) TestReconcile() {
var event *machine.AddressEvent var event *machine.AddressEvent
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
suite.events.messagesMu.Lock() func() error {
defer suite.events.messagesMu.Unlock() suite.events.messagesMu.Lock()
defer suite.events.messagesMu.Unlock()
if len(suite.events.messages) == 0 { if len(suite.events.messages) == 0 {
return retry.ExpectedError(fmt.Errorf("no events created")) return retry.ExpectedError(fmt.Errorf("no events created"))
} }
m := suite.events.messages[len(suite.events.messages)-1] m := suite.events.messages[len(suite.events.messages)-1]
var ok bool var ok bool
event, ok = m.(*machine.AddressEvent) event, ok = m.(*machine.AddressEvent)
if !ok { if !ok {
return fmt.Errorf("not an endpoint event") return fmt.Errorf("not an endpoint event")
} }
if event.Hostname == "" { if event.Hostname == "" {
return retry.ExpectedError(fmt.Errorf("expected hostname to be set")) return retry.ExpectedError(fmt.Errorf("expected hostname to be set"))
} }
return nil return nil
}, },
)) ),
)
suite.Require().Equal(hostname.TypedSpec().Hostname, event.Hostname) suite.Require().Equal(hostname.TypedSpec().Hostname, event.Hostname)
suite.Require().Empty(event.Addresses) suite.Require().Empty(event.Addresses)
nodeAddress := networkresource.NewNodeAddress(networkresource.NamespaceName, networkresource.FilteredNodeAddressID( nodeAddress := networkresource.NewNodeAddress(
networkresource.NodeAddressCurrentID, networkresource.NamespaceName, networkresource.FilteredNodeAddressID(
k8s.NodeAddressFilterNoK8s), networkresource.NodeAddressCurrentID,
k8s.NodeAddressFilterNoK8s,
),
) )
addrs := []string{ addrs := []string{
@ -139,31 +147,33 @@ func (suite *AddressEventsSuite) TestReconcile() {
suite.Require().NoError(suite.state.Create(suite.ctx, nodeAddress)) suite.Require().NoError(suite.state.Create(suite.ctx, nodeAddress))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
suite.events.messagesMu.Lock() func() error {
defer suite.events.messagesMu.Unlock() suite.events.messagesMu.Lock()
defer suite.events.messagesMu.Unlock()
if len(suite.events.messages) == 0 { if len(suite.events.messages) == 0 {
return retry.ExpectedError(fmt.Errorf("no events created")) return retry.ExpectedError(fmt.Errorf("no events created"))
} }
m := suite.events.messages[len(suite.events.messages)-1] m := suite.events.messages[len(suite.events.messages)-1]
var ok bool var ok bool
event, ok = m.(*machine.AddressEvent) event, ok = m.(*machine.AddressEvent)
if !ok { if !ok {
return fmt.Errorf("not an address event") return fmt.Errorf("not an address event")
} }
if len(event.Addresses) == 0 { if len(event.Addresses) == 0 {
return retry.ExpectedError(fmt.Errorf("expected addresses to be set")) return retry.ExpectedError(fmt.Errorf("expected addresses to be set"))
} }
return nil return nil
}, },
)) ),
)
suite.Require().Equal(addrs, event.Addresses) suite.Require().Equal(addrs, event.Addresses)
} }

View File

@ -37,7 +37,7 @@ type AddressMergeSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -73,7 +73,10 @@ func (suite *AddressMergeSuite) assertAddresses(requiredIDs []string, check func
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.NamespaceName, network.AddressSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.AddressSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -99,7 +102,10 @@ func (suite *AddressMergeSuite) assertAddresses(requiredIDs []string, check func
} }
func (suite *AddressMergeSuite) assertNoAddress(id string) error { func (suite *AddressMergeSuite) assertNoAddress(id string) error {
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.NamespaceName, network.AddressSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.AddressSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -154,41 +160,54 @@ func (suite *AddressMergeSuite) TestMerge() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertAddresses([]string{ func() error {
"lo/127.0.0.1/8", return suite.assertAddresses(
"eth0/10.0.0.1/8", []string{
"eth0/10.0.0.35/32", "lo/127.0.0.1/8",
}, func(r *network.AddressSpec) error { "eth0/10.0.0.1/8",
switch r.Metadata().ID() { "eth0/10.0.0.35/32",
case "lo/127.0.0.1/8": }, func(r *network.AddressSpec) error {
suite.Assert().Equal(*loopback.TypedSpec(), *r.TypedSpec()) switch r.Metadata().ID() {
case "eth0/10.0.0.1/8": case "lo/127.0.0.1/8":
suite.Assert().Equal(*override.TypedSpec(), *r.TypedSpec()) suite.Assert().Equal(*loopback.TypedSpec(), *r.TypedSpec())
case "eth0/10.0.0.35/32": case "eth0/10.0.0.1/8":
suite.Assert().Equal(*static.TypedSpec(), *r.TypedSpec()) suite.Assert().Equal(*override.TypedSpec(), *r.TypedSpec())
} case "eth0/10.0.0.35/32":
suite.Assert().Equal(*static.TypedSpec(), *r.TypedSpec())
}
return nil return nil
}) },
})) )
},
),
)
suite.Require().NoError(suite.state.Destroy(suite.ctx, static.Metadata())) suite.Require().NoError(suite.state.Destroy(suite.ctx, static.Metadata()))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertAddresses([]string{ func() error {
"lo/127.0.0.1/8", return suite.assertAddresses(
"eth0/10.0.0.35/32", []string{
}, func(r *network.AddressSpec) error { "lo/127.0.0.1/8",
return nil "eth0/10.0.0.35/32",
}) }, func(r *network.AddressSpec) error {
})) return nil
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( },
func() error { )
return suite.assertNoAddress("eth0/10.0.0.35/32") },
})) ),
)
suite.Assert().NoError(
retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
func() error {
return suite.assertNoAddress("eth0/10.0.0.35/32")
},
),
)
} }
//nolint:gocyclo //nolint:gocyclo
@ -236,50 +255,75 @@ func (suite *AddressMergeSuite) TestMergeFlapping() {
eg.Go(flipflop(0)) eg.Go(flipflop(0))
eg.Go(flipflop(1)) eg.Go(flipflop(1))
eg.Go(func() error { eg.Go(
// add/remove finalizer to the merged resource func() error {
for i := 0; i < 1000; i++ { // add/remove finalizer to the merged resource
if err := suite.state.AddFinalizer(suite.ctx, resource.NewMetadata(network.NamespaceName, network.AddressSpecType, "eth0/10.0.0.1/8", resource.VersionUndefined), "foo"); err != nil { for i := 0; i < 1000; i++ {
if !state.IsNotFoundError(err) { if err := suite.state.AddFinalizer(
return err suite.ctx,
resource.NewMetadata(
network.NamespaceName,
network.AddressSpecType,
"eth0/10.0.0.1/8",
resource.VersionUndefined,
),
"foo",
); err != nil {
if !state.IsNotFoundError(err) {
return err
}
continue
} else {
suite.T().Log("finalizer added")
} }
continue time.Sleep(10 * time.Millisecond)
} else {
suite.T().Log("finalizer added")
}
time.Sleep(10 * time.Millisecond) if err := suite.state.RemoveFinalizer(
suite.ctx,
if err := suite.state.RemoveFinalizer(suite.ctx, resource.NewMetadata(network.NamespaceName, network.AddressSpecType, "eth0/10.0.0.1/8", resource.VersionUndefined), "foo"); err != nil { resource.NewMetadata(
if err != nil && !state.IsNotFoundError(err) { network.NamespaceName,
return err network.AddressSpecType,
"eth0/10.0.0.1/8",
resource.VersionUndefined,
),
"foo",
); err != nil {
if err != nil && !state.IsNotFoundError(err) {
return err
}
} }
} }
}
return nil return nil
}) },
)
suite.Require().NoError(eg.Wait()) suite.Require().NoError(eg.Wait())
suite.Assert().NoError(retry.Constant(15*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(15*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertAddresses([]string{ func() error {
"eth0/10.0.0.1/8", return suite.assertAddresses(
}, func(r *network.AddressSpec) error { []string{
if r.Metadata().Phase() != resource.PhaseRunning { "eth0/10.0.0.1/8",
return retry.ExpectedErrorf("resource phase is %s", r.Metadata().Phase()) }, func(r *network.AddressSpec) error {
} if r.Metadata().Phase() != resource.PhaseRunning {
return retry.ExpectedErrorf("resource phase is %s", r.Metadata().Phase())
}
if *override.TypedSpec() != *r.TypedSpec() { if *override.TypedSpec() != *r.TypedSpec() {
// using retry here, as it might not be reconciled immediately // using retry here, as it might not be reconciled immediately
return retry.ExpectedError(fmt.Errorf("not equal yet")) return retry.ExpectedError(fmt.Errorf("not equal yet"))
} }
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *AddressMergeSuite) TearDownTest() { func (suite *AddressMergeSuite) TearDownTest() {
@ -290,7 +334,12 @@ func (suite *AddressMergeSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewAddressSpec(network.ConfigNamespaceName, "bar"))) suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewAddressSpec(network.ConfigNamespaceName, "bar"),
),
)
} }
func TestAddressMergeSuite(t *testing.T) { func TestAddressMergeSuite(t *testing.T) {

View File

@ -146,7 +146,8 @@ func findAddress(addrs []rtnetlink.AddressMessage, linkIndex uint32, ipPrefix ne
//nolint:gocyclo //nolint:gocyclo
func (ctrl *AddressSpecController) syncAddress(ctx context.Context, r controller.Runtime, logger *zap.Logger, conn *rtnetlink.Conn, func (ctrl *AddressSpecController) syncAddress(ctx context.Context, r controller.Runtime, logger *zap.Logger, conn *rtnetlink.Conn,
links []rtnetlink.LinkMessage, addrs []rtnetlink.AddressMessage, address *network.AddressSpec) error { links []rtnetlink.LinkMessage, addrs []rtnetlink.AddressMessage, address *network.AddressSpec,
) error {
linkIndex := resolveLinkName(links, address.TypedSpec().LinkName) linkIndex := resolveLinkName(links, address.TypedSpec().LinkName)
switch address.Metadata().Phase() { switch address.Metadata().Phase() {

View File

@ -40,7 +40,7 @@ type AddressSpecSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -144,10 +144,13 @@ func (suite *AddressSpecSuite) TestLoopback() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertLinkAddress("lo", "127.11.0.1/32") func() error {
})) return suite.assertLinkAddress("lo", "127.11.0.1/32")
},
),
)
// teardown the address // teardown the address
for { for {
@ -191,26 +194,33 @@ func (suite *AddressSpecSuite) TestDummy() {
} }
// create dummy interface // create dummy interface
suite.Require().NoError(conn.Link.New(&rtnetlink.LinkMessage{ suite.Require().NoError(
Type: unix.ARPHRD_ETHER, conn.Link.New(
Attributes: &rtnetlink.LinkAttributes{ &rtnetlink.LinkMessage{
Name: dummyInterface, Type: unix.ARPHRD_ETHER,
MTU: 1400, Attributes: &rtnetlink.LinkAttributes{
Info: &rtnetlink.LinkInfo{ Name: dummyInterface,
Kind: "dummy", MTU: 1400,
Info: &rtnetlink.LinkInfo{
Kind: "dummy",
},
},
}, },
}, ),
})) )
iface, err := net.InterfaceByName(dummyInterface) iface, err := net.InterfaceByName(dummyInterface)
suite.Require().NoError(err) suite.Require().NoError(err)
defer conn.Link.Delete(uint32(iface.Index)) //nolint:errcheck defer conn.Link.Delete(uint32(iface.Index)) //nolint:errcheck
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertLinkAddress(dummyInterface, "10.0.0.1/8") func() error {
})) return suite.assertLinkAddress(dummyInterface, "10.0.0.1/8")
},
),
)
// delete dummy interface, address should be unassigned automatically // delete dummy interface, address should be unassigned automatically
suite.Require().NoError(conn.Link.Delete(uint32(iface.Index))) suite.Require().NoError(conn.Link.Delete(uint32(iface.Index)))
@ -236,7 +246,12 @@ func (suite *AddressSpecSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewAddressSpec(network.NamespaceName, "bar"))) suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewAddressSpec(network.NamespaceName, "bar"),
),
)
} }
func TestAddressSpecSuite(t *testing.T) { func TestAddressSpecSuite(t *testing.T) {

View File

@ -34,7 +34,7 @@ type AddressStatusSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -70,7 +70,10 @@ func (suite *AddressStatusSuite) assertAddresses(requiredIDs []string, check fun
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.NamespaceName, network.AddressStatusType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.AddressStatusType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -96,12 +99,17 @@ func (suite *AddressStatusSuite) assertAddresses(requiredIDs []string, check fun
} }
func (suite *AddressStatusSuite) TestLoopback() { func (suite *AddressStatusSuite) TestLoopback() {
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertAddresses([]string{"lo/127.0.0.1/8"}, func(r *network.AddressStatus) error { func() error {
return nil return suite.assertAddresses(
}) []string{"lo/127.0.0.1/8"}, func(r *network.AddressStatus) error {
})) return nil
},
)
},
),
)
} }
func (suite *AddressStatusSuite) TearDownTest() { func (suite *AddressStatusSuite) TearDownTest() {

View File

@ -39,7 +39,7 @@ type EtcFileConfigSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
cfg *config.MachineConfig cfg *config.MachineConfig
@ -65,30 +65,32 @@ func (suite *EtcFileConfigSuite) SetupTest() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
suite.cfg = config.NewMachineConfig(&v1alpha1.Config{ suite.cfg = config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{ ConfigVersion: "v1alpha1",
MachineNetwork: &v1alpha1.NetworkConfig{ MachineConfig: &v1alpha1.MachineConfig{
ExtraHostEntries: []*v1alpha1.ExtraHost{ MachineNetwork: &v1alpha1.NetworkConfig{
{ ExtraHostEntries: []*v1alpha1.ExtraHost{
HostIP: "10.0.0.1", {
HostAliases: []string{"a", "b"}, HostIP: "10.0.0.1",
HostAliases: []string{"a", "b"},
},
{
HostIP: "10.0.0.2",
HostAliases: []string{"c", "d"},
},
}, },
{ },
HostIP: "10.0.0.2", },
HostAliases: []string{"c", "d"}, ClusterConfig: &v1alpha1.ClusterConfig{
ControlPlane: &v1alpha1.ControlPlaneConfig{
Endpoint: &v1alpha1.Endpoint{
URL: u,
}, },
}, },
}, },
}, },
ClusterConfig: &v1alpha1.ClusterConfig{ )
ControlPlane: &v1alpha1.ControlPlaneConfig{
Endpoint: &v1alpha1.Endpoint{
URL: u,
},
},
},
})
suite.defaultAddress = network.NewNodeAddress(network.NamespaceName, network.NodeAddressDefaultID) suite.defaultAddress = network.NewNodeAddress(network.NamespaceName, network.NodeAddressDefaultID)
suite.defaultAddress.TypedSpec().Addresses = []netaddr.IPPrefix{netaddr.MustParseIPPrefix("33.11.22.44/32")} suite.defaultAddress.TypedSpec().Addresses = []netaddr.IPPrefix{netaddr.MustParseIPPrefix("33.11.22.44/32")}
@ -98,7 +100,12 @@ func (suite *EtcFileConfigSuite) SetupTest() {
suite.hostnameStatus.TypedSpec().Domainname = "example.com" suite.hostnameStatus.TypedSpec().Domainname = "example.com"
suite.resolverStatus = network.NewResolverStatus(network.NamespaceName, network.ResolverID) suite.resolverStatus = network.NewResolverStatus(network.NamespaceName, network.ResolverID)
suite.resolverStatus.TypedSpec().DNSServers = []netaddr.IP{netaddr.MustParseIP("1.1.1.1"), netaddr.MustParseIP("2.2.2.2"), netaddr.MustParseIP("3.3.3.3"), netaddr.MustParseIP("4.4.4.4")} suite.resolverStatus.TypedSpec().DNSServers = []netaddr.IP{
netaddr.MustParseIP("1.1.1.1"),
netaddr.MustParseIP("2.2.2.2"),
netaddr.MustParseIP("3.3.3.3"),
netaddr.MustParseIP("4.4.4.4"),
}
} }
func (suite *EtcFileConfigSuite) startRuntime() { func (suite *EtcFileConfigSuite) startRuntime() {
@ -118,7 +125,10 @@ func (suite *EtcFileConfigSuite) assertEtcFiles(requiredIDs []string, check func
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(files.NamespaceName, files.EtcFileSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(files.NamespaceName, files.EtcFileSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -144,7 +154,10 @@ func (suite *EtcFileConfigSuite) assertEtcFiles(requiredIDs []string, check func
} }
func (suite *EtcFileConfigSuite) assertNoEtcFile(id string) error { func (suite *EtcFileConfigSuite) assertNoEtcFile(id string) error {
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(files.NamespaceName, files.EtcFileSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(files.NamespaceName, files.EtcFileSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -177,41 +190,50 @@ func (suite *EtcFileConfigSuite) testFiles(resources []resource.Resource, resolv
unexpectedIds = append(unexpectedIds, "hosts") unexpectedIds = append(unexpectedIds, "hosts")
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertEtcFiles( func() error {
expectedIds, return suite.assertEtcFiles(
func(r *files.EtcFileSpec) error { expectedIds,
switch r.Metadata().ID() { func(r *files.EtcFileSpec) error {
case "hosts": switch r.Metadata().ID() {
suite.Assert().Equal(hosts, string(r.TypedSpec().Contents)) case "hosts":
case "resolv.conf": suite.Assert().Equal(hosts, string(r.TypedSpec().Contents))
suite.Assert().Equal(resolvConf, string(r.TypedSpec().Contents)) case "resolv.conf":
} suite.Assert().Equal(resolvConf, string(r.TypedSpec().Contents))
}
return nil return nil
}) },
})) )
},
),
)
for _, id := range unexpectedIds { for _, id := range unexpectedIds {
id := id id := id
suite.Assert().NoError(retry.Constant(1*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(1*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNoEtcFile(id) func() error {
})) return suite.assertNoEtcFile(id)
},
),
)
} }
} }
func (suite *EtcFileConfigSuite) TestComplete() { func (suite *EtcFileConfigSuite) TestComplete() {
suite.testFiles([]resource.Resource{suite.cfg, suite.defaultAddress, suite.hostnameStatus, suite.resolverStatus}, suite.testFiles(
[]resource.Resource{suite.cfg, suite.defaultAddress, suite.hostnameStatus, suite.resolverStatus},
"nameserver 1.1.1.1\nnameserver 2.2.2.2\nnameserver 3.3.3.3\n\nsearch example.com\n", "nameserver 1.1.1.1\nnameserver 2.2.2.2\nnameserver 3.3.3.3\n\nsearch example.com\n",
"127.0.0.1 localhost\n33.11.22.44 foo.example.com foo\n::1 localhost ip6-localhost ip6-loopback\nff02::1 ip6-allnodes\nff02::2 ip6-allrouters\n\n10.0.0.1 a b \n10.0.0.2 c d ", //nolint:lll "127.0.0.1 localhost\n33.11.22.44 foo.example.com foo\n::1 localhost ip6-localhost ip6-loopback\nff02::1 ip6-allnodes\nff02::2 ip6-allrouters\n\n10.0.0.1 a b \n10.0.0.2 c d ", //nolint:lll
) )
} }
func (suite *EtcFileConfigSuite) TestNoExtraHosts() { func (suite *EtcFileConfigSuite) TestNoExtraHosts() {
suite.testFiles([]resource.Resource{suite.defaultAddress, suite.hostnameStatus, suite.resolverStatus}, suite.testFiles(
[]resource.Resource{suite.defaultAddress, suite.hostnameStatus, suite.resolverStatus},
"nameserver 1.1.1.1\nnameserver 2.2.2.2\nnameserver 3.3.3.3\n\nsearch example.com\n", "nameserver 1.1.1.1\nnameserver 2.2.2.2\nnameserver 3.3.3.3\n\nsearch example.com\n",
"127.0.0.1 localhost\n33.11.22.44 foo.example.com foo\n::1 localhost ip6-localhost ip6-loopback\nff02::1 ip6-allnodes\nff02::2 ip6-allrouters", "127.0.0.1 localhost\n33.11.22.44 foo.example.com foo\n::1 localhost ip6-localhost ip6-loopback\nff02::1 ip6-allnodes\nff02::2 ip6-allrouters",
) )
@ -220,21 +242,24 @@ func (suite *EtcFileConfigSuite) TestNoExtraHosts() {
func (suite *EtcFileConfigSuite) TestNoDomainname() { func (suite *EtcFileConfigSuite) TestNoDomainname() {
suite.hostnameStatus.TypedSpec().Domainname = "" suite.hostnameStatus.TypedSpec().Domainname = ""
suite.testFiles([]resource.Resource{suite.defaultAddress, suite.hostnameStatus, suite.resolverStatus}, suite.testFiles(
[]resource.Resource{suite.defaultAddress, suite.hostnameStatus, suite.resolverStatus},
"nameserver 1.1.1.1\nnameserver 2.2.2.2\nnameserver 3.3.3.3\n", "nameserver 1.1.1.1\nnameserver 2.2.2.2\nnameserver 3.3.3.3\n",
"127.0.0.1 localhost\n33.11.22.44 foo \n::1 localhost ip6-localhost ip6-loopback\nff02::1 ip6-allnodes\nff02::2 ip6-allrouters", "127.0.0.1 localhost\n33.11.22.44 foo \n::1 localhost ip6-localhost ip6-loopback\nff02::1 ip6-allnodes\nff02::2 ip6-allrouters",
) )
} }
func (suite *EtcFileConfigSuite) TestOnlyResolvers() { func (suite *EtcFileConfigSuite) TestOnlyResolvers() {
suite.testFiles([]resource.Resource{suite.resolverStatus}, suite.testFiles(
[]resource.Resource{suite.resolverStatus},
"nameserver 1.1.1.1\nnameserver 2.2.2.2\nnameserver 3.3.3.3\n", "nameserver 1.1.1.1\nnameserver 2.2.2.2\nnameserver 3.3.3.3\n",
"", "",
) )
} }
func (suite *EtcFileConfigSuite) TestOnlyHostname() { func (suite *EtcFileConfigSuite) TestOnlyHostname() {
suite.testFiles([]resource.Resource{suite.defaultAddress, suite.hostnameStatus}, suite.testFiles(
[]resource.Resource{suite.defaultAddress, suite.hostnameStatus},
"", "",
"127.0.0.1 localhost\n33.11.22.44 foo.example.com foo\n::1 localhost ip6-localhost ip6-loopback\nff02::1 ip6-allnodes\nff02::2 ip6-allrouters", "127.0.0.1 localhost\n33.11.22.44 foo.example.com foo\n::1 localhost ip6-localhost ip6-loopback\nff02::1 ip6-allnodes\nff02::2 ip6-allrouters",
) )
@ -248,19 +273,38 @@ func (suite *EtcFileConfigSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ err := suite.state.Create(
ConfigVersion: "v1alpha1", context.Background(), config.NewMachineConfig(
MachineConfig: &v1alpha1.MachineConfig{}, &v1alpha1.Config{
})) ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{},
},
),
)
if state.IsConflictError(err) { if state.IsConflictError(err) {
err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata())
} }
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewHostnameStatus(network.NamespaceName, "bar"))) suite.Assert().NoError(
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewResolverStatus(network.NamespaceName, "bar"))) suite.state.Create(
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewNodeAddress(network.NamespaceName, "bar"))) context.Background(),
network.NewHostnameStatus(network.NamespaceName, "bar"),
),
)
suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewResolverStatus(network.NamespaceName, "bar"),
),
)
suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewNodeAddress(network.NamespaceName, "bar"),
),
)
} }
func TestEtcFileConfigSuite(t *testing.T) { func TestEtcFileConfigSuite(t *testing.T) {

View File

@ -36,7 +36,7 @@ type HardwareAddrSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -72,7 +72,10 @@ func (suite *HardwareAddrSuite) assertHWAddr(requiredIDs []string, check func(*n
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.NamespaceName, network.HardwareAddrType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.HardwareAddrType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -98,7 +101,10 @@ func (suite *HardwareAddrSuite) assertHWAddr(requiredIDs []string, check func(*n
} }
func (suite *HardwareAddrSuite) assertNoHWAddr(id string) error { func (suite *HardwareAddrSuite) assertNoHWAddr(id string) error {
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.NamespaceName, network.HardwareAddrType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.HardwareAddrType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -136,37 +142,50 @@ func (suite *HardwareAddrSuite) TestFirst() {
suite.Require().NoError(suite.state.Create(suite.ctx, bond0)) suite.Require().NoError(suite.state.Create(suite.ctx, bond0))
suite.Require().NoError(suite.state.Create(suite.ctx, eth1)) suite.Require().NoError(suite.state.Create(suite.ctx, eth1))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertHWAddr([]string{network.FirstHardwareAddr}, func(r *network.HardwareAddr) error { func() error {
if r.TypedSpec().Name != eth1.Metadata().ID() && net.HardwareAddr(r.TypedSpec().HardwareAddr).String() != "6a:2b:bd:b2:fc:e0" { return suite.assertHWAddr(
return retry.ExpectedErrorf("should be eth1") []string{network.FirstHardwareAddr}, func(r *network.HardwareAddr) error {
} if r.TypedSpec().Name != eth1.Metadata().ID() && net.HardwareAddr(r.TypedSpec().HardwareAddr).String() != "6a:2b:bd:b2:fc:e0" {
return retry.ExpectedErrorf("should be eth1")
}
return nil return nil
}) },
})) )
},
),
)
suite.Require().NoError(suite.state.Create(suite.ctx, eth0)) suite.Require().NoError(suite.state.Create(suite.ctx, eth0))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertHWAddr([]string{network.FirstHardwareAddr}, func(r *network.HardwareAddr) error { func() error {
if r.TypedSpec().Name != eth0.Metadata().ID() && net.HardwareAddr(r.TypedSpec().HardwareAddr).String() != "56:a0:a0:87:1c:fa" { return suite.assertHWAddr(
return retry.ExpectedErrorf("should be eth0") []string{network.FirstHardwareAddr}, func(r *network.HardwareAddr) error {
} if r.TypedSpec().Name != eth0.Metadata().ID() && net.HardwareAddr(r.TypedSpec().HardwareAddr).String() != "56:a0:a0:87:1c:fa" {
return retry.ExpectedErrorf("should be eth0")
}
return nil return nil
}) },
})) )
},
),
)
suite.Require().NoError(suite.state.Destroy(suite.ctx, eth0.Metadata())) suite.Require().NoError(suite.state.Destroy(suite.ctx, eth0.Metadata()))
suite.Require().NoError(suite.state.Destroy(suite.ctx, eth1.Metadata())) suite.Require().NoError(suite.state.Destroy(suite.ctx, eth1.Metadata()))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNoHWAddr(network.FirstHardwareAddr) func() error {
})) return suite.assertNoHWAddr(network.FirstHardwareAddr)
},
),
)
} }
func (suite *HardwareAddrSuite) TearDownTest() { func (suite *HardwareAddrSuite) TearDownTest() {
@ -177,7 +196,12 @@ func (suite *HardwareAddrSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewLinkStatus(network.NamespaceName, "bar"))) suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewLinkStatus(network.NamespaceName, "bar"),
),
)
} }
func TestHardwareAddrSuite(t *testing.T) { func TestHardwareAddrSuite(t *testing.T) {

View File

@ -40,7 +40,7 @@ type HostnameConfigSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -72,7 +72,10 @@ func (suite *HostnameConfigSuite) assertHostnames(requiredIDs []string, check fu
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.ConfigNamespaceName, network.HostnameSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.ConfigNamespaceName, network.HostnameSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -98,7 +101,10 @@ func (suite *HostnameConfigSuite) assertHostnames(requiredIDs []string, check fu
} }
func (suite *HostnameConfigSuite) assertNoHostname(id string) error { func (suite *HostnameConfigSuite) assertNoHostname(id string) error {
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.ConfigNamespaceName, network.HostnameSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.ConfigNamespaceName, network.HostnameSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -122,39 +128,53 @@ func (suite *HostnameConfigSuite) TestDefaults() {
suite.Require().NoError(suite.state.Create(suite.ctx, defaultAddress)) suite.Require().NoError(suite.state.Create(suite.ctx, defaultAddress))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertHostnames([]string{ func() error {
"default/hostname", return suite.assertHostnames(
}, func(r *network.HostnameSpec) error { []string{
suite.Assert().Equal("talos-33-11-22-44", r.TypedSpec().Hostname) "default/hostname",
suite.Assert().Equal("", r.TypedSpec().Domainname) }, func(r *network.HostnameSpec) error {
suite.Assert().Equal(network.ConfigDefault, r.TypedSpec().ConfigLayer) suite.Assert().Equal("talos-33-11-22-44", r.TypedSpec().Hostname)
suite.Assert().Equal("", r.TypedSpec().Domainname)
suite.Assert().Equal(network.ConfigDefault, r.TypedSpec().ConfigLayer)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *HostnameConfigSuite) TestCmdline() { func (suite *HostnameConfigSuite) TestCmdline() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.HostnameConfigController{ suite.Require().NoError(
Cmdline: procfs.NewCmdline("ip=172.20.0.2:172.21.0.1:172.20.0.1:255.255.255.0:master1.domain.tld:eth1::10.0.0.1:10.0.0.2:10.0.0.1"), suite.runtime.RegisterController(
})) &netctrl.HostnameConfigController{
Cmdline: procfs.NewCmdline("ip=172.20.0.2:172.21.0.1:172.20.0.1:255.255.255.0:master1.domain.tld:eth1::10.0.0.1:10.0.0.2:10.0.0.1"),
},
),
)
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertHostnames([]string{ func() error {
"cmdline/hostname", return suite.assertHostnames(
}, func(r *network.HostnameSpec) error { []string{
suite.Assert().Equal("master1", r.TypedSpec().Hostname) "cmdline/hostname",
suite.Assert().Equal("domain.tld", r.TypedSpec().Domainname) }, func(r *network.HostnameSpec) error {
suite.Assert().Equal(network.ConfigCmdline, r.TypedSpec().ConfigLayer) suite.Assert().Equal("master1", r.TypedSpec().Hostname)
suite.Assert().Equal("domain.tld", r.TypedSpec().Domainname)
suite.Assert().Equal(network.ConfigCmdline, r.TypedSpec().ConfigLayer)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *HostnameConfigSuite) TestMachineConfiguration() { func (suite *HostnameConfigSuite) TestMachineConfiguration() {
@ -165,48 +185,63 @@ func (suite *HostnameConfigSuite) TestMachineConfiguration() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{ ConfigVersion: "v1alpha1",
MachineNetwork: &v1alpha1.NetworkConfig{ MachineConfig: &v1alpha1.MachineConfig{
NetworkHostname: "foo", MachineNetwork: &v1alpha1.NetworkConfig{
NetworkHostname: "foo",
},
}, },
}, ClusterConfig: &v1alpha1.ClusterConfig{
ClusterConfig: &v1alpha1.ClusterConfig{ ControlPlane: &v1alpha1.ControlPlaneConfig{
ControlPlane: &v1alpha1.ControlPlaneConfig{ Endpoint: &v1alpha1.Endpoint{
Endpoint: &v1alpha1.Endpoint{ URL: u,
URL: u, },
}, },
}, },
}, },
}) )
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertHostnames([]string{ func() error {
"configuration/hostname", return suite.assertHostnames(
}, func(r *network.HostnameSpec) error { []string{
suite.Assert().Equal("foo", r.TypedSpec().Hostname) "configuration/hostname",
suite.Assert().Equal("", r.TypedSpec().Domainname) }, func(r *network.HostnameSpec) error {
suite.Assert().Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer) suite.Assert().Equal("foo", r.TypedSpec().Hostname)
suite.Assert().Equal("", r.TypedSpec().Domainname)
suite.Assert().Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer)
return nil return nil
}) },
})) )
},
),
)
_, err = suite.state.UpdateWithConflicts(suite.ctx, cfg.Metadata(), func(r resource.Resource) error { _, err = suite.state.UpdateWithConflicts(
r.(*config.MachineConfig).Config().(*v1alpha1.Config).MachineConfig.MachineNetwork.NetworkHostname = strings.Repeat("a", 128) suite.ctx, cfg.Metadata(), func(r resource.Resource) error {
r.(*config.MachineConfig).Config().(*v1alpha1.Config).MachineConfig.MachineNetwork.NetworkHostname = strings.Repeat(
"a",
128,
)
return nil return nil
}) },
)
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNoHostname("configuration/hostname") func() error {
})) return suite.assertNoHostname("configuration/hostname")
},
),
)
} }
func (suite *HostnameConfigSuite) TearDownTest() { func (suite *HostnameConfigSuite) TearDownTest() {
@ -217,17 +252,26 @@ func (suite *HostnameConfigSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ err := suite.state.Create(
ConfigVersion: "v1alpha1", context.Background(), config.NewMachineConfig(
MachineConfig: &v1alpha1.MachineConfig{}, &v1alpha1.Config{
})) ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{},
},
),
)
if state.IsConflictError(err) { if state.IsConflictError(err) {
err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata())
} }
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewNodeAddress(network.NamespaceName, "bar"))) suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewNodeAddress(network.NamespaceName, "bar"),
),
)
} }
func TestHostnameConfigSuite(t *testing.T) { func TestHostnameConfigSuite(t *testing.T) {

View File

@ -34,7 +34,7 @@ type HostnameMergeSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -70,7 +70,10 @@ func (suite *HostnameMergeSuite) assertHostnames(requiredIDs []string, check fun
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.NamespaceName, network.HostnameSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.HostnameSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -126,33 +129,43 @@ func (suite *HostnameMergeSuite) TestMerge() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertHostnames([]string{ func() error {
"hostname", return suite.assertHostnames(
}, func(r *network.HostnameSpec) error { []string{
suite.Assert().Equal("bar.com", r.TypedSpec().FQDN()) "hostname",
suite.Assert().Equal("bar", r.TypedSpec().Hostname) }, func(r *network.HostnameSpec) error {
suite.Assert().Equal("com", r.TypedSpec().Domainname) suite.Assert().Equal("bar.com", r.TypedSpec().FQDN())
suite.Assert().Equal("bar", r.TypedSpec().Hostname)
suite.Assert().Equal("com", r.TypedSpec().Domainname)
return nil return nil
}) },
})) )
},
),
)
suite.Require().NoError(suite.state.Destroy(suite.ctx, static.Metadata())) suite.Require().NoError(suite.state.Destroy(suite.ctx, static.Metadata()))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertHostnames([]string{ func() error {
"hostname", return suite.assertHostnames(
}, func(r *network.HostnameSpec) error { []string{
if r.TypedSpec().FQDN() != "eth-0" { "hostname",
return retry.ExpectedErrorf("unexpected hostname %q", r.TypedSpec().FQDN()) }, func(r *network.HostnameSpec) error {
} if r.TypedSpec().FQDN() != "eth-0" {
return retry.ExpectedErrorf("unexpected hostname %q", r.TypedSpec().FQDN())
}
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *HostnameMergeSuite) TearDownTest() { func (suite *HostnameMergeSuite) TearDownTest() {
@ -163,7 +176,12 @@ func (suite *HostnameMergeSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewHostnameSpec(network.ConfigNamespaceName, "bar"))) suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewHostnameSpec(network.ConfigNamespaceName, "bar"),
),
)
} }
func TestHostnameMergeSuite(t *testing.T) { func TestHostnameMergeSuite(t *testing.T) {

View File

@ -33,7 +33,7 @@ type HostnameSpecSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -47,9 +47,13 @@ func (suite *HostnameSpecSuite) SetupTest() {
suite.runtime, err = runtime.NewRuntime(suite.state, logging.Wrap(log.Writer())) suite.runtime, err = runtime.NewRuntime(suite.state, logging.Wrap(log.Writer()))
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.HostnameSpecController{ suite.Require().NoError(
V1Alpha1Mode: v1alpha1runtime.ModeContainer, // run in container mode to skip _actually_ setting hostname suite.runtime.RegisterController(
})) &netctrl.HostnameSpecController{
V1Alpha1Mode: v1alpha1runtime.ModeContainer, // run in container mode to skip _actually_ setting hostname
},
),
)
suite.startRuntime() suite.startRuntime()
} }
@ -65,7 +69,10 @@ func (suite *HostnameSpecSuite) startRuntime() {
} }
func (suite *HostnameSpecSuite) assertStatus(id string, fqdn string) error { func (suite *HostnameSpecSuite) assertStatus(id string, fqdn string) error {
r, err := suite.state.Get(suite.ctx, resource.NewMetadata(network.NamespaceName, network.HostnameStatusType, id, resource.VersionUndefined)) r, err := suite.state.Get(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.HostnameStatusType, id, resource.VersionUndefined),
)
if err != nil { if err != nil {
if state.IsNotFoundError(err) { if state.IsNotFoundError(err) {
return retry.ExpectedError(err) return retry.ExpectedError(err)
@ -95,10 +102,13 @@ func (suite *HostnameSpecSuite) TestSpec() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertStatus("hostname", "foo.bar") func() error {
})) return suite.assertStatus("hostname", "foo.bar")
},
),
)
} }
func (suite *HostnameSpecSuite) TearDownTest() { func (suite *HostnameSpecSuite) TearDownTest() {
@ -109,7 +119,12 @@ func (suite *HostnameSpecSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewHostnameSpec(network.NamespaceName, "bar"))) suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewHostnameSpec(network.NamespaceName, "bar"),
),
)
} }
func TestHostnameSpecSuite(t *testing.T) { func TestHostnameSpecSuite(t *testing.T) {

View File

@ -40,7 +40,7 @@ type LinkConfigSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -72,7 +72,10 @@ func (suite *LinkConfigSuite) assertLinks(requiredIDs []string, check func(*netw
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.ConfigNamespaceName, network.LinkSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.ConfigNamespaceName, network.LinkSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -104,7 +107,10 @@ func (suite *LinkConfigSuite) assertNoLinks(unexpectedIDs []string) error {
unexpIDs[id] = struct{}{} unexpIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.ConfigNamespaceName, network.LinkSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.ConfigNamespaceName, network.LinkSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -124,41 +130,55 @@ func (suite *LinkConfigSuite) TestLoopback() {
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertLinks([]string{ func() error {
"default/lo", return suite.assertLinks(
}, func(r *network.LinkSpec) error { []string{
suite.Assert().Equal("lo", r.TypedSpec().Name) "default/lo",
suite.Assert().True(r.TypedSpec().Up) }, func(r *network.LinkSpec) error {
suite.Assert().False(r.TypedSpec().Logical) suite.Assert().Equal("lo", r.TypedSpec().Name)
suite.Assert().Equal(network.ConfigDefault, r.TypedSpec().ConfigLayer) suite.Assert().True(r.TypedSpec().Up)
suite.Assert().False(r.TypedSpec().Logical)
suite.Assert().Equal(network.ConfigDefault, r.TypedSpec().ConfigLayer)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *LinkConfigSuite) TestCmdline() { func (suite *LinkConfigSuite) TestCmdline() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.LinkConfigController{ suite.Require().NoError(
Cmdline: procfs.NewCmdline("ip=172.20.0.2::172.20.0.1:255.255.255.0::eth1:::::"), suite.runtime.RegisterController(
})) &netctrl.LinkConfigController{
Cmdline: procfs.NewCmdline("ip=172.20.0.2::172.20.0.1:255.255.255.0::eth1:::::"),
},
),
)
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertLinks([]string{ func() error {
"cmdline/eth1", return suite.assertLinks(
}, func(r *network.LinkSpec) error { []string{
suite.Assert().Equal("eth1", r.TypedSpec().Name) "cmdline/eth1",
suite.Assert().True(r.TypedSpec().Up) }, func(r *network.LinkSpec) error {
suite.Assert().False(r.TypedSpec().Logical) suite.Assert().Equal("eth1", r.TypedSpec().Name)
suite.Assert().Equal(network.ConfigCmdline, r.TypedSpec().ConfigLayer) suite.Assert().True(r.TypedSpec().Up)
suite.Assert().False(r.TypedSpec().Logical)
suite.Assert().Equal(network.ConfigCmdline, r.TypedSpec().ConfigLayer)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *LinkConfigSuite) TestMachineConfiguration() { func (suite *LinkConfigSuite) TestMachineConfiguration() {
@ -169,67 +189,69 @@ func (suite *LinkConfigSuite) TestMachineConfiguration() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{ ConfigVersion: "v1alpha1",
MachineNetwork: &v1alpha1.NetworkConfig{ MachineConfig: &v1alpha1.MachineConfig{
NetworkInterfaces: []*v1alpha1.Device{ MachineNetwork: &v1alpha1.NetworkConfig{
{ NetworkInterfaces: []*v1alpha1.Device{
DeviceInterface: "eth0", {
DeviceVlans: []*v1alpha1.Vlan{ DeviceInterface: "eth0",
{ DeviceVlans: []*v1alpha1.Vlan{
VlanID: 24,
VlanMTU: 1000,
VlanAddresses: []string{
"10.0.0.1/8",
},
},
{
VlanID: 48,
VlanAddresses: []string{
"10.0.0.2/8",
},
},
},
},
{
DeviceInterface: "eth1",
DeviceAddresses: []string{"192.168.0.24/28"},
},
{
DeviceInterface: "eth1",
DeviceMTU: 9001,
},
{
DeviceIgnore: true,
DeviceInterface: "eth2",
DeviceAddresses: []string{"192.168.0.24/28"},
},
{
DeviceInterface: "eth2",
},
{
DeviceInterface: "bond0",
DeviceBond: &v1alpha1.Bond{
BondInterfaces: []string{"eth2", "eth3"},
BondMode: "balance-xor",
},
},
{
DeviceInterface: "dummy0",
DeviceDummy: true,
},
{
DeviceInterface: "wireguard0",
DeviceWireguardConfig: &v1alpha1.DeviceWireguardConfig{
WireguardPrivateKey: "ABC",
WireguardPeers: []*v1alpha1.DeviceWireguardPeer{
{ {
WireguardPublicKey: "DEF", VlanID: 24,
WireguardEndpoint: "10.0.0.1:3000", VlanMTU: 1000,
WireguardAllowedIPs: []string{ VlanAddresses: []string{
"10.2.3.0/24", "10.0.0.1/8",
"10.2.4.0/24", },
},
{
VlanID: 48,
VlanAddresses: []string{
"10.0.0.2/8",
},
},
},
},
{
DeviceInterface: "eth1",
DeviceAddresses: []string{"192.168.0.24/28"},
},
{
DeviceInterface: "eth1",
DeviceMTU: 9001,
},
{
DeviceIgnore: true,
DeviceInterface: "eth2",
DeviceAddresses: []string{"192.168.0.24/28"},
},
{
DeviceInterface: "eth2",
},
{
DeviceInterface: "bond0",
DeviceBond: &v1alpha1.Bond{
BondInterfaces: []string{"eth2", "eth3"},
BondMode: "balance-xor",
},
},
{
DeviceInterface: "dummy0",
DeviceDummy: true,
},
{
DeviceInterface: "wireguard0",
DeviceWireguardConfig: &v1alpha1.DeviceWireguardConfig{
WireguardPrivateKey: "ABC",
WireguardPeers: []*v1alpha1.DeviceWireguardPeer{
{
WireguardPublicKey: "DEF",
WireguardEndpoint: "10.0.0.1:3000",
WireguardAllowedIPs: []string{
"10.2.3.0/24",
"10.2.4.0/24",
},
}, },
}, },
}, },
@ -237,98 +259,109 @@ func (suite *LinkConfigSuite) TestMachineConfiguration() {
}, },
}, },
}, },
}, ClusterConfig: &v1alpha1.ClusterConfig{
ClusterConfig: &v1alpha1.ClusterConfig{ ControlPlane: &v1alpha1.ControlPlaneConfig{
ControlPlane: &v1alpha1.ControlPlaneConfig{ Endpoint: &v1alpha1.Endpoint{
Endpoint: &v1alpha1.Endpoint{ URL: u,
URL: u, },
}, },
}, },
}, },
}) )
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertLinks([]string{ func() error {
"configuration/eth0", return suite.assertLinks(
"configuration/eth0.24", []string{
"configuration/eth0.48", "configuration/eth0",
"configuration/eth1", "configuration/eth0.24",
"configuration/eth2", "configuration/eth0.48",
"configuration/eth3", "configuration/eth1",
"configuration/bond0", "configuration/eth2",
"configuration/dummy0", "configuration/eth3",
"configuration/wireguard0", "configuration/bond0",
}, func(r *network.LinkSpec) error { "configuration/dummy0",
suite.Assert().Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer) "configuration/wireguard0",
}, func(r *network.LinkSpec) error {
suite.Assert().Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer)
switch r.TypedSpec().Name { switch r.TypedSpec().Name {
case "eth0", "eth1": case "eth0", "eth1":
suite.Assert().True(r.TypedSpec().Up) suite.Assert().True(r.TypedSpec().Up)
suite.Assert().False(r.TypedSpec().Logical) suite.Assert().False(r.TypedSpec().Logical)
if r.TypedSpec().Name == "eth0" { if r.TypedSpec().Name == "eth0" {
suite.Assert().EqualValues(0, r.TypedSpec().MTU) suite.Assert().EqualValues(0, r.TypedSpec().MTU)
} else { } else {
suite.Assert().EqualValues(9001, r.TypedSpec().MTU) suite.Assert().EqualValues(9001, r.TypedSpec().MTU)
} }
case "eth0.24", "eth0.48": case "eth0.24", "eth0.48":
suite.Assert().True(r.TypedSpec().Up) suite.Assert().True(r.TypedSpec().Up)
suite.Assert().True(r.TypedSpec().Logical) suite.Assert().True(r.TypedSpec().Logical)
suite.Assert().Equal(nethelpers.LinkEther, r.TypedSpec().Type) suite.Assert().Equal(nethelpers.LinkEther, r.TypedSpec().Type)
suite.Assert().Equal(network.LinkKindVLAN, r.TypedSpec().Kind) suite.Assert().Equal(network.LinkKindVLAN, r.TypedSpec().Kind)
suite.Assert().Equal("eth0", r.TypedSpec().ParentName) suite.Assert().Equal("eth0", r.TypedSpec().ParentName)
suite.Assert().Equal(nethelpers.VLANProtocol8021Q, r.TypedSpec().VLAN.Protocol) suite.Assert().Equal(nethelpers.VLANProtocol8021Q, r.TypedSpec().VLAN.Protocol)
if r.TypedSpec().Name == "eth0.24" { if r.TypedSpec().Name == "eth0.24" {
suite.Assert().EqualValues(24, r.TypedSpec().VLAN.VID) suite.Assert().EqualValues(24, r.TypedSpec().VLAN.VID)
suite.Assert().EqualValues(1000, r.TypedSpec().MTU) suite.Assert().EqualValues(1000, r.TypedSpec().MTU)
} else { } else {
suite.Assert().EqualValues(48, r.TypedSpec().VLAN.VID) suite.Assert().EqualValues(48, r.TypedSpec().VLAN.VID)
suite.Assert().EqualValues(0, r.TypedSpec().MTU) suite.Assert().EqualValues(0, r.TypedSpec().MTU)
} }
case "eth2", "eth3": case "eth2", "eth3":
suite.Assert().True(r.TypedSpec().Up) suite.Assert().True(r.TypedSpec().Up)
suite.Assert().False(r.TypedSpec().Logical) suite.Assert().False(r.TypedSpec().Logical)
suite.Assert().Equal("bond0", r.TypedSpec().MasterName) suite.Assert().Equal("bond0", r.TypedSpec().MasterName)
case "bond0": case "bond0":
suite.Assert().True(r.TypedSpec().Up) suite.Assert().True(r.TypedSpec().Up)
suite.Assert().True(r.TypedSpec().Logical) suite.Assert().True(r.TypedSpec().Logical)
suite.Assert().Equal(nethelpers.LinkEther, r.TypedSpec().Type) suite.Assert().Equal(nethelpers.LinkEther, r.TypedSpec().Type)
suite.Assert().Equal(network.LinkKindBond, r.TypedSpec().Kind) suite.Assert().Equal(network.LinkKindBond, r.TypedSpec().Kind)
suite.Assert().Equal(nethelpers.BondModeXOR, r.TypedSpec().BondMaster.Mode) suite.Assert().Equal(nethelpers.BondModeXOR, r.TypedSpec().BondMaster.Mode)
suite.Assert().True(r.TypedSpec().BondMaster.UseCarrier) suite.Assert().True(r.TypedSpec().BondMaster.UseCarrier)
case "wireguard0": case "wireguard0":
suite.Assert().True(r.TypedSpec().Up) suite.Assert().True(r.TypedSpec().Up)
suite.Assert().True(r.TypedSpec().Logical) suite.Assert().True(r.TypedSpec().Logical)
suite.Assert().Equal(nethelpers.LinkNone, r.TypedSpec().Type) suite.Assert().Equal(nethelpers.LinkNone, r.TypedSpec().Type)
suite.Assert().Equal(network.LinkKindWireguard, r.TypedSpec().Kind) suite.Assert().Equal(network.LinkKindWireguard, r.TypedSpec().Kind)
suite.Assert().Equal(network.WireguardSpec{ suite.Assert().Equal(
PrivateKey: "ABC", network.WireguardSpec{
Peers: []network.WireguardPeer{ PrivateKey: "ABC",
{ Peers: []network.WireguardPeer{
PublicKey: "DEF", {
Endpoint: "10.0.0.1:3000", PublicKey: "DEF",
AllowedIPs: []netaddr.IPPrefix{ Endpoint: "10.0.0.1:3000",
netaddr.MustParseIPPrefix("10.2.3.0/24"), AllowedIPs: []netaddr.IPPrefix{
netaddr.MustParseIPPrefix("10.2.4.0/24"), netaddr.MustParseIPPrefix("10.2.3.0/24"),
}, netaddr.MustParseIPPrefix("10.2.4.0/24"),
}, },
}, },
}, r.TypedSpec().Wireguard) },
} }, r.TypedSpec().Wireguard,
)
}
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *LinkConfigSuite) TestDefaultUp() { func (suite *LinkConfigSuite) TestDefaultUp() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.LinkConfigController{ suite.Require().NoError(
Cmdline: procfs.NewCmdline("talos.network.interface.ignore=eth2"), suite.runtime.RegisterController(
})) &netctrl.LinkConfigController{
Cmdline: procfs.NewCmdline("talos.network.interface.ignore=eth2"),
},
),
)
for _, link := range []string{"eth0", "eth1", "eth2", "eth3", "eth4"} { for _, link := range []string{"eth0", "eth1", "eth2", "eth3", "eth4"} {
linkStatus := network.NewLinkStatus(network.NamespaceName, link) linkStatus := network.NewLinkStatus(network.NamespaceName, link)
@ -341,74 +374,86 @@ func (suite *LinkConfigSuite) TestDefaultUp() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{ ConfigVersion: "v1alpha1",
MachineNetwork: &v1alpha1.NetworkConfig{ MachineConfig: &v1alpha1.MachineConfig{
NetworkInterfaces: []*v1alpha1.Device{ MachineNetwork: &v1alpha1.NetworkConfig{
{ NetworkInterfaces: []*v1alpha1.Device{
DeviceInterface: "eth0", {
DeviceVlans: []*v1alpha1.Vlan{ DeviceInterface: "eth0",
{ DeviceVlans: []*v1alpha1.Vlan{
VlanID: 24, {
VlanAddresses: []string{ VlanID: 24,
"10.0.0.1/8", VlanAddresses: []string{
"10.0.0.1/8",
},
}, },
}, {
{ VlanID: 48,
VlanID: 48, VlanAddresses: []string{
VlanAddresses: []string{ "10.0.0.2/8",
"10.0.0.2/8", },
}, },
}, },
}, },
}, {
{ DeviceInterface: "bond0",
DeviceInterface: "bond0", DeviceBond: &v1alpha1.Bond{
DeviceBond: &v1alpha1.Bond{ BondInterfaces: []string{
BondInterfaces: []string{ "eth3",
"eth3", "eth4",
"eth4", },
}, },
}, },
}, },
}, },
}, },
}, ClusterConfig: &v1alpha1.ClusterConfig{
ClusterConfig: &v1alpha1.ClusterConfig{ ControlPlane: &v1alpha1.ControlPlaneConfig{
ControlPlane: &v1alpha1.ControlPlaneConfig{ Endpoint: &v1alpha1.Endpoint{
Endpoint: &v1alpha1.Endpoint{ URL: u,
URL: u, },
}, },
}, },
}, },
}) )
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertLinks([]string{ func() error {
"default/eth1", return suite.assertLinks(
}, func(r *network.LinkSpec) error { []string{
suite.Assert().Equal(network.ConfigDefault, r.TypedSpec().ConfigLayer) "default/eth1",
suite.Assert().True(r.TypedSpec().Up) }, func(r *network.LinkSpec) error {
suite.Assert().Equal(network.ConfigDefault, r.TypedSpec().ConfigLayer)
suite.Assert().True(r.TypedSpec().Up)
return nil return nil
}) },
})) )
},
),
)
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNoLinks([]string{ func() error {
"default/eth0", return suite.assertNoLinks(
"default/eth2", []string{
"default/eth3", "default/eth0",
"default/eth4", "default/eth2",
}) "default/eth3",
})) "default/eth4",
},
)
},
),
)
} }
func (suite *LinkConfigSuite) TearDownTest() { func (suite *LinkConfigSuite) TearDownTest() {
@ -419,17 +464,26 @@ func (suite *LinkConfigSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ err := suite.state.Create(
ConfigVersion: "v1alpha1", context.Background(), config.NewMachineConfig(
MachineConfig: &v1alpha1.MachineConfig{}, &v1alpha1.Config{
})) ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{},
},
),
)
if state.IsConflictError(err) { if state.IsConflictError(err) {
err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata())
} }
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewLinkStatus(network.NamespaceName, "bar"))) suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewLinkStatus(network.NamespaceName, "bar"),
),
)
} }
func TestLinkConfigSuite(t *testing.T) { func TestLinkConfigSuite(t *testing.T) {

View File

@ -36,7 +36,7 @@ type LinkMergeSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -72,7 +72,10 @@ func (suite *LinkMergeSuite) assertLinks(requiredIDs []string, check func(*netwo
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.NamespaceName, network.LinkSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.LinkSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -98,7 +101,10 @@ func (suite *LinkMergeSuite) assertLinks(requiredIDs []string, check func(*netwo
} }
func (suite *LinkMergeSuite) assertNoLinks(id string) error { func (suite *LinkMergeSuite) assertNoLinks(id string) error {
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.NamespaceName, network.AddressStatusType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.AddressStatusType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -140,51 +146,64 @@ func (suite *LinkMergeSuite) TestMerge() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertLinks([]string{ func() error {
"lo", return suite.assertLinks(
"eth0", []string{
}, func(r *network.LinkSpec) error { "lo",
switch r.Metadata().ID() { "eth0",
case "lo": }, func(r *network.LinkSpec) error {
suite.Assert().Equal(*loopback.TypedSpec(), *r.TypedSpec()) switch r.Metadata().ID() {
case "eth0": case "lo":
suite.Assert().EqualValues(1500, r.TypedSpec().MTU) // static should override dhcp suite.Assert().Equal(*loopback.TypedSpec(), *r.TypedSpec())
} case "eth0":
suite.Assert().EqualValues(1500, r.TypedSpec().MTU) // static should override dhcp
}
return nil return nil
}) },
})) )
},
),
)
suite.Require().NoError(suite.state.Destroy(suite.ctx, static.Metadata())) suite.Require().NoError(suite.state.Destroy(suite.ctx, static.Metadata()))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertLinks([]string{ func() error {
"lo", return suite.assertLinks(
"eth0", []string{
}, func(r *network.LinkSpec) error { "lo",
switch r.Metadata().ID() { "eth0",
case "lo": }, func(r *network.LinkSpec) error {
suite.Assert().Equal(*loopback.TypedSpec(), *r.TypedSpec()) switch r.Metadata().ID() {
case "eth0": case "lo":
// reconcile happens eventually, so give it some time suite.Assert().Equal(*loopback.TypedSpec(), *r.TypedSpec())
if r.TypedSpec().MTU != 1450 { case "eth0":
return retry.ExpectedErrorf("MTU %d != 1450", r.TypedSpec().MTU) // reconcile happens eventually, so give it some time
} if r.TypedSpec().MTU != 1450 {
} return retry.ExpectedErrorf("MTU %d != 1450", r.TypedSpec().MTU)
}
}
return nil return nil
}) },
})) )
},
),
)
suite.Require().NoError(suite.state.Destroy(suite.ctx, loopback.Metadata())) suite.Require().NoError(suite.state.Destroy(suite.ctx, loopback.Metadata()))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNoLinks("lo") func() error {
})) return suite.assertNoLinks("lo")
},
),
)
} }
func (suite *LinkMergeSuite) TestMergeLogicalLink() { func (suite *LinkMergeSuite) TestMergeLogicalLink() {
@ -211,21 +230,26 @@ func (suite *LinkMergeSuite) TestMergeLogicalLink() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertLinks([]string{ func() error {
"bond0", return suite.assertLinks(
}, func(r *network.LinkSpec) error { []string{
if r.TypedSpec().MTU != 1450 { "bond0",
return retry.ExpectedErrorf("not merged yet") }, func(r *network.LinkSpec) error {
} if r.TypedSpec().MTU != 1450 {
return retry.ExpectedErrorf("not merged yet")
}
suite.Assert().True(r.TypedSpec().Logical) suite.Assert().True(r.TypedSpec().Logical)
suite.Assert().EqualValues(1450, r.TypedSpec().MTU) suite.Assert().EqualValues(1450, r.TypedSpec().MTU)
return nil return nil
}) },
})) )
},
),
)
} }
//nolint:gocyclo //nolint:gocyclo
@ -271,49 +295,74 @@ func (suite *LinkMergeSuite) TestMergeFlapping() {
eg.Go(flipflop(0)) eg.Go(flipflop(0))
eg.Go(flipflop(1)) eg.Go(flipflop(1))
eg.Go(func() error { eg.Go(
// add/remove finalizer to the merged resource func() error {
for i := 0; i < 1000; i++ { // add/remove finalizer to the merged resource
if err := suite.state.AddFinalizer(suite.ctx, resource.NewMetadata(network.NamespaceName, network.LinkSpecType, "eth0", resource.VersionUndefined), "foo"); err != nil { for i := 0; i < 1000; i++ {
if !state.IsNotFoundError(err) { if err := suite.state.AddFinalizer(
return err suite.ctx,
resource.NewMetadata(
network.NamespaceName,
network.LinkSpecType,
"eth0",
resource.VersionUndefined,
),
"foo",
); err != nil {
if !state.IsNotFoundError(err) {
return err
}
continue
} else {
suite.T().Log("finalizer added")
} }
continue time.Sleep(10 * time.Millisecond)
} else {
suite.T().Log("finalizer added")
}
time.Sleep(10 * time.Millisecond) if err := suite.state.RemoveFinalizer(
suite.ctx,
if err := suite.state.RemoveFinalizer(suite.ctx, resource.NewMetadata(network.NamespaceName, network.LinkSpecType, "eth0", resource.VersionUndefined), "foo"); err != nil { resource.NewMetadata(
if err != nil && !state.IsNotFoundError(err) { network.NamespaceName,
return err network.LinkSpecType,
"eth0",
resource.VersionUndefined,
),
"foo",
); err != nil {
if err != nil && !state.IsNotFoundError(err) {
return err
}
} }
} }
}
return nil return nil
}) },
)
suite.Require().NoError(eg.Wait()) suite.Require().NoError(eg.Wait())
suite.Assert().NoError(retry.Constant(15*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(15*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertLinks([]string{ func() error {
"eth0", return suite.assertLinks(
}, func(r *network.LinkSpec) error { []string{
if r.Metadata().Phase() != resource.PhaseRunning { "eth0",
return retry.ExpectedErrorf("resource phase is %s", r.Metadata().Phase()) }, func(r *network.LinkSpec) error {
} if r.Metadata().Phase() != resource.PhaseRunning {
return retry.ExpectedErrorf("resource phase is %s", r.Metadata().Phase())
}
if r.TypedSpec().MTU != 1500 { if r.TypedSpec().MTU != 1500 {
return retry.ExpectedErrorf("MTU %d != 1500", r.TypedSpec().MTU) return retry.ExpectedErrorf("MTU %d != 1500", r.TypedSpec().MTU)
} }
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *LinkMergeSuite) TestMergeWireguard() { func (suite *LinkMergeSuite) TestMergeWireguard() {
@ -352,41 +401,52 @@ func (suite *LinkMergeSuite) TestMergeWireguard() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertLinks([]string{ func() error {
"kubespan", return suite.assertLinks(
}, func(r *network.LinkSpec) error { []string{
suite.Assert().Equal("IG9MqCII7z54Ysof1fQ9a7WcMNG+qNJRMyRCQz3JTUY=", r.TypedSpec().Wireguard.PrivateKey) "kubespan",
suite.Assert().Equal(1234, r.TypedSpec().Wireguard.ListenPort) }, func(r *network.LinkSpec) error {
suite.Assert().Len(r.TypedSpec().Wireguard.Peers, 2) suite.Assert().Equal(
"IG9MqCII7z54Ysof1fQ9a7WcMNG+qNJRMyRCQz3JTUY=",
r.TypedSpec().Wireguard.PrivateKey,
)
suite.Assert().Equal(1234, r.TypedSpec().Wireguard.ListenPort)
suite.Assert().Len(r.TypedSpec().Wireguard.Peers, 2)
suite.Assert().Equal( suite.Assert().Equal(
network.WireguardPeer{ network.WireguardPeer{
PublicKey: "RXdQkMTD1Jcxd/Wizr9k8syw8ANs57l5jTormDVHAVs=", PublicKey: "RXdQkMTD1Jcxd/Wizr9k8syw8ANs57l5jTormDVHAVs=",
Endpoint: "127.0.0.1:1234", Endpoint: "127.0.0.1:1234",
},
r.TypedSpec().Wireguard.Peers[0],
)
suite.Assert().Equal(
network.WireguardPeer{
PublicKey: "bGsc2rOpl6JHd/Pm4fYrIkEABL0ZxW7IlaSyh77IMhw=",
Endpoint: "127.0.0.1:9999",
},
r.TypedSpec().Wireguard.Peers[1],
)
return nil
}, },
r.TypedSpec().Wireguard.Peers[0],
) )
},
suite.Assert().Equal( ),
network.WireguardPeer{ )
PublicKey: "bGsc2rOpl6JHd/Pm4fYrIkEABL0ZxW7IlaSyh77IMhw=",
Endpoint: "127.0.0.1:9999",
},
r.TypedSpec().Wireguard.Peers[1],
)
return nil
})
}))
suite.Require().NoError(suite.state.Destroy(suite.ctx, kubespanOperator.Metadata())) suite.Require().NoError(suite.state.Destroy(suite.ctx, kubespanOperator.Metadata()))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNoLinks("kubespan") func() error {
})) return suite.assertNoLinks("kubespan")
},
),
)
} }
func (suite *LinkMergeSuite) TearDownTest() { func (suite *LinkMergeSuite) TearDownTest() {
@ -397,7 +457,12 @@ func (suite *LinkMergeSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewLinkSpec(network.ConfigNamespaceName, "bar"))) suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewLinkSpec(network.ConfigNamespaceName, "bar"),
),
)
} }
func TestLinkMergeSuite(t *testing.T) { func TestLinkMergeSuite(t *testing.T) {

View File

@ -160,7 +160,8 @@ func findLink(links []rtnetlink.LinkMessage, name string) *rtnetlink.LinkMessage
// //
//nolint:gocyclo,cyclop //nolint:gocyclo,cyclop
func (ctrl *LinkSpecController) syncLink(ctx context.Context, r controller.Runtime, logger *zap.Logger, conn *rtnetlink.Conn, wgClient *wgctrl.Client, func (ctrl *LinkSpecController) syncLink(ctx context.Context, r controller.Runtime, logger *zap.Logger, conn *rtnetlink.Conn, wgClient *wgctrl.Client,
links *[]rtnetlink.LinkMessage, link *network.LinkSpec) error { links *[]rtnetlink.LinkMessage, link *network.LinkSpec,
) error {
logger = logger.With(zap.String("link", link.TypedSpec().Name)) logger = logger.With(zap.String("link", link.TypedSpec().Name))
switch link.Metadata().Phase() { switch link.Metadata().Phase() {

View File

@ -39,7 +39,7 @@ type LinkSpecSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -78,7 +78,10 @@ func (suite *LinkSpecSuite) assertInterfaces(requiredIDs []string, check func(*n
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.NamespaceName, network.LinkStatusType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.LinkStatusType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -104,7 +107,10 @@ func (suite *LinkSpecSuite) assertInterfaces(requiredIDs []string, check func(*n
} }
func (suite *LinkSpecSuite) assertNoInterface(id string) error { func (suite *LinkSpecSuite) assertNoInterface(id string) error {
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.NamespaceName, network.LinkStatusType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.LinkStatusType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -134,12 +140,17 @@ func (suite *LinkSpecSuite) TestLoopback() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertInterfaces([]string{"lo"}, func(r *network.LinkStatus) error { func() error {
return nil return suite.assertInterfaces(
}) []string{"lo"}, func(r *network.LinkStatus) error {
})) return nil
},
)
},
),
)
} }
func (suite *LinkSpecSuite) TestDummy() { func (suite *LinkSpecSuite) TestDummy() {
@ -160,22 +171,27 @@ func (suite *LinkSpecSuite) TestDummy() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertInterfaces([]string{dummyInterface}, func(r *network.LinkStatus) error { func() error {
suite.Assert().Equal("dummy", r.TypedSpec().Kind) return suite.assertInterfaces(
[]string{dummyInterface}, func(r *network.LinkStatus) error {
suite.Assert().Equal("dummy", r.TypedSpec().Kind)
if r.TypedSpec().OperationalState != nethelpers.OperStateUnknown && r.TypedSpec().OperationalState != nethelpers.OperStateUp { if r.TypedSpec().OperationalState != nethelpers.OperStateUnknown && r.TypedSpec().OperationalState != nethelpers.OperStateUp {
return retry.ExpectedErrorf("link is not up") return retry.ExpectedErrorf("link is not up")
} }
if r.TypedSpec().MTU != 1400 { if r.TypedSpec().MTU != 1400 {
return retry.ExpectedErrorf("unexpected MTU %d", r.TypedSpec().MTU) return retry.ExpectedErrorf("unexpected MTU %d", r.TypedSpec().MTU)
} }
return nil return nil
}) },
})) )
},
),
)
// teardown the link // teardown the link
for { for {
@ -189,10 +205,13 @@ func (suite *LinkSpecSuite) TestDummy() {
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNoInterface(dummyInterface) func() error {
})) return suite.assertNoInterface(dummyInterface)
},
),
)
} }
//nolint:gocyclo //nolint:gocyclo
@ -245,49 +264,61 @@ func (suite *LinkSpecSuite) TestVLAN() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertInterfaces([]string{dummyInterface, vlanName1, vlanName2}, func(r *network.LinkStatus) error { func() error {
switch r.Metadata().ID() { return suite.assertInterfaces(
case dummyInterface: []string{dummyInterface, vlanName1, vlanName2}, func(r *network.LinkStatus) error {
suite.Assert().Equal("dummy", r.TypedSpec().Kind) switch r.Metadata().ID() {
case vlanName1, vlanName2: case dummyInterface:
suite.Assert().Equal(network.LinkKindVLAN, r.TypedSpec().Kind) suite.Assert().Equal("dummy", r.TypedSpec().Kind)
suite.Assert().Equal(nethelpers.VLANProtocol8021Q, r.TypedSpec().VLAN.Protocol) case vlanName1, vlanName2:
suite.Assert().Equal(network.LinkKindVLAN, r.TypedSpec().Kind)
suite.Assert().Equal(nethelpers.VLANProtocol8021Q, r.TypedSpec().VLAN.Protocol)
if r.Metadata().ID() == vlanName1 { if r.Metadata().ID() == vlanName1 {
suite.Assert().EqualValues(2, r.TypedSpec().VLAN.VID) suite.Assert().EqualValues(2, r.TypedSpec().VLAN.VID)
} else { } else {
suite.Assert().EqualValues(4, r.TypedSpec().VLAN.VID) suite.Assert().EqualValues(4, r.TypedSpec().VLAN.VID)
} }
} }
if r.TypedSpec().OperationalState != nethelpers.OperStateUnknown && r.TypedSpec().OperationalState != nethelpers.OperStateUp { if r.TypedSpec().OperationalState != nethelpers.OperStateUnknown && r.TypedSpec().OperationalState != nethelpers.OperStateUp {
return retry.ExpectedErrorf("link is not up") return retry.ExpectedErrorf("link is not up")
} }
return nil return nil
}) },
})) )
},
),
)
// attempt to change VLAN ID // attempt to change VLAN ID
_, err := suite.state.UpdateWithConflicts(suite.ctx, vlan1.Metadata(), func(r resource.Resource) error { _, err := suite.state.UpdateWithConflicts(
r.(*network.LinkSpec).TypedSpec().VLAN.VID = 42 suite.ctx, vlan1.Metadata(), func(r resource.Resource) error {
r.(*network.LinkSpec).TypedSpec().VLAN.VID = 42
return nil return nil
}) },
)
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertInterfaces([]string{vlanName1}, func(r *network.LinkStatus) error { func() error {
if r.TypedSpec().VLAN.VID != 42 { return suite.assertInterfaces(
return retry.ExpectedErrorf("vlan ID is not 42: %d", r.TypedSpec().VLAN.VID) []string{vlanName1}, func(r *network.LinkStatus) error {
} if r.TypedSpec().VLAN.VID != 42 {
return retry.ExpectedErrorf("vlan ID is not 42: %d", r.TypedSpec().VLAN.VID)
}
return nil return nil
}) },
})) )
},
),
)
// teardown the links // teardown the links
for _, r := range []resource.Resource{vlan1, vlan2, dummy} { for _, r := range []resource.Resource{vlan1, vlan2, dummy} {
@ -303,10 +334,13 @@ func (suite *LinkSpecSuite) TestVLAN() {
} }
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNoInterface(dummyInterface) func() error {
})) return suite.assertNoInterface(dummyInterface)
},
),
)
} }
//nolint:gocyclo //nolint:gocyclo
@ -362,69 +396,92 @@ func (suite *LinkSpecSuite) TestBond() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertInterfaces([]string{dummy0Name, dummy1Name, bondName}, func(r *network.LinkStatus) error { func() error {
switch r.Metadata().ID() { return suite.assertInterfaces(
case bondName: []string{dummy0Name, dummy1Name, bondName}, func(r *network.LinkStatus) error {
suite.Assert().Equal(network.LinkKindBond, r.TypedSpec().Kind) switch r.Metadata().ID() {
case bondName:
suite.Assert().Equal(network.LinkKindBond, r.TypedSpec().Kind)
if r.TypedSpec().OperationalState != nethelpers.OperStateUnknown && r.TypedSpec().OperationalState != nethelpers.OperStateUp { if r.TypedSpec().OperationalState != nethelpers.OperStateUnknown && r.TypedSpec().OperationalState != nethelpers.OperStateUp {
return retry.ExpectedErrorf("link is not up: %s", r.TypedSpec().OperationalState) return retry.ExpectedErrorf("link is not up: %s", r.TypedSpec().OperationalState)
} }
case dummy0Name, dummy1Name: case dummy0Name, dummy1Name:
suite.Assert().Equal("dummy", r.TypedSpec().Kind) suite.Assert().Equal("dummy", r.TypedSpec().Kind)
if r.TypedSpec().OperationalState != nethelpers.OperStateUnknown { if r.TypedSpec().OperationalState != nethelpers.OperStateUnknown {
return retry.ExpectedErrorf("link is not up: %s", r.TypedSpec().OperationalState) return retry.ExpectedErrorf("link is not up: %s", r.TypedSpec().OperationalState)
} }
if r.TypedSpec().MasterIndex == 0 { if r.TypedSpec().MasterIndex == 0 {
return retry.ExpectedErrorf("masterIndex should be non-zero") return retry.ExpectedErrorf("masterIndex should be non-zero")
} }
} }
return nil return nil
}) },
})) )
},
),
)
// attempt to change bond type // attempt to change bond type
_, err := suite.state.UpdateWithConflicts(suite.ctx, bond.Metadata(), func(r resource.Resource) error { _, err := suite.state.UpdateWithConflicts(
r.(*network.LinkSpec).TypedSpec().BondMaster.Mode = nethelpers.BondModeRoundrobin suite.ctx, bond.Metadata(), func(r resource.Resource) error {
r.(*network.LinkSpec).TypedSpec().BondMaster.Mode = nethelpers.BondModeRoundrobin
return nil return nil
}) },
)
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertInterfaces([]string{bondName}, func(r *network.LinkStatus) error { func() error {
if r.TypedSpec().BondMaster.Mode != nethelpers.BondModeRoundrobin { return suite.assertInterfaces(
return retry.ExpectedErrorf("bond mode is not %s: %s", nethelpers.BondModeRoundrobin, r.TypedSpec().BondMaster.Mode) []string{bondName}, func(r *network.LinkStatus) error {
} if r.TypedSpec().BondMaster.Mode != nethelpers.BondModeRoundrobin {
return retry.ExpectedErrorf(
"bond mode is not %s: %s",
nethelpers.BondModeRoundrobin,
r.TypedSpec().BondMaster.Mode,
)
}
return nil return nil
}) },
})) )
},
),
)
// unslave one of the interfaces // unslave one of the interfaces
_, err = suite.state.UpdateWithConflicts(suite.ctx, dummy0.Metadata(), func(r resource.Resource) error { _, err = suite.state.UpdateWithConflicts(
r.(*network.LinkSpec).TypedSpec().MasterName = "" suite.ctx, dummy0.Metadata(), func(r resource.Resource) error {
r.(*network.LinkSpec).TypedSpec().MasterName = ""
return nil return nil
}) },
)
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertInterfaces([]string{dummy0Name}, func(r *network.LinkStatus) error { func() error {
if r.TypedSpec().MasterIndex != 0 { return suite.assertInterfaces(
return retry.ExpectedErrorf("iface not unslaved yet") []string{dummy0Name}, func(r *network.LinkStatus) error {
} if r.TypedSpec().MasterIndex != 0 {
return retry.ExpectedErrorf("iface not unslaved yet")
}
return nil return nil
}) },
})) )
},
),
)
// teardown the links // teardown the links
for _, r := range []resource.Resource{dummy0, dummy1, bond} { for _, r := range []resource.Resource{dummy0, dummy1, bond} {
@ -440,10 +497,13 @@ func (suite *LinkSpecSuite) TestBond() {
} }
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNoInterface(bondName) func() error {
})) return suite.assertNoInterface(bondName)
},
),
)
} }
//nolint:gocyclo //nolint:gocyclo
@ -490,32 +550,37 @@ func (suite *LinkSpecSuite) TestBond8023ad() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertInterfaces(append(dummyNames, bondName), func(r *network.LinkStatus) error { func() error {
if r.Metadata().ID() == bondName { return suite.assertInterfaces(
// master append(dummyNames, bondName), func(r *network.LinkStatus) error {
suite.Assert().Equal(network.LinkKindBond, r.TypedSpec().Kind) if r.Metadata().ID() == bondName {
// master
suite.Assert().Equal(network.LinkKindBond, r.TypedSpec().Kind)
if r.TypedSpec().OperationalState != nethelpers.OperStateUnknown && r.TypedSpec().OperationalState != nethelpers.OperStateUp { if r.TypedSpec().OperationalState != nethelpers.OperStateUnknown && r.TypedSpec().OperationalState != nethelpers.OperStateUp {
return retry.ExpectedErrorf("link is not up: %s", r.TypedSpec().OperationalState) return retry.ExpectedErrorf("link is not up: %s", r.TypedSpec().OperationalState)
} }
} else { } else {
// slaves // slaves
suite.Assert().Equal("dummy", r.TypedSpec().Kind) suite.Assert().Equal("dummy", r.TypedSpec().Kind)
if r.TypedSpec().OperationalState != nethelpers.OperStateUnknown { if r.TypedSpec().OperationalState != nethelpers.OperStateUnknown {
return retry.ExpectedErrorf("link is not up: %s", r.TypedSpec().OperationalState) return retry.ExpectedErrorf("link is not up: %s", r.TypedSpec().OperationalState)
} }
if r.TypedSpec().MasterIndex == 0 { if r.TypedSpec().MasterIndex == 0 {
return retry.ExpectedErrorf("masterIndex should be non-zero") return retry.ExpectedErrorf("masterIndex should be non-zero")
} }
} }
return nil return nil
}) },
})) )
},
),
)
// teardown the links // teardown the links
for _, r := range append(dummies, bond) { for _, r := range append(dummies, bond) {
@ -531,10 +596,13 @@ func (suite *LinkSpecSuite) TestBond8023ad() {
} }
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNoInterface(bondName) func() error {
})) return suite.assertNoInterface(bondName)
},
),
)
} }
func (suite *LinkSpecSuite) TestWireguard() { func (suite *LinkSpecSuite) TestWireguard() {
@ -583,48 +651,60 @@ func (suite *LinkSpecSuite) TestWireguard() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertInterfaces([]string{wgInterface}, func(r *network.LinkStatus) error { func() error {
suite.Assert().Equal("wireguard", r.TypedSpec().Kind) return suite.assertInterfaces(
[]string{wgInterface}, func(r *network.LinkStatus) error {
suite.Assert().Equal("wireguard", r.TypedSpec().Kind)
if r.TypedSpec().Wireguard.PublicKey != priv.PublicKey().String() { if r.TypedSpec().Wireguard.PublicKey != priv.PublicKey().String() {
return retry.ExpectedErrorf("private key not set") return retry.ExpectedErrorf("private key not set")
} }
if len(r.TypedSpec().Wireguard.Peers) != 2 { if len(r.TypedSpec().Wireguard.Peers) != 2 {
return retry.ExpectedErrorf("peers are not set up") return retry.ExpectedErrorf("peers are not set up")
} }
if r.TypedSpec().OperationalState != nethelpers.OperStateUnknown && r.TypedSpec().OperationalState != nethelpers.OperStateUp { if r.TypedSpec().OperationalState != nethelpers.OperStateUnknown && r.TypedSpec().OperationalState != nethelpers.OperStateUp {
return retry.ExpectedErrorf("link is not up") return retry.ExpectedErrorf("link is not up")
} }
return nil return nil
}) },
})) )
},
),
)
// attempt to change wireguard private key // attempt to change wireguard private key
priv2, err := wgtypes.GeneratePrivateKey() priv2, err := wgtypes.GeneratePrivateKey()
suite.Require().NoError(err) suite.Require().NoError(err)
_, err = suite.state.UpdateWithConflicts(suite.ctx, wg.Metadata(), func(r resource.Resource) error { _, err = suite.state.UpdateWithConflicts(
r.(*network.LinkSpec).TypedSpec().Wireguard.PrivateKey = priv2.String() suite.ctx, wg.Metadata(), func(r resource.Resource) error {
r.(*network.LinkSpec).TypedSpec().Wireguard.PrivateKey = priv2.String()
return nil return nil
}) },
)
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertInterfaces([]string{wgInterface}, func(r *network.LinkStatus) error { func() error {
if r.TypedSpec().Wireguard.PublicKey != priv2.PublicKey().String() { return suite.assertInterfaces(
return retry.ExpectedErrorf("private key was not updated") []string{wgInterface}, func(r *network.LinkStatus) error {
} if r.TypedSpec().Wireguard.PublicKey != priv2.PublicKey().String() {
return retry.ExpectedErrorf("private key was not updated")
}
return nil return nil
}) },
})) )
},
),
)
// teardown the links // teardown the links
for _, r := range []resource.Resource{wg} { for _, r := range []resource.Resource{wg} {
@ -640,10 +720,13 @@ func (suite *LinkSpecSuite) TestWireguard() {
} }
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNoInterface(wgInterface) func() error {
})) return suite.assertNoInterface(wgInterface)
},
),
)
} }
func (suite *LinkSpecSuite) TearDownTest() { func (suite *LinkSpecSuite) TearDownTest() {

View File

@ -39,7 +39,7 @@ type LinkStatusSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -79,7 +79,10 @@ func (suite *LinkStatusSuite) assertInterfaces(requiredIDs []string, check func(
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.NamespaceName, network.LinkStatusType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.LinkStatusType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -105,7 +108,10 @@ func (suite *LinkStatusSuite) assertInterfaces(requiredIDs []string, check func(
} }
func (suite *LinkStatusSuite) assertNoInterface(id string) error { func (suite *LinkStatusSuite) assertNoInterface(id string) error {
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.NamespaceName, network.LinkStatusType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.LinkStatusType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -120,15 +126,20 @@ func (suite *LinkStatusSuite) assertNoInterface(id string) error {
} }
func (suite *LinkStatusSuite) TestLoopbackInterface() { func (suite *LinkStatusSuite) TestLoopbackInterface() {
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertInterfaces([]string{"lo"}, func(r *network.LinkStatus) error { func() error {
suite.Assert().Equal("loopback", r.TypedSpec().Type.String()) return suite.assertInterfaces(
suite.Assert().EqualValues(65536, r.TypedSpec().MTU) []string{"lo"}, func(r *network.LinkStatus) error {
suite.Assert().Equal("loopback", r.TypedSpec().Type.String())
suite.Assert().EqualValues(65536, r.TypedSpec().MTU)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *LinkStatusSuite) TestDummyInterface() { func (suite *LinkStatusSuite) TestDummyInterface() {
@ -139,57 +150,83 @@ func (suite *LinkStatusSuite) TestDummyInterface() {
defer conn.Close() //nolint:errcheck defer conn.Close() //nolint:errcheck
suite.Require().NoError(conn.Link.New(&rtnetlink.LinkMessage{ suite.Require().NoError(
Type: unix.ARPHRD_ETHER, conn.Link.New(
Attributes: &rtnetlink.LinkAttributes{ &rtnetlink.LinkMessage{
Name: dummyInterface, Type: unix.ARPHRD_ETHER,
MTU: 1400, Attributes: &rtnetlink.LinkAttributes{
Info: &rtnetlink.LinkInfo{ Name: dummyInterface,
Kind: "dummy", MTU: 1400,
Info: &rtnetlink.LinkInfo{
Kind: "dummy",
},
},
}, },
}, ),
})) )
iface, err := net.InterfaceByName(dummyInterface) iface, err := net.InterfaceByName(dummyInterface)
suite.Require().NoError(err) suite.Require().NoError(err)
defer conn.Link.Delete(uint32(iface.Index)) //nolint:errcheck defer conn.Link.Delete(uint32(iface.Index)) //nolint:errcheck
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertInterfaces([]string{dummyInterface}, func(r *network.LinkStatus) error { func() error {
suite.Assert().Equal("ether", r.TypedSpec().Type.String()) return suite.assertInterfaces(
suite.Assert().EqualValues(1400, r.TypedSpec().MTU) []string{dummyInterface}, func(r *network.LinkStatus) error {
suite.Assert().Equal(nethelpers.OperStateDown, r.TypedSpec().OperationalState) suite.Assert().Equal("ether", r.TypedSpec().Type.String())
suite.Assert().EqualValues(1400, r.TypedSpec().MTU)
suite.Assert().Equal(nethelpers.OperStateDown, r.TypedSpec().OperationalState)
return nil return nil
}) },
})) )
},
),
)
suite.Require().NoError(conn.Link.Set(&rtnetlink.LinkMessage{ suite.Require().NoError(
Type: unix.ARPHRD_ETHER, conn.Link.Set(
Index: uint32(iface.Index), &rtnetlink.LinkMessage{
Flags: unix.IFF_UP, Type: unix.ARPHRD_ETHER,
Change: unix.IFF_UP, Index: uint32(iface.Index),
})) Flags: unix.IFF_UP,
Change: unix.IFF_UP,
},
),
)
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertInterfaces([]string{dummyInterface}, func(r *network.LinkStatus) error { func() error {
if r.TypedSpec().OperationalState != nethelpers.OperStateUp && r.TypedSpec().OperationalState != nethelpers.OperStateUnknown { return suite.assertInterfaces(
return retry.ExpectedError(fmt.Errorf("operational state is not up: %s", r.TypedSpec().OperationalState)) []string{dummyInterface}, func(r *network.LinkStatus) error {
} if r.TypedSpec().OperationalState != nethelpers.OperStateUp && r.TypedSpec().OperationalState != nethelpers.OperStateUnknown {
return retry.ExpectedError(
fmt.Errorf(
"operational state is not up: %s",
r.TypedSpec().OperationalState,
),
)
}
return nil return nil
}) },
})) )
},
),
)
suite.Require().NoError(conn.Link.Delete(uint32(iface.Index))) suite.Require().NoError(conn.Link.Delete(uint32(iface.Index)))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNoInterface(dummyInterface) func() error {
})) return suite.assertNoInterface(dummyInterface)
},
),
)
} }
func (suite *LinkStatusSuite) TearDownTest() { func (suite *LinkStatusSuite) TearDownTest() {
@ -200,7 +237,12 @@ func (suite *LinkStatusSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewLinkRefresh(network.NamespaceName, "bar"))) suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewLinkRefresh(network.NamespaceName, "bar"),
),
)
} }
func TestLinkStatusSuite(t *testing.T) { func TestLinkStatusSuite(t *testing.T) {

View File

@ -39,7 +39,7 @@ type NodeAddressSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -75,7 +75,10 @@ func (suite *NodeAddressSuite) assertAddresses(requiredIDs []string, check func(
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.NamespaceName, network.NodeAddressType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.NodeAddressType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -104,34 +107,43 @@ func (suite *NodeAddressSuite) TestDefaults() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.AddressStatusController{})) suite.Require().NoError(suite.runtime.RegisterController(&netctrl.AddressStatusController{}))
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.LinkStatusController{})) suite.Require().NoError(suite.runtime.RegisterController(&netctrl.LinkStatusController{}))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertAddresses([]string{ func() error {
network.NodeAddressDefaultID, return suite.assertAddresses(
network.NodeAddressCurrentID, []string{
network.NodeAddressAccumulativeID, network.NodeAddressDefaultID,
}, func(r *network.NodeAddress) error { network.NodeAddressCurrentID,
addrs := r.TypedSpec().Addresses network.NodeAddressAccumulativeID,
}, func(r *network.NodeAddress) error {
addrs := r.TypedSpec().Addresses
suite.T().Logf("id %q val %s", r.Metadata().ID(), addrs) suite.T().Logf("id %q val %s", r.Metadata().ID(), addrs)
suite.Assert().True(sort.SliceIsSorted(addrs, func(i, j int) bool { suite.Assert().True(
return addrs[i].IP().Compare(addrs[j].IP()) < 0 sort.SliceIsSorted(
}), "addresses %s", addrs) addrs, func(i, j int) bool {
return addrs[i].IP().Compare(addrs[j].IP()) < 0
},
), "addresses %s", addrs,
)
if r.Metadata().ID() == network.NodeAddressDefaultID { if r.Metadata().ID() == network.NodeAddressDefaultID {
if len(addrs) != 1 { if len(addrs) != 1 {
return fmt.Errorf("there should be only one default address") return fmt.Errorf("there should be only one default address")
} }
} else { } else {
if len(addrs) == 0 { if len(addrs) == 0 {
return fmt.Errorf("there should be some addresses") return fmt.Errorf("there should be some addresses")
} }
} }
return nil return nil
}) },
})) )
},
),
)
} }
//nolint:gocyclo //nolint:gocyclo
@ -158,17 +170,34 @@ func (suite *NodeAddressSuite) TestFilters() {
addressStatus.TypedSpec().Address = addr addressStatus.TypedSpec().Address = addr
addressStatus.TypedSpec().LinkName = link.Metadata().ID() addressStatus.TypedSpec().LinkName = link.Metadata().ID()
addressStatus.TypedSpec().LinkIndex = link.TypedSpec().Index addressStatus.TypedSpec().LinkIndex = link.TypedSpec().Index
suite.Require().NoError(suite.state.Create(suite.ctx, addressStatus, state.WithCreateOwner(addressStatusController.Name()))) suite.Require().NoError(
suite.state.Create(
suite.ctx,
addressStatus,
state.WithCreateOwner(addressStatusController.Name()),
),
)
} }
newExternalAddress := func(addr netaddr.IPPrefix) { newExternalAddress := func(addr netaddr.IPPrefix) {
addressStatus := network.NewAddressStatus(network.NamespaceName, network.AddressID("external", addr)) addressStatus := network.NewAddressStatus(network.NamespaceName, network.AddressID("external", addr))
addressStatus.TypedSpec().Address = addr addressStatus.TypedSpec().Address = addr
addressStatus.TypedSpec().LinkName = "external" addressStatus.TypedSpec().LinkName = "external"
suite.Require().NoError(suite.state.Create(suite.ctx, addressStatus, state.WithCreateOwner(platformConfigController.Name()))) suite.Require().NoError(
suite.state.Create(
suite.ctx,
addressStatus,
state.WithCreateOwner(platformConfigController.Name()),
),
)
} }
for _, addr := range []string{"10.0.0.1/8", "25.3.7.9/32", "2001:470:6d:30e:4a62:b3ba:180b:b5b8/64", "127.0.0.1/8"} { for _, addr := range []string{
"10.0.0.1/8",
"25.3.7.9/32",
"2001:470:6d:30e:4a62:b3ba:180b:b5b8/64",
"127.0.0.1/8",
} {
newAddress(netaddr.MustParseIPPrefix(addr), linkUp) newAddress(netaddr.MustParseIPPrefix(addr), linkUp)
} }
@ -185,56 +214,76 @@ func (suite *NodeAddressSuite) TestFilters() {
suite.Require().NoError(suite.state.Create(suite.ctx, filter1)) suite.Require().NoError(suite.state.Create(suite.ctx, filter1))
filter2 := network.NewNodeAddressFilter(network.NamespaceName, "only-k8s") filter2 := network.NewNodeAddressFilter(network.NamespaceName, "only-k8s")
filter2.TypedSpec().IncludeSubnets = []netaddr.IPPrefix{netaddr.MustParseIPPrefix("10.0.0.0/8"), netaddr.MustParseIPPrefix("192.168.0.0/16")} filter2.TypedSpec().IncludeSubnets = []netaddr.IPPrefix{
netaddr.MustParseIPPrefix("10.0.0.0/8"),
netaddr.MustParseIPPrefix("192.168.0.0/16"),
}
suite.Require().NoError(suite.state.Create(suite.ctx, filter2)) suite.Require().NoError(suite.state.Create(suite.ctx, filter2))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertAddresses([]string{ func() error {
network.NodeAddressDefaultID, return suite.assertAddresses(
network.NodeAddressCurrentID, []string{
network.NodeAddressAccumulativeID, network.NodeAddressDefaultID,
network.FilteredNodeAddressID(network.NodeAddressCurrentID, filter1.Metadata().ID()), network.NodeAddressCurrentID,
network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, filter1.Metadata().ID()), network.NodeAddressAccumulativeID,
network.FilteredNodeAddressID(network.NodeAddressCurrentID, filter2.Metadata().ID()), network.FilteredNodeAddressID(network.NodeAddressCurrentID, filter1.Metadata().ID()),
network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, filter2.Metadata().ID()), network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, filter1.Metadata().ID()),
}, func(r *network.NodeAddress) error { network.FilteredNodeAddressID(network.NodeAddressCurrentID, filter2.Metadata().ID()),
addrs := r.TypedSpec().Addresses network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, filter2.Metadata().ID()),
}, func(r *network.NodeAddress) error {
addrs := r.TypedSpec().Addresses
switch r.Metadata().ID() { switch r.Metadata().ID() {
case network.NodeAddressDefaultID: case network.NodeAddressDefaultID:
if !reflect.DeepEqual(addrs, ipList("10.0.0.1/8")) { if !reflect.DeepEqual(addrs, ipList("10.0.0.1/8")) {
return fmt.Errorf("unexpected %q: %s", r.Metadata().ID(), addrs) return fmt.Errorf("unexpected %q: %s", r.Metadata().ID(), addrs)
} }
case network.NodeAddressCurrentID: case network.NodeAddressCurrentID:
if !reflect.DeepEqual(addrs, ipList("1.2.3.4/32 10.0.0.1/8 25.3.7.9/32 2001:470:6d:30e:4a62:b3ba:180b:b5b8/64")) { if !reflect.DeepEqual(
return fmt.Errorf("unexpected %q: %s", r.Metadata().ID(), addrs) addrs,
} ipList("1.2.3.4/32 10.0.0.1/8 25.3.7.9/32 2001:470:6d:30e:4a62:b3ba:180b:b5b8/64"),
case network.NodeAddressAccumulativeID: ) {
if !reflect.DeepEqual(addrs, ipList("1.2.3.4/32 10.0.0.1/8 10.0.0.2/8 25.3.7.9/32 192.168.3.7/24 2001:470:6d:30e:4a62:b3ba:180b:b5b8/64")) { return fmt.Errorf("unexpected %q: %s", r.Metadata().ID(), addrs)
return fmt.Errorf("unexpected %q: %s", r.Metadata().ID(), addrs) }
} case network.NodeAddressAccumulativeID:
case network.FilteredNodeAddressID(network.NodeAddressCurrentID, filter1.Metadata().ID()): if !reflect.DeepEqual(
if !reflect.DeepEqual(addrs, ipList("1.2.3.4/32 25.3.7.9/32 2001:470:6d:30e:4a62:b3ba:180b:b5b8/64")) { addrs,
return fmt.Errorf("unexpected %q: %s", r.Metadata().ID(), addrs) ipList("1.2.3.4/32 10.0.0.1/8 10.0.0.2/8 25.3.7.9/32 192.168.3.7/24 2001:470:6d:30e:4a62:b3ba:180b:b5b8/64"),
} ) {
case network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, filter1.Metadata().ID()): return fmt.Errorf("unexpected %q: %s", r.Metadata().ID(), addrs)
if !reflect.DeepEqual(addrs, ipList("1.2.3.4/32 25.3.7.9/32 192.168.3.7/24 2001:470:6d:30e:4a62:b3ba:180b:b5b8/64")) { }
return fmt.Errorf("unexpected %q: %s", r.Metadata().ID(), addrs) case network.FilteredNodeAddressID(network.NodeAddressCurrentID, filter1.Metadata().ID()):
} if !reflect.DeepEqual(
case network.FilteredNodeAddressID(network.NodeAddressCurrentID, filter2.Metadata().ID()): addrs,
if !reflect.DeepEqual(addrs, ipList("10.0.0.1/8")) { ipList("1.2.3.4/32 25.3.7.9/32 2001:470:6d:30e:4a62:b3ba:180b:b5b8/64"),
return fmt.Errorf("unexpected %q: %s", r.Metadata().ID(), addrs) ) {
} return fmt.Errorf("unexpected %q: %s", r.Metadata().ID(), addrs)
case network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, filter2.Metadata().ID()): }
if !reflect.DeepEqual(addrs, ipList("10.0.0.1/8 10.0.0.2/8 192.168.3.7/24")) { case network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, filter1.Metadata().ID()):
return fmt.Errorf("unexpected %q: %s", r.Metadata().ID(), addrs) if !reflect.DeepEqual(
} addrs,
} ipList("1.2.3.4/32 25.3.7.9/32 192.168.3.7/24 2001:470:6d:30e:4a62:b3ba:180b:b5b8/64"),
) {
return fmt.Errorf("unexpected %q: %s", r.Metadata().ID(), addrs)
}
case network.FilteredNodeAddressID(network.NodeAddressCurrentID, filter2.Metadata().ID()):
if !reflect.DeepEqual(addrs, ipList("10.0.0.1/8")) {
return fmt.Errorf("unexpected %q: %s", r.Metadata().ID(), addrs)
}
case network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, filter2.Metadata().ID()):
if !reflect.DeepEqual(addrs, ipList("10.0.0.1/8 10.0.0.2/8 192.168.3.7/24")) {
return fmt.Errorf("unexpected %q: %s", r.Metadata().ID(), addrs)
}
}
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *NodeAddressSuite) TearDownTest() { func (suite *NodeAddressSuite) TearDownTest() {
@ -245,8 +294,18 @@ func (suite *NodeAddressSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewAddressStatus(network.NamespaceName, "bar"))) suite.Assert().NoError(
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewLinkStatus(network.NamespaceName, "bar"))) suite.state.Create(
context.Background(),
network.NewAddressStatus(network.NamespaceName, "bar"),
),
)
suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewLinkStatus(network.NamespaceName, "bar"),
),
)
} }
func TestNodeAddressSuite(t *testing.T) { func TestNodeAddressSuite(t *testing.T) {

View File

@ -40,7 +40,7 @@ type OperatorConfigSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -72,7 +72,10 @@ func (suite *OperatorConfigSuite) assertOperators(requiredIDs []string, check fu
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.ConfigNamespaceName, network.OperatorSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.ConfigNamespaceName, network.OperatorSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -104,7 +107,10 @@ func (suite *OperatorConfigSuite) assertNoOperators(unexpectedIDs []string) erro
unexpIDs[id] = struct{}{} unexpIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.ConfigNamespaceName, network.OperatorSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.ConfigNamespaceName, network.OperatorSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -120,9 +126,13 @@ func (suite *OperatorConfigSuite) assertNoOperators(unexpectedIDs []string) erro
} }
func (suite *OperatorConfigSuite) TestDefaultDHCP() { func (suite *OperatorConfigSuite) TestDefaultDHCP() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.OperatorConfigController{ suite.Require().NoError(
Cmdline: procfs.NewCmdline("talos.network.interface.ignore=eth2"), suite.runtime.RegisterController(
})) &netctrl.OperatorConfigController{
Cmdline: procfs.NewCmdline("talos.network.interface.ignore=eth2"),
},
),
)
suite.startRuntime() suite.startRuntime()
@ -134,32 +144,41 @@ func (suite *OperatorConfigSuite) TestDefaultDHCP() {
suite.Require().NoError(suite.state.Create(suite.ctx, linkStatus)) suite.Require().NoError(suite.state.Create(suite.ctx, linkStatus))
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertOperators([]string{ func() error {
"default/dhcp4/eth0", return suite.assertOperators(
"default/dhcp4/eth1", []string{
}, func(r *network.OperatorSpec) error { "default/dhcp4/eth0",
suite.Assert().Equal(network.OperatorDHCP4, r.TypedSpec().Operator) "default/dhcp4/eth1",
suite.Assert().True(r.TypedSpec().RequireUp) }, func(r *network.OperatorSpec) error {
suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().DHCP4.RouteMetric) suite.Assert().Equal(network.OperatorDHCP4, r.TypedSpec().Operator)
suite.Assert().True(r.TypedSpec().RequireUp)
suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().DHCP4.RouteMetric)
switch r.Metadata().ID() { switch r.Metadata().ID() {
case "default/dhcp4/eth0": case "default/dhcp4/eth0":
suite.Assert().Equal("eth0", r.TypedSpec().LinkName) suite.Assert().Equal("eth0", r.TypedSpec().LinkName)
case "default/dhcp4/eth1": case "default/dhcp4/eth1":
suite.Assert().Equal("eth1", r.TypedSpec().LinkName) suite.Assert().Equal("eth1", r.TypedSpec().LinkName)
} }
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *OperatorConfigSuite) TestDefaultDHCPCmdline() { func (suite *OperatorConfigSuite) TestDefaultDHCPCmdline() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.OperatorConfigController{ suite.Require().NoError(
Cmdline: procfs.NewCmdline("ip=172.20.0.2::172.20.0.1:255.255.255.0::eth1:::::"), suite.runtime.RegisterController(
})) &netctrl.OperatorConfigController{
Cmdline: procfs.NewCmdline("ip=172.20.0.2::172.20.0.1:255.255.255.0::eth1:::::"),
},
),
)
suite.startRuntime() suite.startRuntime()
@ -171,46 +190,69 @@ func (suite *OperatorConfigSuite) TestDefaultDHCPCmdline() {
suite.Require().NoError(suite.state.Create(suite.ctx, linkStatus)) suite.Require().NoError(suite.state.Create(suite.ctx, linkStatus))
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertOperators([]string{ func() error {
"default/dhcp4/eth0", return suite.assertOperators(
"default/dhcp4/eth2", []string{
}, func(r *network.OperatorSpec) error { "default/dhcp4/eth0",
suite.Assert().Equal(network.OperatorDHCP4, r.TypedSpec().Operator) "default/dhcp4/eth2",
suite.Assert().True(r.TypedSpec().RequireUp) }, func(r *network.OperatorSpec) error {
suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().DHCP4.RouteMetric) suite.Assert().Equal(network.OperatorDHCP4, r.TypedSpec().Operator)
suite.Assert().True(r.TypedSpec().RequireUp)
suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().DHCP4.RouteMetric)
switch r.Metadata().ID() { switch r.Metadata().ID() {
case "default/dhcp4/eth0": case "default/dhcp4/eth0":
suite.Assert().Equal("eth0", r.TypedSpec().LinkName) suite.Assert().Equal("eth0", r.TypedSpec().LinkName)
case "default/dhcp4/eth2": case "default/dhcp4/eth2":
suite.Assert().Equal("eth2", r.TypedSpec().LinkName) suite.Assert().Equal("eth2", r.TypedSpec().LinkName)
} }
return nil return nil
}) },
})) )
},
),
)
// remove link // remove link
suite.Require().NoError(suite.state.Destroy(suite.ctx, resource.NewMetadata(network.NamespaceName, network.LinkStatusType, "eth2", resource.VersionUndefined))) suite.Require().NoError(
suite.state.Destroy(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.LinkStatusType, "eth2", resource.VersionUndefined),
),
)
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNoOperators([]string{ func() error {
"default/dhcp4/eth2", return suite.assertNoOperators(
}) []string{
})) "default/dhcp4/eth2",
},
)
},
),
)
} }
func (suite *OperatorConfigSuite) TestMachineConfigurationDHCP4() { func (suite *OperatorConfigSuite) TestMachineConfigurationDHCP4() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.OperatorConfigController{ suite.Require().NoError(
Cmdline: procfs.NewCmdline("talos.network.interface.ignore=eth5"), suite.runtime.RegisterController(
})) &netctrl.OperatorConfigController{
Cmdline: procfs.NewCmdline("talos.network.interface.ignore=eth5"),
},
),
)
// add LinkConfig controller to produce link specs based on machine configuration // add LinkConfig controller to produce link specs based on machine configuration
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.LinkConfigController{ suite.Require().NoError(
Cmdline: procfs.NewCmdline("talos.network.interface.ignore=eth5"), suite.runtime.RegisterController(
})) &netctrl.LinkConfigController{
Cmdline: procfs.NewCmdline("talos.network.interface.ignore=eth5"),
},
),
)
suite.startRuntime() suite.startRuntime()
@ -225,97 +267,109 @@ func (suite *OperatorConfigSuite) TestMachineConfigurationDHCP4() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{ ConfigVersion: "v1alpha1",
MachineNetwork: &v1alpha1.NetworkConfig{ MachineConfig: &v1alpha1.MachineConfig{
NetworkInterfaces: []*v1alpha1.Device{ MachineNetwork: &v1alpha1.NetworkConfig{
{ NetworkInterfaces: []*v1alpha1.Device{
DeviceInterface: "eth0", {
}, DeviceInterface: "eth0",
{
DeviceInterface: "eth1",
DeviceDHCP: true,
},
{
DeviceIgnore: true,
DeviceInterface: "eth2",
DeviceDHCP: true,
},
{
DeviceInterface: "eth3",
DeviceDHCP: true,
DeviceDHCPOptions: &v1alpha1.DHCPOptions{
DHCPIPv4: pointer.ToBool(true),
DHCPRouteMetric: 256,
}, },
}, {
{ DeviceInterface: "eth1",
DeviceInterface: "eth4", DeviceDHCP: true,
DeviceVlans: []*v1alpha1.Vlan{ },
{ {
VlanID: 25, DeviceIgnore: true,
VlanDHCP: true, DeviceInterface: "eth2",
}, DeviceDHCP: true,
{ },
VlanID: 26, {
DeviceInterface: "eth3",
DeviceDHCP: true,
DeviceDHCPOptions: &v1alpha1.DHCPOptions{
DHCPIPv4: pointer.ToBool(true),
DHCPRouteMetric: 256,
}, },
}, },
{
DeviceInterface: "eth4",
DeviceVlans: []*v1alpha1.Vlan{
{
VlanID: 25,
VlanDHCP: true,
},
{
VlanID: 26,
},
},
},
{
DeviceInterface: "eth5",
DeviceDHCP: true,
},
}, },
{ },
DeviceInterface: "eth5", },
DeviceDHCP: true, ClusterConfig: &v1alpha1.ClusterConfig{
ControlPlane: &v1alpha1.ControlPlaneConfig{
Endpoint: &v1alpha1.Endpoint{
URL: u,
}, },
}, },
}, },
}, },
ClusterConfig: &v1alpha1.ClusterConfig{ )
ControlPlane: &v1alpha1.ControlPlaneConfig{
Endpoint: &v1alpha1.Endpoint{
URL: u,
},
},
},
})
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertOperators([]string{ func() error {
"configuration/dhcp4/eth1", return suite.assertOperators(
"configuration/dhcp4/eth3", []string{
"configuration/dhcp4/eth4.25", "configuration/dhcp4/eth1",
}, func(r *network.OperatorSpec) error { "configuration/dhcp4/eth3",
suite.Assert().Equal(network.OperatorDHCP4, r.TypedSpec().Operator) "configuration/dhcp4/eth4.25",
suite.Assert().True(r.TypedSpec().RequireUp) }, func(r *network.OperatorSpec) error {
suite.Assert().Equal(network.OperatorDHCP4, r.TypedSpec().Operator)
suite.Assert().True(r.TypedSpec().RequireUp)
switch r.Metadata().ID() { switch r.Metadata().ID() {
case "configuration/dhcp4/eth1": case "configuration/dhcp4/eth1":
suite.Assert().Equal("eth1", r.TypedSpec().LinkName) suite.Assert().Equal("eth1", r.TypedSpec().LinkName)
suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().DHCP4.RouteMetric) suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().DHCP4.RouteMetric)
case "configuration/dhcp4/eth3": case "configuration/dhcp4/eth3":
suite.Assert().Equal("eth3", r.TypedSpec().LinkName) suite.Assert().Equal("eth3", r.TypedSpec().LinkName)
suite.Assert().EqualValues(256, r.TypedSpec().DHCP4.RouteMetric) suite.Assert().EqualValues(256, r.TypedSpec().DHCP4.RouteMetric)
case "configuration/dhcp4/eth4.25": case "configuration/dhcp4/eth4.25":
suite.Assert().Equal("eth4.25", r.TypedSpec().LinkName) suite.Assert().Equal("eth4.25", r.TypedSpec().LinkName)
suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().DHCP4.RouteMetric) suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().DHCP4.RouteMetric)
} }
return nil return nil
}) },
})) )
},
),
)
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNoOperators([]string{ func() error {
"configuration/dhcp4/eth0", return suite.assertNoOperators(
"default/dhcp4/eth0", []string{
"configuration/dhcp4/eth2", "configuration/dhcp4/eth0",
"default/dhcp4/eth2", "default/dhcp4/eth0",
"configuration/dhcp4/eth4.26", "configuration/dhcp4/eth2",
}) "default/dhcp4/eth2",
})) "configuration/dhcp4/eth4.26",
},
)
},
),
)
} }
func (suite *OperatorConfigSuite) TestMachineConfigurationDHCP6() { func (suite *OperatorConfigSuite) TestMachineConfigurationDHCP6() {
@ -326,75 +380,87 @@ func (suite *OperatorConfigSuite) TestMachineConfigurationDHCP6() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{ ConfigVersion: "v1alpha1",
MachineNetwork: &v1alpha1.NetworkConfig{ MachineConfig: &v1alpha1.MachineConfig{
NetworkInterfaces: []*v1alpha1.Device{ MachineNetwork: &v1alpha1.NetworkConfig{
{ NetworkInterfaces: []*v1alpha1.Device{
DeviceInterface: "eth1", {
DeviceDHCP: true, DeviceInterface: "eth1",
DeviceDHCPOptions: &v1alpha1.DHCPOptions{ DeviceDHCP: true,
DHCPIPv4: pointer.ToBool(true), DeviceDHCPOptions: &v1alpha1.DHCPOptions{
DHCPIPv4: pointer.ToBool(true),
},
}, },
}, {
{ DeviceInterface: "eth2",
DeviceInterface: "eth2", DeviceDHCP: true,
DeviceDHCP: true, DeviceDHCPOptions: &v1alpha1.DHCPOptions{
DeviceDHCPOptions: &v1alpha1.DHCPOptions{ DHCPIPv6: pointer.ToBool(true),
DHCPIPv6: pointer.ToBool(true), },
}, },
}, {
{ DeviceInterface: "eth3",
DeviceInterface: "eth3", DeviceDHCP: true,
DeviceDHCP: true, DeviceDHCPOptions: &v1alpha1.DHCPOptions{
DeviceDHCPOptions: &v1alpha1.DHCPOptions{ DHCPIPv6: pointer.ToBool(true),
DHCPIPv6: pointer.ToBool(true), DHCPRouteMetric: 512,
DHCPRouteMetric: 512, },
}, },
}, },
}, },
}, },
}, ClusterConfig: &v1alpha1.ClusterConfig{
ClusterConfig: &v1alpha1.ClusterConfig{ ControlPlane: &v1alpha1.ControlPlaneConfig{
ControlPlane: &v1alpha1.ControlPlaneConfig{ Endpoint: &v1alpha1.Endpoint{
Endpoint: &v1alpha1.Endpoint{ URL: u,
URL: u, },
}, },
}, },
}, },
}) )
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertOperators([]string{ func() error {
"configuration/dhcp6/eth2", return suite.assertOperators(
"configuration/dhcp6/eth3", []string{
}, func(r *network.OperatorSpec) error { "configuration/dhcp6/eth2",
suite.Assert().Equal(network.OperatorDHCP6, r.TypedSpec().Operator) "configuration/dhcp6/eth3",
suite.Assert().True(r.TypedSpec().RequireUp) }, func(r *network.OperatorSpec) error {
suite.Assert().Equal(network.OperatorDHCP6, r.TypedSpec().Operator)
suite.Assert().True(r.TypedSpec().RequireUp)
switch r.Metadata().ID() { switch r.Metadata().ID() {
case "configuration/dhcp6/eth2": case "configuration/dhcp6/eth2":
suite.Assert().Equal("eth2", r.TypedSpec().LinkName) suite.Assert().Equal("eth2", r.TypedSpec().LinkName)
suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().DHCP6.RouteMetric) suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().DHCP6.RouteMetric)
case "configuration/dhcp6/eth3": case "configuration/dhcp6/eth3":
suite.Assert().Equal("eth3", r.TypedSpec().LinkName) suite.Assert().Equal("eth3", r.TypedSpec().LinkName)
suite.Assert().EqualValues(512, r.TypedSpec().DHCP6.RouteMetric) suite.Assert().EqualValues(512, r.TypedSpec().DHCP6.RouteMetric)
} }
return nil return nil
}) },
})) )
},
),
)
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNoOperators([]string{ func() error {
"configuration/dhcp6/eth1", return suite.assertNoOperators(
}) []string{
})) "configuration/dhcp6/eth1",
},
)
},
),
)
} }
func (suite *OperatorConfigSuite) TearDownTest() { func (suite *OperatorConfigSuite) TearDownTest() {
@ -405,17 +471,26 @@ func (suite *OperatorConfigSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ err := suite.state.Create(
ConfigVersion: "v1alpha1", context.Background(), config.NewMachineConfig(
MachineConfig: &v1alpha1.MachineConfig{}, &v1alpha1.Config{
})) ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{},
},
),
)
if state.IsConflictError(err) { if state.IsConflictError(err) {
err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata())
} }
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewLinkStatus(network.ConfigNamespaceName, "bar"))) suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewLinkStatus(network.ConfigNamespaceName, "bar"),
),
)
} }
func TestOperatorConfigSuite(t *testing.T) { func TestOperatorConfigSuite(t *testing.T) {

View File

@ -35,7 +35,7 @@ type OperatorMergeSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -71,7 +71,10 @@ func (suite *OperatorMergeSuite) assertOperators(requiredIDs []string, check fun
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.NamespaceName, network.OperatorSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.OperatorSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -97,7 +100,10 @@ func (suite *OperatorMergeSuite) assertOperators(requiredIDs []string, check fun
} }
func (suite *OperatorMergeSuite) assertNoOperator(id string) error { func (suite *OperatorMergeSuite) assertNoOperator(id string) error {
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.NamespaceName, network.OperatorSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.OperatorSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -139,37 +145,50 @@ func (suite *OperatorMergeSuite) TestMerge() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertOperators([]string{ func() error {
"dhcp4/eth0", return suite.assertOperators(
"dhcp6/eth0", []string{
}, func(r *network.OperatorSpec) error { "dhcp4/eth0",
switch r.Metadata().ID() { "dhcp6/eth0",
case "dhcp4/eth0": }, func(r *network.OperatorSpec) error {
suite.Assert().Equal(*dhcp2.TypedSpec(), *r.TypedSpec()) switch r.Metadata().ID() {
case "dhcp6/eth0": case "dhcp4/eth0":
suite.Assert().Equal(*dhcp6.TypedSpec(), *r.TypedSpec()) suite.Assert().Equal(*dhcp2.TypedSpec(), *r.TypedSpec())
} case "dhcp6/eth0":
suite.Assert().Equal(*dhcp6.TypedSpec(), *r.TypedSpec())
}
return nil return nil
}) },
})) )
},
),
)
suite.Require().NoError(suite.state.Destroy(suite.ctx, dhcp6.Metadata())) suite.Require().NoError(suite.state.Destroy(suite.ctx, dhcp6.Metadata()))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertOperators([]string{ func() error {
"dhcp4/eth0", return suite.assertOperators(
}, func(r *network.OperatorSpec) error { []string{
return nil "dhcp4/eth0",
}) }, func(r *network.OperatorSpec) error {
})) return nil
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( },
func() error { )
return suite.assertNoOperator("dhcp6/eth0") },
})) ),
)
suite.Assert().NoError(
retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
func() error {
return suite.assertNoOperator("dhcp6/eth0")
},
),
)
} }
//nolint:gocyclo //nolint:gocyclo
@ -214,50 +233,75 @@ func (suite *OperatorMergeSuite) TestMergeFlapping() {
eg.Go(flipflop(0)) eg.Go(flipflop(0))
eg.Go(flipflop(1)) eg.Go(flipflop(1))
eg.Go(func() error { eg.Go(
// add/remove finalizer to the merged resource func() error {
for i := 0; i < 1000; i++ { // add/remove finalizer to the merged resource
if err := suite.state.AddFinalizer(suite.ctx, resource.NewMetadata(network.NamespaceName, network.OperatorSpecType, "dhcp4/eth0", resource.VersionUndefined), "foo"); err != nil { for i := 0; i < 1000; i++ {
if !state.IsNotFoundError(err) { if err := suite.state.AddFinalizer(
return err suite.ctx,
resource.NewMetadata(
network.NamespaceName,
network.OperatorSpecType,
"dhcp4/eth0",
resource.VersionUndefined,
),
"foo",
); err != nil {
if !state.IsNotFoundError(err) {
return err
}
continue
} else {
suite.T().Log("finalizer added")
} }
continue time.Sleep(10 * time.Millisecond)
} else {
suite.T().Log("finalizer added")
}
time.Sleep(10 * time.Millisecond) if err := suite.state.RemoveFinalizer(
suite.ctx,
if err := suite.state.RemoveFinalizer(suite.ctx, resource.NewMetadata(network.NamespaceName, network.OperatorSpecType, "dhcp4/eth0", resource.VersionUndefined), "foo"); err != nil { resource.NewMetadata(
if err != nil && !state.IsNotFoundError(err) { network.NamespaceName,
return err network.OperatorSpecType,
"dhcp4/eth0",
resource.VersionUndefined,
),
"foo",
); err != nil {
if err != nil && !state.IsNotFoundError(err) {
return err
}
} }
} }
}
return nil return nil
}) },
)
suite.Require().NoError(eg.Wait()) suite.Require().NoError(eg.Wait())
suite.Assert().NoError(retry.Constant(15*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(15*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertOperators([]string{ func() error {
"dhcp4/eth0", return suite.assertOperators(
}, func(r *network.OperatorSpec) error { []string{
if r.Metadata().Phase() != resource.PhaseRunning { "dhcp4/eth0",
return retry.ExpectedErrorf("resource phase is %s", r.Metadata().Phase()) }, func(r *network.OperatorSpec) error {
} if r.Metadata().Phase() != resource.PhaseRunning {
return retry.ExpectedErrorf("resource phase is %s", r.Metadata().Phase())
}
if *override.TypedSpec() != *r.TypedSpec() { if *override.TypedSpec() != *r.TypedSpec() {
// using retry here, as it might not be reconciled immediately // using retry here, as it might not be reconciled immediately
return retry.ExpectedError(fmt.Errorf("not equal yet")) return retry.ExpectedError(fmt.Errorf("not equal yet"))
} }
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *OperatorMergeSuite) TearDownTest() { func (suite *OperatorMergeSuite) TearDownTest() {
@ -268,7 +312,12 @@ func (suite *OperatorMergeSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewOperatorSpec(network.ConfigNamespaceName, "bar"))) suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewOperatorSpec(network.ConfigNamespaceName, "bar"),
),
)
} }
func TestOperatorMergeSuite(t *testing.T) { func TestOperatorMergeSuite(t *testing.T) {

View File

@ -37,7 +37,7 @@ type OperatorSpecSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -155,9 +155,13 @@ func (suite *OperatorSpecSuite) SetupTest() {
runningOperators = map[string]*mockOperator{} runningOperators = map[string]*mockOperator{}
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.OperatorSpecController{ suite.Require().NoError(
Factory: suite.newOperator, suite.runtime.RegisterController(
})) &netctrl.OperatorSpecController{
Factory: suite.newOperator,
},
),
)
suite.startRuntime() suite.startRuntime()
} }
@ -214,7 +218,10 @@ func (suite *OperatorSpecSuite) assertResources(resourceType resource.Type, requ
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.ConfigNamespaceName, resourceType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.ConfigNamespaceName, resourceType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -255,12 +262,17 @@ func (suite *OperatorSpecSuite) TestScheduling() {
suite.Require().NoError(suite.state.Create(suite.ctx, specVIP)) suite.Require().NoError(suite.state.Create(suite.ctx, specVIP))
// operators shouldn't be running yet, as link state is not known yet // operators shouldn't be running yet, as link state is not known yet
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertRunning(nil, func(op *mockOperator) error { func() error {
return nil return suite.assertRunning(
}) nil, func(op *mockOperator) error {
})) return nil
},
)
},
),
)
linkState := network.NewLinkStatus(network.NamespaceName, "eth0") linkState := network.NewLinkStatus(network.NamespaceName, "eth0")
*linkState.TypedSpec() = network.LinkStatusSpec{ *linkState.TypedSpec() = network.LinkStatusSpec{
@ -270,79 +282,105 @@ func (suite *OperatorSpecSuite) TestScheduling() {
suite.Require().NoError(suite.state.Create(suite.ctx, linkState)) suite.Require().NoError(suite.state.Create(suite.ctx, linkState))
// vip operator should be scheduled now, as VIP operator doesn't require link to be up // vip operator should be scheduled now, as VIP operator doesn't require link to be up
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertRunning([]string{"vip/eth0"}, func(op *mockOperator) error { func() error {
suite.Assert().Equal(netaddr.MustParseIP("1.2.3.4"), op.spec.VIP.IP) return suite.assertRunning(
[]string{"vip/eth0"}, func(op *mockOperator) error {
suite.Assert().Equal(netaddr.MustParseIP("1.2.3.4"), op.spec.VIP.IP)
return nil return nil
}) },
})) )
},
),
)
_, err := suite.state.UpdateWithConflicts(suite.ctx, linkState.Metadata(), func(r resource.Resource) error { _, err := suite.state.UpdateWithConflicts(
r.(*network.LinkStatus).TypedSpec().OperationalState = nethelpers.OperStateUp suite.ctx, linkState.Metadata(), func(r resource.Resource) error {
r.(*network.LinkStatus).TypedSpec().OperationalState = nethelpers.OperStateUp
return nil return nil
}) },
)
suite.Require().NoError(err) suite.Require().NoError(err)
// now all operators should be scheduled // now all operators should be scheduled
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertRunning([]string{"dhcp4/eth0", "vip/eth0"}, func(op *mockOperator) error { func() error {
switch op.spec.Operator { //nolint:exhaustive return suite.assertRunning(
case network.OperatorDHCP4: []string{"dhcp4/eth0", "vip/eth0"}, func(op *mockOperator) error {
suite.Assert().EqualValues(1024, op.spec.DHCP4.RouteMetric) switch op.spec.Operator { //nolint:exhaustive
case network.OperatorVIP: case network.OperatorDHCP4:
suite.Assert().Equal(netaddr.MustParseIP("1.2.3.4"), op.spec.VIP.IP) suite.Assert().EqualValues(1024, op.spec.DHCP4.RouteMetric)
default: case network.OperatorVIP:
panic("unreachable") suite.Assert().Equal(netaddr.MustParseIP("1.2.3.4"), op.spec.VIP.IP)
} default:
panic("unreachable")
}
return nil return nil
}) },
})) )
},
),
)
// change the spec, operator should be rescheduled // change the spec, operator should be rescheduled
_, err = suite.state.UpdateWithConflicts(suite.ctx, specVIP.Metadata(), func(r resource.Resource) error { _, err = suite.state.UpdateWithConflicts(
r.(*network.OperatorSpec).TypedSpec().VIP.IP = netaddr.MustParseIP("3.4.5.6") suite.ctx, specVIP.Metadata(), func(r resource.Resource) error {
r.(*network.OperatorSpec).TypedSpec().VIP.IP = netaddr.MustParseIP("3.4.5.6")
return nil return nil
}) },
)
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertRunning([]string{"dhcp4/eth0", "vip/eth0"}, func(op *mockOperator) error { func() error {
switch op.spec.Operator { //nolint:exhaustive return suite.assertRunning(
case network.OperatorDHCP4: []string{"dhcp4/eth0", "vip/eth0"}, func(op *mockOperator) error {
suite.Assert().EqualValues(1024, op.spec.DHCP4.RouteMetric) switch op.spec.Operator { //nolint:exhaustive
case network.OperatorVIP: case network.OperatorDHCP4:
if op.spec.VIP.IP.Compare(netaddr.MustParseIP("3.4.5.6")) != 0 { suite.Assert().EqualValues(1024, op.spec.DHCP4.RouteMetric)
return retry.ExpectedErrorf("unexpected vip: %s", op.spec.VIP.IP) case network.OperatorVIP:
} if op.spec.VIP.IP.Compare(netaddr.MustParseIP("3.4.5.6")) != 0 {
default: return retry.ExpectedErrorf("unexpected vip: %s", op.spec.VIP.IP)
panic("unreachable") }
} default:
panic("unreachable")
}
return nil return nil
}) },
})) )
},
),
)
// bring down the interface, operator should be stopped // bring down the interface, operator should be stopped
_, err = suite.state.UpdateWithConflicts(suite.ctx, linkState.Metadata(), func(r resource.Resource) error { _, err = suite.state.UpdateWithConflicts(
r.(*network.LinkStatus).TypedSpec().OperationalState = nethelpers.OperStateDown suite.ctx, linkState.Metadata(), func(r resource.Resource) error {
r.(*network.LinkStatus).TypedSpec().OperationalState = nethelpers.OperStateDown
return nil return nil
}) },
)
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertRunning([]string{"vip/eth0"}, func(op *mockOperator) error { func() error {
return nil return suite.assertRunning(
}) []string{"vip/eth0"}, func(op *mockOperator) error {
})) return nil
},
)
},
),
)
} }
func (suite *OperatorSpecSuite) TestPanic() { func (suite *OperatorSpecSuite) TestPanic() {
@ -366,25 +404,35 @@ func (suite *OperatorSpecSuite) TestPanic() {
suite.Require().NoError(suite.state.Create(suite.ctx, linkState)) suite.Require().NoError(suite.state.Create(suite.ctx, linkState))
// DHCP6 operator should panic and then restart // DHCP6 operator should panic and then restart
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertRunning([]string{"dhcp6/eth0"}, func(op *mockOperator) error { return nil }) func() error {
})) return suite.assertRunning([]string{"dhcp6/eth0"}, func(op *mockOperator) error { return nil })
},
),
)
// bring down the interface, operator should be stopped // bring down the interface, operator should be stopped
_, err := suite.state.UpdateWithConflicts(suite.ctx, linkState.Metadata(), func(r resource.Resource) error { _, err := suite.state.UpdateWithConflicts(
r.(*network.LinkStatus).TypedSpec().OperationalState = nethelpers.OperStateDown suite.ctx, linkState.Metadata(), func(r resource.Resource) error {
r.(*network.LinkStatus).TypedSpec().OperationalState = nethelpers.OperStateDown
return nil return nil
}) },
)
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertRunning(nil, func(op *mockOperator) error { func() error {
return nil return suite.assertRunning(
}) nil, func(op *mockOperator) error {
})) return nil
},
)
},
),
)
} }
func (suite *OperatorSpecSuite) TestOperatorOutputs() { func (suite *OperatorSpecSuite) TestOperatorOutputs() {
@ -407,12 +455,17 @@ func (suite *OperatorSpecSuite) TestOperatorOutputs() {
suite.Require().NoError(suite.state.Create(suite.ctx, linkState)) suite.Require().NoError(suite.state.Create(suite.ctx, linkState))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertRunning([]string{"dhcp4/eth0"}, func(op *mockOperator) error { func() error {
return nil return suite.assertRunning(
}) []string{"dhcp4/eth0"}, func(op *mockOperator) error {
})) return nil
},
)
},
),
)
// pretend dhcp has some specs ready // pretend dhcp has some specs ready
runningOperatorsMu.Lock() runningOperatorsMu.Lock()
@ -447,18 +500,27 @@ func (suite *OperatorSpecSuite) TestOperatorOutputs() {
dhcpMock.notify() dhcpMock.notify()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertResources(network.AddressSpecType, []string{"dhcp4/eth0/eth0/10.5.0.2/24"}) func() error {
})) return suite.assertResources(network.AddressSpecType, []string{"dhcp4/eth0/eth0/10.5.0.2/24"})
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( },
func() error { ),
return suite.assertResources(network.LinkSpecType, []string{"dhcp4/eth0/eth0"}) )
})) suite.Assert().NoError(
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
func() error { func() error {
return suite.assertResources(network.HostnameSpecType, []string{"dhcp4/eth0/hostname"}) return suite.assertResources(network.LinkSpecType, []string{"dhcp4/eth0/eth0"})
})) },
),
)
suite.Assert().NoError(
retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
func() error {
return suite.assertResources(network.HostnameSpecType, []string{"dhcp4/eth0/hostname"})
},
),
)
// update specs // update specs
dhcpMock.mu.Lock() dhcpMock.mu.Lock()
@ -476,10 +538,13 @@ func (suite *OperatorSpecSuite) TestOperatorOutputs() {
dhcpMock.notify() dhcpMock.notify()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertResources(network.AddressSpecType, []string{"dhcp4/eth0/eth0/10.5.0.3/24"}) func() error {
})) return suite.assertResources(network.AddressSpecType, []string{"dhcp4/eth0/eth0/10.5.0.3/24"})
},
),
)
} }
func (suite *OperatorSpecSuite) TearDownTest() { func (suite *OperatorSpecSuite) TearDownTest() {
@ -490,7 +555,12 @@ func (suite *OperatorSpecSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewOperatorSpec(network.NamespaceName, "bar"))) suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewOperatorSpec(network.NamespaceName, "bar"),
),
)
} }
func TestOperatorSpecSuite(t *testing.T) { func TestOperatorSpecSuite(t *testing.T) {

View File

@ -38,7 +38,7 @@ type OperatorVIPConfigSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -63,14 +63,20 @@ func (suite *OperatorVIPConfigSuite) startRuntime() {
}() }()
} }
func (suite *OperatorVIPConfigSuite) assertOperators(requiredIDs []string, check func(*network.OperatorSpec) error) error { func (suite *OperatorVIPConfigSuite) assertOperators(
requiredIDs []string,
check func(*network.OperatorSpec) error,
) error {
missingIDs := make(map[string]struct{}, len(requiredIDs)) missingIDs := make(map[string]struct{}, len(requiredIDs))
for _, id := range requiredIDs { for _, id := range requiredIDs {
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.ConfigNamespaceName, network.OperatorSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.ConfigNamespaceName, network.OperatorSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -103,76 +109,86 @@ func (suite *OperatorVIPConfigSuite) TestMachineConfigurationVIP() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{ ConfigVersion: "v1alpha1",
MachineNetwork: &v1alpha1.NetworkConfig{ MachineConfig: &v1alpha1.MachineConfig{
NetworkInterfaces: []*v1alpha1.Device{ MachineNetwork: &v1alpha1.NetworkConfig{
{ NetworkInterfaces: []*v1alpha1.Device{
DeviceInterface: "eth1", {
DeviceDHCP: true, DeviceInterface: "eth1",
DeviceVIPConfig: &v1alpha1.DeviceVIPConfig{ DeviceDHCP: true,
SharedIP: "2.3.4.5", DeviceVIPConfig: &v1alpha1.DeviceVIPConfig{
SharedIP: "2.3.4.5",
},
}, },
}, {
{ DeviceInterface: "eth2",
DeviceInterface: "eth2", DeviceDHCP: true,
DeviceDHCP: true, DeviceVIPConfig: &v1alpha1.DeviceVIPConfig{
DeviceVIPConfig: &v1alpha1.DeviceVIPConfig{ SharedIP: "fd7a:115c:a1e0:ab12:4843:cd96:6277:2302",
SharedIP: "fd7a:115c:a1e0:ab12:4843:cd96:6277:2302", },
}, },
}, {
{ DeviceInterface: "eth3",
DeviceInterface: "eth3", DeviceDHCP: true,
DeviceDHCP: true, DeviceVlans: []*v1alpha1.Vlan{
DeviceVlans: []*v1alpha1.Vlan{ {
{ VlanID: 26,
VlanID: 26, VlanVIP: &v1alpha1.DeviceVIPConfig{
VlanVIP: &v1alpha1.DeviceVIPConfig{ SharedIP: "5.5.4.4",
SharedIP: "5.5.4.4", },
}, },
}, },
}, },
}, },
}, },
}, },
}, ClusterConfig: &v1alpha1.ClusterConfig{
ClusterConfig: &v1alpha1.ClusterConfig{ ControlPlane: &v1alpha1.ControlPlaneConfig{
ControlPlane: &v1alpha1.ControlPlaneConfig{ Endpoint: &v1alpha1.Endpoint{
Endpoint: &v1alpha1.Endpoint{ URL: u,
URL: u, },
}, },
}, },
}, },
}) )
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertOperators([]string{ func() error {
"configuration/vip/eth1", return suite.assertOperators(
"configuration/vip/eth2", []string{
"configuration/vip/eth3.26", "configuration/vip/eth1",
}, func(r *network.OperatorSpec) error { "configuration/vip/eth2",
suite.Assert().Equal(network.OperatorVIP, r.TypedSpec().Operator) "configuration/vip/eth3.26",
suite.Assert().True(r.TypedSpec().RequireUp) }, func(r *network.OperatorSpec) error {
suite.Assert().Equal(network.OperatorVIP, r.TypedSpec().Operator)
suite.Assert().True(r.TypedSpec().RequireUp)
switch r.Metadata().ID() { switch r.Metadata().ID() {
case "configuration/vip/eth1": case "configuration/vip/eth1":
suite.Assert().Equal("eth1", r.TypedSpec().LinkName) suite.Assert().Equal("eth1", r.TypedSpec().LinkName)
suite.Assert().EqualValues(netaddr.MustParseIP("2.3.4.5"), r.TypedSpec().VIP.IP) suite.Assert().EqualValues(netaddr.MustParseIP("2.3.4.5"), r.TypedSpec().VIP.IP)
case "configuration/vip/eth2": case "configuration/vip/eth2":
suite.Assert().Equal("eth2", r.TypedSpec().LinkName) suite.Assert().Equal("eth2", r.TypedSpec().LinkName)
suite.Assert().EqualValues(netaddr.MustParseIP("fd7a:115c:a1e0:ab12:4843:cd96:6277:2302"), r.TypedSpec().VIP.IP) suite.Assert().EqualValues(
case "configuration/vip/eth3.26": netaddr.MustParseIP("fd7a:115c:a1e0:ab12:4843:cd96:6277:2302"),
suite.Assert().Equal("eth3.26", r.TypedSpec().LinkName) r.TypedSpec().VIP.IP,
suite.Assert().EqualValues(netaddr.MustParseIP("5.5.4.4"), r.TypedSpec().VIP.IP) )
} case "configuration/vip/eth3.26":
suite.Assert().Equal("eth3.26", r.TypedSpec().LinkName)
suite.Assert().EqualValues(netaddr.MustParseIP("5.5.4.4"), r.TypedSpec().VIP.IP)
}
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *OperatorVIPConfigSuite) TearDownTest() { func (suite *OperatorVIPConfigSuite) TearDownTest() {
@ -183,17 +199,26 @@ func (suite *OperatorVIPConfigSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ err := suite.state.Create(
ConfigVersion: "v1alpha1", context.Background(), config.NewMachineConfig(
MachineConfig: &v1alpha1.MachineConfig{}, &v1alpha1.Config{
})) ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{},
},
),
)
if state.IsConflictError(err) { if state.IsConflictError(err) {
err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata())
} }
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewLinkStatus(network.ConfigNamespaceName, "bar"))) suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewLinkStatus(network.ConfigNamespaceName, "bar"),
),
)
} }
func TestOperatorVIPConfigSuite(t *testing.T) { func TestOperatorVIPConfigSuite(t *testing.T) {

View File

@ -45,7 +45,7 @@ type PlatformConfigSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -72,14 +72,22 @@ func (suite *PlatformConfigSuite) startRuntime() {
}() }()
} }
func (suite *PlatformConfigSuite) assertResources(resourceNamespace resource.Namespace, resourceType resource.Type, requiredIDs []string, check func(resource.Resource) error) error { func (suite *PlatformConfigSuite) assertResources(
resourceNamespace resource.Namespace,
resourceType resource.Type,
requiredIDs []string,
check func(resource.Resource) error,
) error {
missingIDs := make(map[string]struct{}, len(requiredIDs)) missingIDs := make(map[string]struct{}, len(requiredIDs))
for _, id := range requiredIDs { for _, id := range requiredIDs {
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(resourceNamespace, resourceType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(resourceNamespace, resourceType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -102,7 +110,10 @@ func (suite *PlatformConfigSuite) assertResources(resourceNamespace resource.Nam
} }
func (suite *PlatformConfigSuite) assertNoResource(resourceType resource.Type, id string) error { func (suite *PlatformConfigSuite) assertNoResource(resourceType resource.Type, id string) error {
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.ConfigNamespaceName, resourceType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.ConfigNamespaceName, resourceType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -121,261 +132,360 @@ func (suite *PlatformConfigSuite) TestNoPlatform() {
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNoResource(network.HostnameSpecType, "platform/hostname") func() error {
})) return suite.assertNoResource(network.HostnameSpecType, "platform/hostname")
},
),
)
} }
func (suite *PlatformConfigSuite) TestPlatformMockHostname() { func (suite *PlatformConfigSuite) TestPlatformMockHostname() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.PlatformConfigController{ suite.Require().NoError(
V1alpha1Platform: &platformMock{hostname: []byte("talos-e2e-897b4e49-gcp-controlplane-jvcnl.c.talos-testbed.internal")}, suite.runtime.RegisterController(
StatePath: suite.statePath, &netctrl.PlatformConfigController{
})) V1alpha1Platform: &platformMock{hostname: []byte("talos-e2e-897b4e49-gcp-controlplane-jvcnl.c.talos-testbed.internal")},
StatePath: suite.statePath,
},
),
)
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertResources(network.ConfigNamespaceName, network.HostnameSpecType, []string{ func() error {
"platform/hostname", return suite.assertResources(
}, func(r resource.Resource) error { network.ConfigNamespaceName, network.HostnameSpecType, []string{
spec := r.(*network.HostnameSpec).TypedSpec() "platform/hostname",
}, func(r resource.Resource) error {
spec := r.(*network.HostnameSpec).TypedSpec()
suite.Assert().Equal("talos-e2e-897b4e49-gcp-controlplane-jvcnl", spec.Hostname) suite.Assert().Equal("talos-e2e-897b4e49-gcp-controlplane-jvcnl", spec.Hostname)
suite.Assert().Equal("c.talos-testbed.internal", spec.Domainname) suite.Assert().Equal("c.talos-testbed.internal", spec.Domainname)
suite.Assert().Equal(network.ConfigPlatform, spec.ConfigLayer) suite.Assert().Equal(network.ConfigPlatform, spec.ConfigLayer)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *PlatformConfigSuite) TestPlatformMockHostnameNoDomain() { func (suite *PlatformConfigSuite) TestPlatformMockHostnameNoDomain() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.PlatformConfigController{ suite.Require().NoError(
V1alpha1Platform: &platformMock{hostname: []byte("talos-e2e-897b4e49-gcp-controlplane-jvcnl")}, suite.runtime.RegisterController(
StatePath: suite.statePath, &netctrl.PlatformConfigController{
})) V1alpha1Platform: &platformMock{hostname: []byte("talos-e2e-897b4e49-gcp-controlplane-jvcnl")},
StatePath: suite.statePath,
},
),
)
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertResources(network.ConfigNamespaceName, network.HostnameSpecType, []string{ func() error {
"platform/hostname", return suite.assertResources(
}, func(r resource.Resource) error { network.ConfigNamespaceName, network.HostnameSpecType, []string{
spec := r.(*network.HostnameSpec).TypedSpec() "platform/hostname",
}, func(r resource.Resource) error {
spec := r.(*network.HostnameSpec).TypedSpec()
suite.Assert().Equal("talos-e2e-897b4e49-gcp-controlplane-jvcnl", spec.Hostname) suite.Assert().Equal("talos-e2e-897b4e49-gcp-controlplane-jvcnl", spec.Hostname)
suite.Assert().Equal("", spec.Domainname) suite.Assert().Equal("", spec.Domainname)
suite.Assert().Equal(network.ConfigPlatform, spec.ConfigLayer) suite.Assert().Equal(network.ConfigPlatform, spec.ConfigLayer)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *PlatformConfigSuite) TestPlatformMockAddresses() { func (suite *PlatformConfigSuite) TestPlatformMockAddresses() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.PlatformConfigController{ suite.Require().NoError(
V1alpha1Platform: &platformMock{ suite.runtime.RegisterController(
addresses: []netaddr.IPPrefix{netaddr.MustParseIPPrefix("192.168.1.24/24"), netaddr.MustParseIPPrefix("2001:fd::3/64")}, &netctrl.PlatformConfigController{
}, V1alpha1Platform: &platformMock{
StatePath: suite.statePath, addresses: []netaddr.IPPrefix{
})) netaddr.MustParseIPPrefix("192.168.1.24/24"),
netaddr.MustParseIPPrefix("2001:fd::3/64"),
},
},
StatePath: suite.statePath,
},
),
)
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertResources(network.ConfigNamespaceName, network.AddressSpecType, []string{ func() error {
"platform/eth0/192.168.1.24/24", return suite.assertResources(
"platform/eth0/2001:fd::3/64", network.ConfigNamespaceName, network.AddressSpecType, []string{
}, func(r resource.Resource) error { "platform/eth0/192.168.1.24/24",
spec := r.(*network.AddressSpec).TypedSpec() "platform/eth0/2001:fd::3/64",
}, func(r resource.Resource) error {
spec := r.(*network.AddressSpec).TypedSpec()
switch r.Metadata().ID() { switch r.Metadata().ID() {
case "platform/eth0/192.168.1.24/24": case "platform/eth0/192.168.1.24/24":
suite.Assert().Equal(nethelpers.FamilyInet4, spec.Family) suite.Assert().Equal(nethelpers.FamilyInet4, spec.Family)
suite.Assert().Equal("192.168.1.24/24", spec.Address.String()) suite.Assert().Equal("192.168.1.24/24", spec.Address.String())
case "platform/eth0/2001:fd::3/64": case "platform/eth0/2001:fd::3/64":
suite.Assert().Equal(nethelpers.FamilyInet6, spec.Family) suite.Assert().Equal(nethelpers.FamilyInet6, spec.Family)
suite.Assert().Equal("2001:fd::3/64", spec.Address.String()) suite.Assert().Equal("2001:fd::3/64", spec.Address.String())
} }
suite.Assert().Equal(network.ConfigPlatform, spec.ConfigLayer) suite.Assert().Equal(network.ConfigPlatform, spec.ConfigLayer)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *PlatformConfigSuite) TestPlatformMockLinks() { func (suite *PlatformConfigSuite) TestPlatformMockLinks() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.PlatformConfigController{ suite.Require().NoError(
V1alpha1Platform: &platformMock{ suite.runtime.RegisterController(
linksUp: []string{"eth0", "eth1"}, &netctrl.PlatformConfigController{
}, V1alpha1Platform: &platformMock{
StatePath: suite.statePath, linksUp: []string{"eth0", "eth1"},
})) },
StatePath: suite.statePath,
},
),
)
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertResources(network.ConfigNamespaceName, network.LinkSpecType, []string{ func() error {
"platform/eth0", return suite.assertResources(
"platform/eth1", network.ConfigNamespaceName, network.LinkSpecType, []string{
}, func(r resource.Resource) error { "platform/eth0",
spec := r.(*network.LinkSpec).TypedSpec() "platform/eth1",
}, func(r resource.Resource) error {
spec := r.(*network.LinkSpec).TypedSpec()
suite.Assert().True(spec.Up) suite.Assert().True(spec.Up)
suite.Assert().Equal(network.ConfigPlatform, spec.ConfigLayer) suite.Assert().Equal(network.ConfigPlatform, spec.ConfigLayer)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *PlatformConfigSuite) TestPlatformMockRoutes() { func (suite *PlatformConfigSuite) TestPlatformMockRoutes() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.PlatformConfigController{ suite.Require().NoError(
V1alpha1Platform: &platformMock{ suite.runtime.RegisterController(
defaultRoutes: []netaddr.IP{netaddr.MustParseIP("10.0.0.1")}, &netctrl.PlatformConfigController{
}, V1alpha1Platform: &platformMock{
StatePath: suite.statePath, defaultRoutes: []netaddr.IP{netaddr.MustParseIP("10.0.0.1")},
})) },
StatePath: suite.statePath,
},
),
)
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertResources(network.ConfigNamespaceName, network.RouteSpecType, []string{ func() error {
"platform/inet4/10.0.0.1//1024", return suite.assertResources(
}, func(r resource.Resource) error { network.ConfigNamespaceName, network.RouteSpecType, []string{
spec := r.(*network.RouteSpec).TypedSpec() "platform/inet4/10.0.0.1//1024",
}, func(r resource.Resource) error {
spec := r.(*network.RouteSpec).TypedSpec()
suite.Assert().Equal("10.0.0.1", spec.Gateway.String()) suite.Assert().Equal("10.0.0.1", spec.Gateway.String())
suite.Assert().Equal(network.ConfigPlatform, spec.ConfigLayer) suite.Assert().Equal(network.ConfigPlatform, spec.ConfigLayer)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *PlatformConfigSuite) TestPlatformMockOperators() { func (suite *PlatformConfigSuite) TestPlatformMockOperators() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.PlatformConfigController{ suite.Require().NoError(
V1alpha1Platform: &platformMock{ suite.runtime.RegisterController(
dhcp4Links: []string{"eth1", "eth2"}, &netctrl.PlatformConfigController{
}, V1alpha1Platform: &platformMock{
StatePath: suite.statePath, dhcp4Links: []string{"eth1", "eth2"},
})) },
StatePath: suite.statePath,
},
),
)
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertResources(network.ConfigNamespaceName, network.OperatorSpecType, []string{ func() error {
"platform/dhcp4/eth1", return suite.assertResources(
"platform/dhcp4/eth2", network.ConfigNamespaceName, network.OperatorSpecType, []string{
}, func(r resource.Resource) error { "platform/dhcp4/eth1",
spec := r.(*network.OperatorSpec).TypedSpec() "platform/dhcp4/eth2",
}, func(r resource.Resource) error {
spec := r.(*network.OperatorSpec).TypedSpec()
suite.Assert().Equal(network.OperatorDHCP4, spec.Operator) suite.Assert().Equal(network.OperatorDHCP4, spec.Operator)
suite.Assert().Equal(network.ConfigPlatform, spec.ConfigLayer) suite.Assert().Equal(network.ConfigPlatform, spec.ConfigLayer)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *PlatformConfigSuite) TestPlatformMockResolvers() { func (suite *PlatformConfigSuite) TestPlatformMockResolvers() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.PlatformConfigController{ suite.Require().NoError(
V1alpha1Platform: &platformMock{ suite.runtime.RegisterController(
resolvers: []netaddr.IP{netaddr.MustParseIP("1.1.1.1")}, &netctrl.PlatformConfigController{
}, V1alpha1Platform: &platformMock{
StatePath: suite.statePath, resolvers: []netaddr.IP{netaddr.MustParseIP("1.1.1.1")},
})) },
StatePath: suite.statePath,
},
),
)
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertResources(network.ConfigNamespaceName, network.ResolverSpecType, []string{ func() error {
"platform/resolvers", return suite.assertResources(
}, func(r resource.Resource) error { network.ConfigNamespaceName, network.ResolverSpecType, []string{
spec := r.(*network.ResolverSpec).TypedSpec() "platform/resolvers",
}, func(r resource.Resource) error {
spec := r.(*network.ResolverSpec).TypedSpec()
suite.Assert().Equal("[1.1.1.1]", fmt.Sprintf("%s", spec.DNSServers)) suite.Assert().Equal("[1.1.1.1]", fmt.Sprintf("%s", spec.DNSServers))
suite.Assert().Equal(network.ConfigPlatform, spec.ConfigLayer) suite.Assert().Equal(network.ConfigPlatform, spec.ConfigLayer)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *PlatformConfigSuite) TestPlatformMockTimeServers() { func (suite *PlatformConfigSuite) TestPlatformMockTimeServers() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.PlatformConfigController{ suite.Require().NoError(
V1alpha1Platform: &platformMock{ suite.runtime.RegisterController(
timeServers: []string{"pool.ntp.org"}, &netctrl.PlatformConfigController{
}, V1alpha1Platform: &platformMock{
StatePath: suite.statePath, timeServers: []string{"pool.ntp.org"},
})) },
StatePath: suite.statePath,
},
),
)
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertResources(network.ConfigNamespaceName, network.TimeServerSpecType, []string{ func() error {
"platform/timeservers", return suite.assertResources(
}, func(r resource.Resource) error { network.ConfigNamespaceName, network.TimeServerSpecType, []string{
spec := r.(*network.TimeServerSpec).TypedSpec() "platform/timeservers",
}, func(r resource.Resource) error {
spec := r.(*network.TimeServerSpec).TypedSpec()
suite.Assert().Equal("[pool.ntp.org]", fmt.Sprintf("%s", spec.NTPServers)) suite.Assert().Equal("[pool.ntp.org]", fmt.Sprintf("%s", spec.NTPServers))
suite.Assert().Equal(network.ConfigPlatform, spec.ConfigLayer) suite.Assert().Equal(network.ConfigPlatform, spec.ConfigLayer)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *PlatformConfigSuite) TestPlatformMockExternalIPs() { func (suite *PlatformConfigSuite) TestPlatformMockExternalIPs() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.PlatformConfigController{ suite.Require().NoError(
V1alpha1Platform: &platformMock{externalIPs: []netaddr.IP{netaddr.MustParseIP("10.3.4.5"), netaddr.MustParseIP("2001:470:6d:30e:96f4:4219:5733:b860")}}, suite.runtime.RegisterController(
StatePath: suite.statePath, &netctrl.PlatformConfigController{
})) V1alpha1Platform: &platformMock{
externalIPs: []netaddr.IP{
netaddr.MustParseIP("10.3.4.5"),
netaddr.MustParseIP("2001:470:6d:30e:96f4:4219:5733:b860"),
},
},
StatePath: suite.statePath,
},
),
)
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertResources(network.NamespaceName, network.AddressStatusType, []string{ func() error {
"external/10.3.4.5/32", return suite.assertResources(
"external/2001:470:6d:30e:96f4:4219:5733:b860/128", network.NamespaceName, network.AddressStatusType, []string{
}, func(r resource.Resource) error { "external/10.3.4.5/32",
spec := r.(*network.AddressStatus).TypedSpec() "external/2001:470:6d:30e:96f4:4219:5733:b860/128",
}, func(r resource.Resource) error {
spec := r.(*network.AddressStatus).TypedSpec()
suite.Assert().Equal("external", spec.LinkName) suite.Assert().Equal("external", spec.LinkName)
suite.Assert().Equal(nethelpers.ScopeGlobal, spec.Scope) suite.Assert().Equal(nethelpers.ScopeGlobal, spec.Scope)
if r.Metadata().ID() == "external/10.3.4.5/32" { if r.Metadata().ID() == "external/10.3.4.5/32" {
suite.Assert().Equal(nethelpers.FamilyInet4, spec.Family) suite.Assert().Equal(nethelpers.FamilyInet4, spec.Family)
} else { } else {
suite.Assert().Equal(nethelpers.FamilyInet6, spec.Family) suite.Assert().Equal(nethelpers.FamilyInet6, spec.Family)
} }
return nil return nil
}) },
})) )
},
),
)
} }
const sampleStoredConfig = "addresses: []\nlinks: []\nroutes: []\nhostnames:\n - hostname: talos-e2e-897b4e49-gcp-controlplane-jvcnl\n domainname: \"\"\n layer: default\nresolvers: []\ntimeServers: []\noperators: []\nexternalIPs:\n - 10.3.4.5\n - 2001:470:6d:30e:96f4:4219:5733:b860\n" //nolint:lll const sampleStoredConfig = "addresses: []\nlinks: []\nroutes: []\nhostnames:\n - hostname: talos-e2e-897b4e49-gcp-controlplane-jvcnl\n domainname: \"\"\n layer: default\nresolvers: []\ntimeServers: []\noperators: []\nexternalIPs:\n - 10.3.4.5\n - 2001:470:6d:30e:96f4:4219:5733:b860\n" //nolint:lll
func (suite *PlatformConfigSuite) TestStoreConfig() { func (suite *PlatformConfigSuite) TestStoreConfig() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.PlatformConfigController{ suite.Require().NoError(
V1alpha1Platform: &platformMock{ suite.runtime.RegisterController(
hostname: []byte("talos-e2e-897b4e49-gcp-controlplane-jvcnl"), &netctrl.PlatformConfigController{
externalIPs: []netaddr.IP{netaddr.MustParseIP("10.3.4.5"), netaddr.MustParseIP("2001:470:6d:30e:96f4:4219:5733:b860")}, V1alpha1Platform: &platformMock{
}, hostname: []byte("talos-e2e-897b4e49-gcp-controlplane-jvcnl"),
StatePath: suite.statePath, externalIPs: []netaddr.IP{
})) netaddr.MustParseIP("10.3.4.5"),
netaddr.MustParseIP("2001:470:6d:30e:96f4:4219:5733:b860"),
},
},
StatePath: suite.statePath,
},
),
)
suite.startRuntime() suite.startRuntime()
@ -383,75 +493,98 @@ func (suite *PlatformConfigSuite) TestStoreConfig() {
suite.Assert().NoError(suite.state.Create(suite.ctx, stateMount)) suite.Assert().NoError(suite.state.Create(suite.ctx, stateMount))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
contents, err := os.ReadFile(filepath.Join(suite.statePath, constants.PlatformNetworkConfigFilename)) func() error {
if err != nil { contents, err := os.ReadFile(filepath.Join(suite.statePath, constants.PlatformNetworkConfigFilename))
if os.IsNotExist(err) { if err != nil {
return retry.ExpectedError(err) if os.IsNotExist(err) {
return retry.ExpectedError(err)
}
return err
} }
return err suite.Assert().Equal(sampleStoredConfig, string(contents))
}
suite.Assert().Equal(sampleStoredConfig, string(contents)) return nil
},
return nil ),
})) )
} }
func (suite *PlatformConfigSuite) TestLoadConfig() { func (suite *PlatformConfigSuite) TestLoadConfig() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.PlatformConfigController{ suite.Require().NoError(
V1alpha1Platform: &platformMock{ suite.runtime.RegisterController(
noData: true, &netctrl.PlatformConfigController{
}, V1alpha1Platform: &platformMock{
StatePath: suite.statePath, noData: true,
})) },
StatePath: suite.statePath,
},
),
)
suite.startRuntime() suite.startRuntime()
suite.Require().NoError(os.WriteFile(filepath.Join(suite.statePath, constants.PlatformNetworkConfigFilename), []byte(sampleStoredConfig), 0o400)) suite.Require().NoError(
os.WriteFile(
filepath.Join(suite.statePath, constants.PlatformNetworkConfigFilename),
[]byte(sampleStoredConfig),
0o400,
),
)
stateMount := runtimeres.NewMountStatus(v1alpha1.NamespaceName, constants.StatePartitionLabel) stateMount := runtimeres.NewMountStatus(v1alpha1.NamespaceName, constants.StatePartitionLabel)
suite.Assert().NoError(suite.state.Create(suite.ctx, stateMount)) suite.Assert().NoError(suite.state.Create(suite.ctx, stateMount))
// controller should pick up cached network configuration // controller should pick up cached network configuration
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertResources(network.NamespaceName, network.AddressStatusType, []string{ func() error {
"external/10.3.4.5/32", return suite.assertResources(
"external/2001:470:6d:30e:96f4:4219:5733:b860/128", network.NamespaceName, network.AddressStatusType, []string{
}, func(r resource.Resource) error { "external/10.3.4.5/32",
spec := r.(*network.AddressStatus).TypedSpec() "external/2001:470:6d:30e:96f4:4219:5733:b860/128",
}, func(r resource.Resource) error {
spec := r.(*network.AddressStatus).TypedSpec()
suite.Assert().Equal("external", spec.LinkName) suite.Assert().Equal("external", spec.LinkName)
suite.Assert().Equal(nethelpers.ScopeGlobal, spec.Scope) suite.Assert().Equal(nethelpers.ScopeGlobal, spec.Scope)
if r.Metadata().ID() == "external/10.3.4.5/32" { if r.Metadata().ID() == "external/10.3.4.5/32" {
suite.Assert().Equal(nethelpers.FamilyInet4, spec.Family) suite.Assert().Equal(nethelpers.FamilyInet4, spec.Family)
} else { } else {
suite.Assert().Equal(nethelpers.FamilyInet6, spec.Family) suite.Assert().Equal(nethelpers.FamilyInet6, spec.Family)
} }
return nil return nil
}) },
})) )
},
),
)
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertResources(network.ConfigNamespaceName, network.HostnameSpecType, []string{ func() error {
"platform/hostname", return suite.assertResources(
}, func(r resource.Resource) error { network.ConfigNamespaceName, network.HostnameSpecType, []string{
spec := r.(*network.HostnameSpec).TypedSpec() "platform/hostname",
}, func(r resource.Resource) error {
spec := r.(*network.HostnameSpec).TypedSpec()
suite.Assert().Equal("talos-e2e-897b4e49-gcp-controlplane-jvcnl", spec.Hostname) suite.Assert().Equal("talos-e2e-897b4e49-gcp-controlplane-jvcnl", spec.Hostname)
suite.Assert().Equal("", spec.Domainname) suite.Assert().Equal("", spec.Domainname)
suite.Assert().Equal(network.ConfigPlatform, spec.ConfigLayer) suite.Assert().Equal(network.ConfigPlatform, spec.ConfigLayer)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *PlatformConfigSuite) TearDownTest() { func (suite *PlatformConfigSuite) TearDownTest() {
@ -496,7 +629,10 @@ func (mock *platformMock) KernelArgs() procfs.Parameters {
} }
//nolint:gocyclo //nolint:gocyclo
func (mock *platformMock) NetworkConfiguration(ctx context.Context, ch chan<- *v1alpha1runtime.PlatformNetworkConfig) error { func (mock *platformMock) NetworkConfiguration(
ctx context.Context,
ch chan<- *v1alpha1runtime.PlatformNetworkConfig,
) error {
if mock.noData { if mock.noData {
return nil return nil
} }
@ -520,7 +656,8 @@ func (mock *platformMock) NetworkConfiguration(ctx context.Context, ch chan<- *v
family = nethelpers.FamilyInet6 family = nethelpers.FamilyInet6
} }
networkConfig.Addresses = append(networkConfig.Addresses, networkConfig.Addresses = append(
networkConfig.Addresses,
network.AddressSpecSpec{ network.AddressSpecSpec{
ConfigLayer: network.ConfigPlatform, ConfigLayer: network.ConfigPlatform,
LinkName: "eth0", LinkName: "eth0",
@ -528,7 +665,8 @@ func (mock *platformMock) NetworkConfiguration(ctx context.Context, ch chan<- *v
Scope: nethelpers.ScopeGlobal, Scope: nethelpers.ScopeGlobal,
Flags: nethelpers.AddressFlags(nethelpers.AddressPermanent), Flags: nethelpers.AddressFlags(nethelpers.AddressPermanent),
Family: family, Family: family,
}) },
)
} }
for _, gw := range mock.defaultRoutes { for _, gw := range mock.defaultRoutes {
@ -554,34 +692,42 @@ func (mock *platformMock) NetworkConfiguration(ctx context.Context, ch chan<- *v
} }
for _, link := range mock.linksUp { for _, link := range mock.linksUp {
networkConfig.Links = append(networkConfig.Links, network.LinkSpecSpec{ networkConfig.Links = append(
ConfigLayer: network.ConfigPlatform, networkConfig.Links, network.LinkSpecSpec{
Name: link, ConfigLayer: network.ConfigPlatform,
Up: true, Name: link,
}) Up: true,
},
)
} }
if len(mock.resolvers) > 0 { if len(mock.resolvers) > 0 {
networkConfig.Resolvers = append(networkConfig.Resolvers, network.ResolverSpecSpec{ networkConfig.Resolvers = append(
ConfigLayer: network.ConfigPlatform, networkConfig.Resolvers, network.ResolverSpecSpec{
DNSServers: mock.resolvers, ConfigLayer: network.ConfigPlatform,
}) DNSServers: mock.resolvers,
},
)
} }
if len(mock.timeServers) > 0 { if len(mock.timeServers) > 0 {
networkConfig.TimeServers = append(networkConfig.TimeServers, network.TimeServerSpecSpec{ networkConfig.TimeServers = append(
ConfigLayer: network.ConfigPlatform, networkConfig.TimeServers, network.TimeServerSpecSpec{
NTPServers: mock.timeServers, ConfigLayer: network.ConfigPlatform,
}) NTPServers: mock.timeServers,
},
)
} }
for _, link := range mock.dhcp4Links { for _, link := range mock.dhcp4Links {
networkConfig.Operators = append(networkConfig.Operators, network.OperatorSpecSpec{ networkConfig.Operators = append(
ConfigLayer: network.ConfigPlatform, networkConfig.Operators, network.OperatorSpecSpec{
LinkName: link, ConfigLayer: network.ConfigPlatform,
Operator: network.OperatorDHCP4, LinkName: link,
DHCP4: network.DHCP4OperatorSpec{}, Operator: network.OperatorDHCP4,
}) DHCP4: network.DHCP4OperatorSpec{},
},
)
} }
select { select {

View File

@ -40,7 +40,7 @@ type ResolverConfigSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -72,7 +72,10 @@ func (suite *ResolverConfigSuite) assertResolvers(requiredIDs []string, check fu
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.ConfigNamespaceName, network.ResolverSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.ConfigNamespaceName, network.ResolverSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -98,7 +101,10 @@ func (suite *ResolverConfigSuite) assertResolvers(requiredIDs []string, check fu
} }
func (suite *ResolverConfigSuite) assertNoResolver(id string) error { func (suite *ResolverConfigSuite) assertNoResolver(id string) error {
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.ConfigNamespaceName, network.ResolverSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.ConfigNamespaceName, network.ResolverSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -117,36 +123,60 @@ func (suite *ResolverConfigSuite) TestDefaults() {
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertResolvers([]string{ func() error {
"default/resolvers", return suite.assertResolvers(
}, func(r *network.ResolverSpec) error { []string{
suite.Assert().Equal([]netaddr.IP{netaddr.MustParseIP(constants.DefaultPrimaryResolver), netaddr.MustParseIP(constants.DefaultSecondaryResolver)}, r.TypedSpec().DNSServers) "default/resolvers",
suite.Assert().Equal(network.ConfigDefault, r.TypedSpec().ConfigLayer) }, func(r *network.ResolverSpec) error {
suite.Assert().Equal(
[]netaddr.IP{
netaddr.MustParseIP(constants.DefaultPrimaryResolver),
netaddr.MustParseIP(constants.DefaultSecondaryResolver),
}, r.TypedSpec().DNSServers,
)
suite.Assert().Equal(network.ConfigDefault, r.TypedSpec().ConfigLayer)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *ResolverConfigSuite) TestCmdline() { func (suite *ResolverConfigSuite) TestCmdline() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.ResolverConfigController{ suite.Require().NoError(
Cmdline: procfs.NewCmdline("ip=172.20.0.2:172.21.0.1:172.20.0.1:255.255.255.0:master1:eth1::10.0.0.1:10.0.0.2:10.0.0.1"), suite.runtime.RegisterController(
})) &netctrl.ResolverConfigController{
Cmdline: procfs.NewCmdline("ip=172.20.0.2:172.21.0.1:172.20.0.1:255.255.255.0:master1:eth1::10.0.0.1:10.0.0.2:10.0.0.1"),
},
),
)
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertResolvers([]string{ func() error {
"cmdline/resolvers", return suite.assertResolvers(
}, func(r *network.ResolverSpec) error { []string{
suite.Assert().Equal([]netaddr.IP{netaddr.MustParseIP("10.0.0.1"), netaddr.MustParseIP("10.0.0.2")}, r.TypedSpec().DNSServers) "cmdline/resolvers",
}, func(r *network.ResolverSpec) error {
suite.Assert().Equal(
[]netaddr.IP{
netaddr.MustParseIP("10.0.0.1"),
netaddr.MustParseIP("10.0.0.2"),
}, r.TypedSpec().DNSServers,
)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *ResolverConfigSuite) TestMachineConfiguration() { func (suite *ResolverConfigSuite) TestMachineConfiguration() {
@ -157,46 +187,63 @@ func (suite *ResolverConfigSuite) TestMachineConfiguration() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{ ConfigVersion: "v1alpha1",
MachineNetwork: &v1alpha1.NetworkConfig{ MachineConfig: &v1alpha1.MachineConfig{
NameServers: []string{"2.2.2.2", "3.3.3.3"}, MachineNetwork: &v1alpha1.NetworkConfig{
NameServers: []string{"2.2.2.2", "3.3.3.3"},
},
}, },
}, ClusterConfig: &v1alpha1.ClusterConfig{
ClusterConfig: &v1alpha1.ClusterConfig{ ControlPlane: &v1alpha1.ControlPlaneConfig{
ControlPlane: &v1alpha1.ControlPlaneConfig{ Endpoint: &v1alpha1.Endpoint{
Endpoint: &v1alpha1.Endpoint{ URL: u,
URL: u, },
}, },
}, },
}, },
}) )
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertResolvers([]string{ func() error {
"configuration/resolvers", return suite.assertResolvers(
}, func(r *network.ResolverSpec) error { []string{
suite.Assert().Equal([]netaddr.IP{netaddr.MustParseIP("2.2.2.2"), netaddr.MustParseIP("3.3.3.3")}, r.TypedSpec().DNSServers) "configuration/resolvers",
}, func(r *network.ResolverSpec) error {
suite.Assert().Equal(
[]netaddr.IP{
netaddr.MustParseIP("2.2.2.2"),
netaddr.MustParseIP("3.3.3.3"),
}, r.TypedSpec().DNSServers,
)
return nil return nil
}) },
})) )
},
),
)
_, err = suite.state.UpdateWithConflicts(suite.ctx, cfg.Metadata(), func(r resource.Resource) error { _, err = suite.state.UpdateWithConflicts(
r.(*config.MachineConfig).Config().(*v1alpha1.Config).MachineConfig.MachineNetwork.NameServers = nil suite.ctx, cfg.Metadata(), func(r resource.Resource) error {
r.(*config.MachineConfig).Config().(*v1alpha1.Config).MachineConfig.MachineNetwork.NameServers = nil
return nil return nil
}) },
)
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNoResolver("configuration/resolvers") func() error {
})) return suite.assertNoResolver("configuration/resolvers")
},
),
)
} }
func (suite *ResolverConfigSuite) TearDownTest() { func (suite *ResolverConfigSuite) TearDownTest() {
@ -207,10 +254,14 @@ func (suite *ResolverConfigSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ err := suite.state.Create(
ConfigVersion: "v1alpha1", context.Background(), config.NewMachineConfig(
MachineConfig: &v1alpha1.MachineConfig{}, &v1alpha1.Config{
})) ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{},
},
),
)
if state.IsConflictError(err) { if state.IsConflictError(err) {
err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata())
} }

View File

@ -37,7 +37,7 @@ type ResolverMergeSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -73,7 +73,10 @@ func (suite *ResolverMergeSuite) assertResolvers(requiredIDs []string, check fun
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.NamespaceName, network.ResolverSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.ResolverSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -101,7 +104,10 @@ func (suite *ResolverMergeSuite) assertResolvers(requiredIDs []string, check fun
func (suite *ResolverMergeSuite) TestMerge() { func (suite *ResolverMergeSuite) TestMerge() {
def := network.NewResolverSpec(network.ConfigNamespaceName, "default/resolvers") def := network.NewResolverSpec(network.ConfigNamespaceName, "default/resolvers")
*def.TypedSpec() = network.ResolverSpecSpec{ *def.TypedSpec() = network.ResolverSpecSpec{
DNSServers: []netaddr.IP{netaddr.MustParseIP(constants.DefaultPrimaryResolver), netaddr.MustParseIP(constants.DefaultSecondaryResolver)}, DNSServers: []netaddr.IP{
netaddr.MustParseIP(constants.DefaultPrimaryResolver),
netaddr.MustParseIP(constants.DefaultSecondaryResolver),
},
ConfigLayer: network.ConfigDefault, ConfigLayer: network.ConfigDefault,
} }
@ -127,31 +133,44 @@ func (suite *ResolverMergeSuite) TestMerge() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertResolvers([]string{ func() error {
"resolvers", return suite.assertResolvers(
}, func(r *network.ResolverSpec) error { []string{
suite.Assert().Equal(*static.TypedSpec(), *r.TypedSpec()) "resolvers",
}, func(r *network.ResolverSpec) error {
suite.Assert().Equal(*static.TypedSpec(), *r.TypedSpec())
return nil return nil
}) },
})) )
},
),
)
suite.Require().NoError(suite.state.Destroy(suite.ctx, static.Metadata())) suite.Require().NoError(suite.state.Destroy(suite.ctx, static.Metadata()))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertResolvers([]string{ func() error {
"resolvers", return suite.assertResolvers(
}, func(r *network.ResolverSpec) error { []string{
if !reflect.DeepEqual(r.TypedSpec().DNSServers, []netaddr.IP{netaddr.MustParseIP("1.1.2.0"), netaddr.MustParseIP("1.1.2.1")}) { "resolvers",
return retry.ExpectedErrorf("unexpected servers %q", r.TypedSpec().DNSServers) }, func(r *network.ResolverSpec) error {
} if !reflect.DeepEqual(
r.TypedSpec().DNSServers,
[]netaddr.IP{netaddr.MustParseIP("1.1.2.0"), netaddr.MustParseIP("1.1.2.1")},
) {
return retry.ExpectedErrorf("unexpected servers %q", r.TypedSpec().DNSServers)
}
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *ResolverMergeSuite) TearDownTest() { func (suite *ResolverMergeSuite) TearDownTest() {
@ -162,7 +181,12 @@ func (suite *ResolverMergeSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewResolverSpec(network.ConfigNamespaceName, "bar"))) suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewResolverSpec(network.ConfigNamespaceName, "bar"),
),
)
} }
func TestResolverMergeSuite(t *testing.T) { func TestResolverMergeSuite(t *testing.T) {

View File

@ -36,7 +36,7 @@ type ResolverSpecSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -66,7 +66,10 @@ func (suite *ResolverSpecSuite) startRuntime() {
} }
func (suite *ResolverSpecSuite) assertStatus(id string, servers ...netaddr.IP) error { func (suite *ResolverSpecSuite) assertStatus(id string, servers ...netaddr.IP) error {
r, err := suite.state.Get(suite.ctx, resource.NewMetadata(network.NamespaceName, network.ResolverStatusType, id, resource.VersionUndefined)) r, err := suite.state.Get(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.ResolverStatusType, id, resource.VersionUndefined),
)
if err != nil { if err != nil {
if state.IsNotFoundError(err) { if state.IsNotFoundError(err) {
return retry.ExpectedError(err) return retry.ExpectedError(err)
@ -95,10 +98,13 @@ func (suite *ResolverSpecSuite) TestSpec() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertStatus("resolvers", netaddr.MustParseIP(constants.DefaultPrimaryResolver)) func() error {
})) return suite.assertStatus("resolvers", netaddr.MustParseIP(constants.DefaultPrimaryResolver))
},
),
)
} }
func (suite *ResolverSpecSuite) TearDownTest() { func (suite *ResolverSpecSuite) TearDownTest() {
@ -109,7 +115,12 @@ func (suite *ResolverSpecSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewResolverSpec(network.NamespaceName, "bar"))) suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewResolverSpec(network.NamespaceName, "bar"),
),
)
} }
func TestResolverSpecSuite(t *testing.T) { func TestResolverSpecSuite(t *testing.T) {

View File

@ -40,7 +40,7 @@ type RouteConfigSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -72,7 +72,10 @@ func (suite *RouteConfigSuite) assertRoutes(requiredIDs []string, check func(*ne
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.ConfigNamespaceName, network.RouteSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.ConfigNamespaceName, network.RouteSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -98,25 +101,34 @@ func (suite *RouteConfigSuite) assertRoutes(requiredIDs []string, check func(*ne
} }
func (suite *RouteConfigSuite) TestCmdline() { func (suite *RouteConfigSuite) TestCmdline() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.RouteConfigController{ suite.Require().NoError(
Cmdline: procfs.NewCmdline("ip=172.20.0.2::172.20.0.1:255.255.255.0::eth1:::::"), suite.runtime.RegisterController(
})) &netctrl.RouteConfigController{
Cmdline: procfs.NewCmdline("ip=172.20.0.2::172.20.0.1:255.255.255.0::eth1:::::"),
},
),
)
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertRoutes([]string{ func() error {
"cmdline/inet4/172.20.0.1//1024", return suite.assertRoutes(
}, func(r *network.RouteSpec) error { []string{
suite.Assert().Equal("eth1", r.TypedSpec().OutLinkName) "cmdline/inet4/172.20.0.1//1024",
suite.Assert().Equal(network.ConfigCmdline, r.TypedSpec().ConfigLayer) }, func(r *network.RouteSpec) error {
suite.Assert().Equal(nethelpers.FamilyInet4, r.TypedSpec().Family) suite.Assert().Equal("eth1", r.TypedSpec().OutLinkName)
suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().Priority) suite.Assert().Equal(network.ConfigCmdline, r.TypedSpec().ConfigLayer)
suite.Assert().Equal(nethelpers.FamilyInet4, r.TypedSpec().Family)
suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().Priority)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *RouteConfigSuite) TestMachineConfiguration() { func (suite *RouteConfigSuite) TestMachineConfiguration() {
@ -127,127 +139,134 @@ func (suite *RouteConfigSuite) TestMachineConfiguration() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{ ConfigVersion: "v1alpha1",
MachineNetwork: &v1alpha1.NetworkConfig{ MachineConfig: &v1alpha1.MachineConfig{
NetworkInterfaces: []*v1alpha1.Device{ MachineNetwork: &v1alpha1.NetworkConfig{
{ NetworkInterfaces: []*v1alpha1.Device{
DeviceInterface: "eth3", {
DeviceAddresses: []string{"192.168.0.24/28"}, DeviceInterface: "eth3",
DeviceRoutes: []*v1alpha1.Route{ DeviceAddresses: []string{"192.168.0.24/28"},
{ DeviceRoutes: []*v1alpha1.Route{
RouteNetwork: "192.168.0.0/18", {
RouteGateway: "192.168.0.25", RouteNetwork: "192.168.0.0/18",
RouteMetric: 25, RouteGateway: "192.168.0.25",
}, RouteMetric: 25,
{
RouteNetwork: "169.254.254.254/32",
},
},
},
{
DeviceIgnore: true,
DeviceInterface: "eth4",
DeviceAddresses: []string{"192.168.0.24/28"},
DeviceRoutes: []*v1alpha1.Route{
{
RouteNetwork: "192.168.0.0/18",
RouteGateway: "192.168.0.26",
RouteMetric: 25,
},
},
},
{
DeviceInterface: "eth2",
DeviceAddresses: []string{"2001:470:6d:30e:8ed2:b60c:9d2f:803a/64"},
DeviceRoutes: []*v1alpha1.Route{
{
RouteGateway: "2001:470:6d:30e:8ed2:b60c:9d2f:803b",
},
},
},
{
DeviceInterface: "eth0",
DeviceVlans: []*v1alpha1.Vlan{
{
VlanID: 24,
VlanAddresses: []string{
"10.0.0.1/8",
}, },
VlanRoutes: []*v1alpha1.Route{ {
{ RouteNetwork: "169.254.254.254/32",
RouteNetwork: "10.0.3.0/24", },
RouteGateway: "10.0.3.1", },
},
{
DeviceIgnore: true,
DeviceInterface: "eth4",
DeviceAddresses: []string{"192.168.0.24/28"},
DeviceRoutes: []*v1alpha1.Route{
{
RouteNetwork: "192.168.0.0/18",
RouteGateway: "192.168.0.26",
RouteMetric: 25,
},
},
},
{
DeviceInterface: "eth2",
DeviceAddresses: []string{"2001:470:6d:30e:8ed2:b60c:9d2f:803a/64"},
DeviceRoutes: []*v1alpha1.Route{
{
RouteGateway: "2001:470:6d:30e:8ed2:b60c:9d2f:803b",
},
},
},
{
DeviceInterface: "eth0",
DeviceVlans: []*v1alpha1.Vlan{
{
VlanID: 24,
VlanAddresses: []string{
"10.0.0.1/8",
},
VlanRoutes: []*v1alpha1.Route{
{
RouteNetwork: "10.0.3.0/24",
RouteGateway: "10.0.3.1",
},
}, },
}, },
}, },
}, },
}, {
{ DeviceInterface: "eth1",
DeviceInterface: "eth1", DeviceRoutes: []*v1alpha1.Route{
DeviceRoutes: []*v1alpha1.Route{ {
{ RouteNetwork: "192.244.0.0/24",
RouteNetwork: "192.244.0.0/24", RouteGateway: "192.244.0.1",
RouteGateway: "192.244.0.1", RouteSource: "192.244.0.10",
RouteSource: "192.244.0.10", },
}, },
}, },
}, },
}, },
}, },
}, ClusterConfig: &v1alpha1.ClusterConfig{
ClusterConfig: &v1alpha1.ClusterConfig{ ControlPlane: &v1alpha1.ControlPlaneConfig{
ControlPlane: &v1alpha1.ControlPlaneConfig{ Endpoint: &v1alpha1.Endpoint{
Endpoint: &v1alpha1.Endpoint{ URL: u,
URL: u, },
}, },
}, },
}, },
}) )
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertRoutes([]string{ func() error {
"configuration/inet6/2001:470:6d:30e:8ed2:b60c:9d2f:803b//1024", return suite.assertRoutes(
"configuration/inet4/10.0.3.1/10.0.3.0/24/1024", []string{
"configuration/inet4/192.168.0.25/192.168.0.0/18/25", "configuration/inet6/2001:470:6d:30e:8ed2:b60c:9d2f:803b//1024",
"configuration/inet4/192.244.0.1/192.244.0.0/24/1024", "configuration/inet4/10.0.3.1/10.0.3.0/24/1024",
"configuration/inet4//169.254.254.254/32/1024", "configuration/inet4/192.168.0.25/192.168.0.0/18/25",
}, func(r *network.RouteSpec) error { "configuration/inet4/192.244.0.1/192.244.0.0/24/1024",
switch r.Metadata().ID() { "configuration/inet4//169.254.254.254/32/1024",
case "configuration/inet6/2001:470:6d:30e:8ed2:b60c:9d2f:803b//1024": }, func(r *network.RouteSpec) error {
suite.Assert().Equal("eth2", r.TypedSpec().OutLinkName) switch r.Metadata().ID() {
suite.Assert().Equal(nethelpers.FamilyInet6, r.TypedSpec().Family) case "configuration/inet6/2001:470:6d:30e:8ed2:b60c:9d2f:803b//1024":
suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().Priority) suite.Assert().Equal("eth2", r.TypedSpec().OutLinkName)
case "configuration/inet4/10.0.3.1/10.0.3.0/24/1024": suite.Assert().Equal(nethelpers.FamilyInet6, r.TypedSpec().Family)
suite.Assert().Equal("eth0.24", r.TypedSpec().OutLinkName) suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().Priority)
suite.Assert().Equal(nethelpers.FamilyInet4, r.TypedSpec().Family) case "configuration/inet4/10.0.3.1/10.0.3.0/24/1024":
suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().Priority) suite.Assert().Equal("eth0.24", r.TypedSpec().OutLinkName)
case "configuration/inet4/192.168.0.25/192.168.0.0/18/25": suite.Assert().Equal(nethelpers.FamilyInet4, r.TypedSpec().Family)
suite.Assert().Equal("eth3", r.TypedSpec().OutLinkName) suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().Priority)
suite.Assert().Equal(nethelpers.FamilyInet4, r.TypedSpec().Family) case "configuration/inet4/192.168.0.25/192.168.0.0/18/25":
suite.Assert().EqualValues(25, r.TypedSpec().Priority) suite.Assert().Equal("eth3", r.TypedSpec().OutLinkName)
case "configuration/inet4/192.244.0.1/192.244.0.0/24/1024": suite.Assert().Equal(nethelpers.FamilyInet4, r.TypedSpec().Family)
suite.Assert().Equal("eth1", r.TypedSpec().OutLinkName) suite.Assert().EqualValues(25, r.TypedSpec().Priority)
suite.Assert().Equal(nethelpers.FamilyInet4, r.TypedSpec().Family) case "configuration/inet4/192.244.0.1/192.244.0.0/24/1024":
suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().Priority) suite.Assert().Equal("eth1", r.TypedSpec().OutLinkName)
suite.Assert().EqualValues(netaddr.MustParseIP("192.244.0.10"), r.TypedSpec().Source) suite.Assert().Equal(nethelpers.FamilyInet4, r.TypedSpec().Family)
case "configuration/inet4//169.254.254.254/32/1024": suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().Priority)
suite.Assert().Equal("eth3", r.TypedSpec().OutLinkName) suite.Assert().EqualValues(netaddr.MustParseIP("192.244.0.10"), r.TypedSpec().Source)
suite.Assert().Equal(nethelpers.FamilyInet4, r.TypedSpec().Family) case "configuration/inet4//169.254.254.254/32/1024":
suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().Priority) suite.Assert().Equal("eth3", r.TypedSpec().OutLinkName)
suite.Assert().Equal(nethelpers.ScopeLink, r.TypedSpec().Scope) suite.Assert().Equal(nethelpers.FamilyInet4, r.TypedSpec().Family)
suite.Assert().Equal("169.254.254.254/32", r.TypedSpec().Destination.String()) suite.Assert().EqualValues(netctrl.DefaultRouteMetric, r.TypedSpec().Priority)
} suite.Assert().Equal(nethelpers.ScopeLink, r.TypedSpec().Scope)
suite.Assert().Equal("169.254.254.254/32", r.TypedSpec().Destination.String())
}
suite.Assert().Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer) suite.Assert().Equal(network.ConfigMachineConfiguration, r.TypedSpec().ConfigLayer)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *RouteConfigSuite) TearDownTest() { func (suite *RouteConfigSuite) TearDownTest() {
@ -258,10 +277,14 @@ func (suite *RouteConfigSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ err := suite.state.Create(
ConfigVersion: "v1alpha1", context.Background(), config.NewMachineConfig(
MachineConfig: &v1alpha1.MachineConfig{}, &v1alpha1.Config{
})) ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{},
},
),
)
if state.IsConflictError(err) { if state.IsConflictError(err) {
err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata())
} }

View File

@ -37,7 +37,7 @@ type RouteMergeSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -73,7 +73,10 @@ func (suite *RouteMergeSuite) assertRoutes(requiredIDs []string, check func(*net
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.NamespaceName, network.RouteSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.RouteSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -99,7 +102,10 @@ func (suite *RouteMergeSuite) assertRoutes(requiredIDs []string, check func(*net
} }
func (suite *RouteMergeSuite) assertNoRoute(id string) error { func (suite *RouteMergeSuite) assertNoRoute(id string) error {
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.NamespaceName, network.RouteSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.RouteSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -155,55 +161,68 @@ func (suite *RouteMergeSuite) TestMerge() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertRoutes([]string{ func() error {
"inet4/10.5.0.3//50", return suite.assertRoutes(
"inet4/10.0.0.34/10.0.0.35/32/1024", []string{
}, func(r *network.RouteSpec) error { "inet4/10.5.0.3//50",
suite.Assert().Equal(resource.PhaseRunning, r.Metadata().Phase()) "inet4/10.0.0.34/10.0.0.35/32/1024",
}, func(r *network.RouteSpec) error {
suite.Assert().Equal(resource.PhaseRunning, r.Metadata().Phase())
switch r.Metadata().ID() { switch r.Metadata().ID() {
case "inet4/10.5.0.3//50": case "inet4/10.5.0.3//50":
suite.Assert().Equal(*dhcp.TypedSpec(), *r.TypedSpec()) suite.Assert().Equal(*dhcp.TypedSpec(), *r.TypedSpec())
case "inet4/10.0.0.34/10.0.0.35/32/1024": case "inet4/10.0.0.34/10.0.0.35/32/1024":
suite.Assert().Equal(*static.TypedSpec(), *r.TypedSpec()) suite.Assert().Equal(*static.TypedSpec(), *r.TypedSpec())
} }
return nil return nil
}) },
})) )
},
),
)
suite.Require().NoError(suite.state.Destroy(suite.ctx, dhcp.Metadata())) suite.Require().NoError(suite.state.Destroy(suite.ctx, dhcp.Metadata()))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertRoutes([]string{ func() error {
"inet4/10.5.0.3//50", return suite.assertRoutes(
"inet4/10.0.0.34/10.0.0.35/32/1024", []string{
}, func(r *network.RouteSpec) error { "inet4/10.5.0.3//50",
suite.Assert().Equal(resource.PhaseRunning, r.Metadata().Phase()) "inet4/10.0.0.34/10.0.0.35/32/1024",
}, func(r *network.RouteSpec) error {
suite.Assert().Equal(resource.PhaseRunning, r.Metadata().Phase())
switch r.Metadata().ID() { switch r.Metadata().ID() {
case "inet4/10.5.0.3//50": case "inet4/10.5.0.3//50":
if *cmdline.TypedSpec() != *r.TypedSpec() { if *cmdline.TypedSpec() != *r.TypedSpec() {
// using retry here, as it might not be reconciled immediately // using retry here, as it might not be reconciled immediately
return retry.ExpectedError(fmt.Errorf("not equal yet")) return retry.ExpectedError(fmt.Errorf("not equal yet"))
} }
case "inet4/10.0.0.34/10.0.0.35/32/1024": case "inet4/10.0.0.34/10.0.0.35/32/1024":
suite.Assert().Equal(*static.TypedSpec(), *r.TypedSpec()) suite.Assert().Equal(*static.TypedSpec(), *r.TypedSpec())
} }
return nil return nil
}) },
})) )
},
),
)
suite.Require().NoError(suite.state.Destroy(suite.ctx, static.Metadata())) suite.Require().NoError(suite.state.Destroy(suite.ctx, static.Metadata()))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNoRoute("inet4/10.0.0.34/10.0.0.35/32/1024") func() error {
})) return suite.assertNoRoute("inet4/10.0.0.34/10.0.0.35/32/1024")
},
),
)
} }
//nolint:gocyclo //nolint:gocyclo
@ -257,50 +276,75 @@ func (suite *RouteMergeSuite) TestMergeFlapping() {
eg.Go(flipflop(0)) eg.Go(flipflop(0))
eg.Go(flipflop(1)) eg.Go(flipflop(1))
eg.Go(func() error { eg.Go(
// add/remove finalizer to the merged resource func() error {
for i := 0; i < 1000; i++ { // add/remove finalizer to the merged resource
if err := suite.state.AddFinalizer(suite.ctx, resource.NewMetadata(network.NamespaceName, network.RouteSpecType, "inet4/10.5.0.3//50", resource.VersionUndefined), "foo"); err != nil { for i := 0; i < 1000; i++ {
if !state.IsNotFoundError(err) { if err := suite.state.AddFinalizer(
return err suite.ctx,
resource.NewMetadata(
network.NamespaceName,
network.RouteSpecType,
"inet4/10.5.0.3//50",
resource.VersionUndefined,
),
"foo",
); err != nil {
if !state.IsNotFoundError(err) {
return err
}
continue
} else {
suite.T().Log("finalizer added")
} }
continue time.Sleep(10 * time.Millisecond)
} else {
suite.T().Log("finalizer added")
}
time.Sleep(10 * time.Millisecond) if err := suite.state.RemoveFinalizer(
suite.ctx,
if err := suite.state.RemoveFinalizer(suite.ctx, resource.NewMetadata(network.NamespaceName, network.RouteSpecType, "inet4/10.5.0.3//50", resource.VersionUndefined), "foo"); err != nil { resource.NewMetadata(
if err != nil && !state.IsNotFoundError(err) { network.NamespaceName,
return err network.RouteSpecType,
"inet4/10.5.0.3//50",
resource.VersionUndefined,
),
"foo",
); err != nil {
if err != nil && !state.IsNotFoundError(err) {
return err
}
} }
} }
}
return nil return nil
}) },
)
suite.Require().NoError(eg.Wait()) suite.Require().NoError(eg.Wait())
suite.Assert().NoError(retry.Constant(15*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(15*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertRoutes([]string{ func() error {
"inet4/10.5.0.3//50", return suite.assertRoutes(
}, func(r *network.RouteSpec) error { []string{
if r.Metadata().Phase() != resource.PhaseRunning { "inet4/10.5.0.3//50",
return retry.ExpectedErrorf("resource phase is %s", r.Metadata().Phase()) }, func(r *network.RouteSpec) error {
} if r.Metadata().Phase() != resource.PhaseRunning {
return retry.ExpectedErrorf("resource phase is %s", r.Metadata().Phase())
}
if *dhcp.TypedSpec() != *r.TypedSpec() { if *dhcp.TypedSpec() != *r.TypedSpec() {
// using retry here, as it might not be reconciled immediately // using retry here, as it might not be reconciled immediately
return retry.ExpectedError(fmt.Errorf("not equal yet")) return retry.ExpectedError(fmt.Errorf("not equal yet"))
} }
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *RouteMergeSuite) TearDownTest() { func (suite *RouteMergeSuite) TearDownTest() {
@ -311,7 +355,12 @@ func (suite *RouteMergeSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewRouteSpec(network.ConfigNamespaceName, "bar"))) suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewRouteSpec(network.ConfigNamespaceName, "bar"),
),
)
} }
func TestRouteMergeSuite(t *testing.T) { func TestRouteMergeSuite(t *testing.T) {

View File

@ -149,7 +149,8 @@ func findRoutes(routes []rtnetlink.RouteMessage, family nethelpers.Family, desti
//nolint:gocyclo,cyclop //nolint:gocyclo,cyclop
func (ctrl *RouteSpecController) syncRoute(ctx context.Context, r controller.Runtime, logger *zap.Logger, conn *rtnetlink.Conn, func (ctrl *RouteSpecController) syncRoute(ctx context.Context, r controller.Runtime, logger *zap.Logger, conn *rtnetlink.Conn,
links []rtnetlink.LinkMessage, routes []rtnetlink.RouteMessage, route *network.RouteSpec) error { links []rtnetlink.LinkMessage, routes []rtnetlink.RouteMessage, route *network.RouteSpec,
) error {
linkIndex := resolveLinkName(links, route.TypedSpec().OutLinkName) linkIndex := resolveLinkName(links, route.TypedSpec().OutLinkName)
destinationStr := route.TypedSpec().Destination.String() destinationStr := route.TypedSpec().Destination.String()

View File

@ -40,7 +40,7 @@ type RouteSpecSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -73,7 +73,11 @@ func (suite *RouteSpecSuite) startRuntime() {
}() }()
} }
func (suite *RouteSpecSuite) assertRoute(destination netaddr.IPPrefix, gateway netaddr.IP, check func(rtnetlink.RouteMessage) error) error { func (suite *RouteSpecSuite) assertRoute(
destination netaddr.IPPrefix,
gateway netaddr.IP,
check func(rtnetlink.RouteMessage) error,
) error {
conn, err := rtnetlink.Dial(nil) conn, err := rtnetlink.Dial(nil)
suite.Require().NoError(err) suite.Require().NoError(err)
@ -150,14 +154,21 @@ func (suite *RouteSpecSuite) TestLoopback() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertRoute(netaddr.MustParseIPPrefix("127.0.11.0/24"), netaddr.MustParseIP("127.0.11.1"), func(route rtnetlink.RouteMessage) error { func() error {
suite.Assert().EqualValues(0, route.Attributes.Priority) return suite.assertRoute(
netaddr.MustParseIPPrefix("127.0.11.0/24"),
netaddr.MustParseIP("127.0.11.1"),
func(route rtnetlink.RouteMessage) error {
suite.Assert().EqualValues(0, route.Attributes.Priority)
return nil return nil
}) },
})) )
},
),
)
// teardown the route // teardown the route
for { for {
@ -172,7 +183,12 @@ func (suite *RouteSpecSuite) TestLoopback() {
} }
// torn down address should be removed immediately // torn down address should be removed immediately
suite.Assert().NoError(suite.assertNoRoute(netaddr.MustParseIPPrefix("127.0.11.0/24"), netaddr.MustParseIP("127.0.11.1"))) suite.Assert().NoError(
suite.assertNoRoute(
netaddr.MustParseIPPrefix("127.0.11.0/24"),
netaddr.MustParseIP("127.0.11.1"),
),
)
suite.Require().NoError(suite.state.Destroy(suite.ctx, loopback.Metadata())) suite.Require().NoError(suite.state.Destroy(suite.ctx, loopback.Metadata()))
} }
@ -197,38 +213,50 @@ func (suite *RouteSpecSuite) TestDefaultRoute() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertRoute(netaddr.IPPrefix{}, netaddr.MustParseIP("127.0.11.2"), func(route rtnetlink.RouteMessage) error { func() error {
suite.Assert().Nil(route.Attributes.Dst) return suite.assertRoute(
suite.Assert().EqualValues(1048576, route.Attributes.Priority) netaddr.IPPrefix{}, netaddr.MustParseIP("127.0.11.2"), func(route rtnetlink.RouteMessage) error {
suite.Assert().Nil(route.Attributes.Dst)
suite.Assert().EqualValues(1048576, route.Attributes.Priority)
return nil return nil
}) },
})) )
},
),
)
// update the route metric // update the route metric
_, err := suite.state.UpdateWithConflicts(suite.ctx, def.Metadata(), func(r resource.Resource) error { _, err := suite.state.UpdateWithConflicts(
defR := r.(*network.RouteSpec) //nolint:forcetypeassert,errcheck suite.ctx, def.Metadata(), func(r resource.Resource) error {
defR := r.(*network.RouteSpec) //nolint:forcetypeassert,errcheck
defR.TypedSpec().Priority = 1048577 defR.TypedSpec().Priority = 1048577
return nil return nil
}) },
)
suite.Assert().NoError(err) suite.Assert().NoError(err)
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertRoute(netaddr.IPPrefix{}, netaddr.MustParseIP("127.0.11.2"), func(route rtnetlink.RouteMessage) error { func() error {
suite.Assert().Nil(route.Attributes.Dst) return suite.assertRoute(
netaddr.IPPrefix{}, netaddr.MustParseIP("127.0.11.2"), func(route rtnetlink.RouteMessage) error {
suite.Assert().Nil(route.Attributes.Dst)
if route.Attributes.Priority != 1048577 { if route.Attributes.Priority != 1048577 {
return fmt.Errorf("route metric wasn't updated: %d", route.Attributes.Priority) return fmt.Errorf("route metric wasn't updated: %d", route.Attributes.Priority)
} }
return nil return nil
}) },
})) )
},
),
)
// teardown the route // teardown the route
for { for {
@ -256,18 +284,22 @@ func (suite *RouteSpecSuite) TestDefaultAndInterfaceRoutes() {
defer conn.Close() //nolint:errcheck defer conn.Close() //nolint:errcheck
suite.Require().NoError(conn.Link.New(&rtnetlink.LinkMessage{ suite.Require().NoError(
Type: unix.ARPHRD_ETHER, conn.Link.New(
Flags: unix.IFF_UP, &rtnetlink.LinkMessage{
Change: unix.IFF_UP, Type: unix.ARPHRD_ETHER,
Attributes: &rtnetlink.LinkAttributes{ Flags: unix.IFF_UP,
Name: dummyInterface, Change: unix.IFF_UP,
MTU: 1400, Attributes: &rtnetlink.LinkAttributes{
Info: &rtnetlink.LinkInfo{ Name: dummyInterface,
Kind: "dummy", MTU: 1400,
Info: &rtnetlink.LinkInfo{
Kind: "dummy",
},
},
}, },
}, ),
})) )
iface, err := net.InterfaceByName(dummyInterface) iface, err := net.InterfaceByName(dummyInterface)
suite.Require().NoError(err) suite.Require().NoError(err)
@ -276,16 +308,20 @@ func (suite *RouteSpecSuite) TestDefaultAndInterfaceRoutes() {
localIP := net.ParseIP("10.28.0.27").To4() localIP := net.ParseIP("10.28.0.27").To4()
suite.Require().NoError(conn.Address.New(&rtnetlink.AddressMessage{ suite.Require().NoError(
Family: unix.AF_INET, conn.Address.New(
PrefixLength: 32, &rtnetlink.AddressMessage{
Scope: unix.RT_SCOPE_UNIVERSE, Family: unix.AF_INET,
Index: uint32(iface.Index), PrefixLength: 32,
Attributes: &rtnetlink.AddressAttributes{ Scope: unix.RT_SCOPE_UNIVERSE,
Address: localIP, Index: uint32(iface.Index),
Local: localIP, Attributes: &rtnetlink.AddressAttributes{
}, Address: localIP,
})) Local: localIP,
},
},
),
)
def := network.NewRouteSpec(network.NamespaceName, "default") def := network.NewRouteSpec(network.NamespaceName, "default")
*def.TypedSpec() = network.RouteSpecSpec{ *def.TypedSpec() = network.RouteSpecSpec{
@ -321,24 +357,31 @@ func (suite *RouteSpecSuite) TestDefaultAndInterfaceRoutes() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
if err := suite.assertRoute(netaddr.IPPrefix{}, netaddr.MustParseIP("10.28.0.1"), func(route rtnetlink.RouteMessage) error { func() error {
suite.Assert().Nil(route.Attributes.Dst) if err := suite.assertRoute(
suite.Assert().EqualValues(1048576, route.Attributes.Priority) netaddr.IPPrefix{}, netaddr.MustParseIP("10.28.0.1"), func(route rtnetlink.RouteMessage) error {
suite.Assert().Nil(route.Attributes.Dst)
suite.Assert().EqualValues(1048576, route.Attributes.Priority)
return nil return nil
}); err != nil { },
return err ); err != nil {
} return err
}
return suite.assertRoute(netaddr.MustParseIPPrefix("10.28.0.1/32"), netaddr.IP{}, func(route rtnetlink.RouteMessage) error { return suite.assertRoute(
suite.Assert().Nil(route.Attributes.Gateway) netaddr.MustParseIPPrefix("10.28.0.1/32"), netaddr.IP{}, func(route rtnetlink.RouteMessage) error {
suite.Assert().EqualValues(1048576, route.Attributes.Priority) suite.Assert().Nil(route.Attributes.Gateway)
suite.Assert().EqualValues(1048576, route.Attributes.Priority)
return nil return nil
}) },
})) )
},
),
)
// teardown the routes // teardown the routes
for { for {
@ -378,18 +421,22 @@ func (suite *RouteSpecSuite) TestLinkLocalRoute() {
defer conn.Close() //nolint:errcheck defer conn.Close() //nolint:errcheck
suite.Require().NoError(conn.Link.New(&rtnetlink.LinkMessage{ suite.Require().NoError(
Type: unix.ARPHRD_ETHER, conn.Link.New(
Flags: unix.IFF_UP, &rtnetlink.LinkMessage{
Change: unix.IFF_UP, Type: unix.ARPHRD_ETHER,
Attributes: &rtnetlink.LinkAttributes{ Flags: unix.IFF_UP,
Name: dummyInterface, Change: unix.IFF_UP,
MTU: 1500, Attributes: &rtnetlink.LinkAttributes{
Info: &rtnetlink.LinkInfo{ Name: dummyInterface,
Kind: "dummy", MTU: 1500,
Info: &rtnetlink.LinkInfo{
Kind: "dummy",
},
},
}, },
}, ),
})) )
iface, err := net.InterfaceByName(dummyInterface) iface, err := net.InterfaceByName(dummyInterface)
suite.Require().NoError(err) suite.Require().NoError(err)
@ -398,16 +445,20 @@ func (suite *RouteSpecSuite) TestLinkLocalRoute() {
localIP := net.ParseIP("10.28.0.27").To4() localIP := net.ParseIP("10.28.0.27").To4()
suite.Require().NoError(conn.Address.New(&rtnetlink.AddressMessage{ suite.Require().NoError(
Family: unix.AF_INET, conn.Address.New(
PrefixLength: 24, &rtnetlink.AddressMessage{
Scope: unix.RT_SCOPE_UNIVERSE, Family: unix.AF_INET,
Index: uint32(iface.Index), PrefixLength: 24,
Attributes: &rtnetlink.AddressAttributes{ Scope: unix.RT_SCOPE_UNIVERSE,
Address: localIP, Index: uint32(iface.Index),
Local: localIP, Attributes: &rtnetlink.AddressAttributes{
}, Address: localIP,
})) Local: localIP,
},
},
),
)
ll := network.NewRouteSpec(network.NamespaceName, "ll") ll := network.NewRouteSpec(network.NamespaceName, "ll")
*ll.TypedSpec() = network.RouteSpecSpec{ *ll.TypedSpec() = network.RouteSpecSpec{
@ -428,14 +479,21 @@ func (suite *RouteSpecSuite) TestLinkLocalRoute() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertRoute(netaddr.MustParseIPPrefix("169.254.169.254/32"), netaddr.MustParseIP("10.28.0.1"), func(route rtnetlink.RouteMessage) error { func() error {
suite.Assert().EqualValues(1048576, route.Attributes.Priority) return suite.assertRoute(
netaddr.MustParseIPPrefix("169.254.169.254/32"),
netaddr.MustParseIP("10.28.0.1"),
func(route rtnetlink.RouteMessage) error {
suite.Assert().EqualValues(1048576, route.Attributes.Priority)
return nil return nil
}) },
})) )
},
),
)
// teardown the routes // teardown the routes
for { for {
@ -450,7 +508,12 @@ func (suite *RouteSpecSuite) TestLinkLocalRoute() {
} }
// torn down route should be removed immediately // torn down route should be removed immediately
suite.Assert().NoError(suite.assertNoRoute(netaddr.MustParseIPPrefix("169.254.169.254/32"), netaddr.MustParseIP("10.28.0.1"))) suite.Assert().NoError(
suite.assertNoRoute(
netaddr.MustParseIPPrefix("169.254.169.254/32"),
netaddr.MustParseIP("10.28.0.1"),
),
)
suite.Require().NoError(suite.state.Destroy(suite.ctx, ll.Metadata())) suite.Require().NoError(suite.state.Destroy(suite.ctx, ll.Metadata()))
} }

View File

@ -35,7 +35,7 @@ type RouteStatusSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -71,7 +71,10 @@ func (suite *RouteStatusSuite) assertRoutes(requiredIDs []string, check func(*ne
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.NamespaceName, network.RouteStatusType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.RouteStatusType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -97,19 +100,24 @@ func (suite *RouteStatusSuite) assertRoutes(requiredIDs []string, check func(*ne
} }
func (suite *RouteStatusSuite) TestRoutes() { func (suite *RouteStatusSuite) TestRoutes() {
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertRoutes([]string{"local/inet4//127.0.0.0/8/0"}, func(r *network.RouteStatus) error { func() error {
suite.Assert().True(r.TypedSpec().Source.IsLoopback()) return suite.assertRoutes(
suite.Assert().Equal("lo", r.TypedSpec().OutLinkName) []string{"local/inet4//127.0.0.0/8/0"}, func(r *network.RouteStatus) error {
suite.Assert().Equal(nethelpers.TableLocal, r.TypedSpec().Table) suite.Assert().True(r.TypedSpec().Source.IsLoopback())
suite.Assert().Equal(nethelpers.ScopeHost, r.TypedSpec().Scope) suite.Assert().Equal("lo", r.TypedSpec().OutLinkName)
suite.Assert().Equal(nethelpers.TypeLocal, r.TypedSpec().Type) suite.Assert().Equal(nethelpers.TableLocal, r.TypedSpec().Table)
suite.Assert().Equal(nethelpers.ProtocolKernel, r.TypedSpec().Protocol) suite.Assert().Equal(nethelpers.ScopeHost, r.TypedSpec().Scope)
suite.Assert().Equal(nethelpers.TypeLocal, r.TypedSpec().Type)
suite.Assert().Equal(nethelpers.ProtocolKernel, r.TypedSpec().Protocol)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *RouteStatusSuite) TearDownTest() { func (suite *RouteStatusSuite) TearDownTest() {

View File

@ -35,7 +35,7 @@ type StatusSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -65,7 +65,10 @@ func (suite *StatusSuite) startRuntime() {
} }
func (suite *StatusSuite) assertStatus(expected network.StatusSpec) error { func (suite *StatusSuite) assertStatus(expected network.StatusSpec) error {
status, err := suite.state.Get(suite.ctx, resource.NewMetadata(network.NamespaceName, network.StatusType, network.StatusID, resource.VersionUndefined)) status, err := suite.state.Get(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.StatusType, network.StatusID, resource.VersionUndefined),
)
if err != nil { if err != nil {
if !state.IsNotFoundError(err) { if !state.IsNotFoundError(err) {
suite.Require().NoError(err) suite.Require().NoError(err)
@ -82,10 +85,13 @@ func (suite *StatusSuite) assertStatus(expected network.StatusSpec) error {
} }
func (suite *StatusSuite) TestNone() { func (suite *StatusSuite) TestNone() {
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertStatus(network.StatusSpec{}) func() error {
})) return suite.assertStatus(network.StatusSpec{})
},
),
)
} }
func (suite *StatusSuite) TestAddresses() { func (suite *StatusSuite) TestAddresses() {
@ -94,10 +100,13 @@ func (suite *StatusSuite) TestAddresses() {
suite.Require().NoError(suite.state.Create(suite.ctx, nodeAddress)) suite.Require().NoError(suite.state.Create(suite.ctx, nodeAddress))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertStatus(network.StatusSpec{AddressReady: true}) func() error {
})) return suite.assertStatus(network.StatusSpec{AddressReady: true})
},
),
)
} }
func (suite *StatusSuite) TestRoutes() { func (suite *StatusSuite) TestRoutes() {
@ -106,10 +115,13 @@ func (suite *StatusSuite) TestRoutes() {
suite.Require().NoError(suite.state.Create(suite.ctx, route)) suite.Require().NoError(suite.state.Create(suite.ctx, route))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertStatus(network.StatusSpec{ConnectivityReady: true}) func() error {
})) return suite.assertStatus(network.StatusSpec{ConnectivityReady: true})
},
),
)
} }
func (suite *StatusSuite) TestHostname() { func (suite *StatusSuite) TestHostname() {
@ -118,10 +130,13 @@ func (suite *StatusSuite) TestHostname() {
suite.Require().NoError(suite.state.Create(suite.ctx, hostname)) suite.Require().NoError(suite.state.Create(suite.ctx, hostname))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertStatus(network.StatusSpec{HostnameReady: true}) func() error {
})) return suite.assertStatus(network.StatusSpec{HostnameReady: true})
},
),
)
} }
func (suite *StatusSuite) TestEtcFiles() { func (suite *StatusSuite) TestEtcFiles() {
@ -131,10 +146,13 @@ func (suite *StatusSuite) TestEtcFiles() {
suite.Require().NoError(suite.state.Create(suite.ctx, hosts)) suite.Require().NoError(suite.state.Create(suite.ctx, hosts))
suite.Require().NoError(suite.state.Create(suite.ctx, resolv)) suite.Require().NoError(suite.state.Create(suite.ctx, resolv))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertStatus(network.StatusSpec{EtcFilesReady: true}) func() error {
})) return suite.assertStatus(network.StatusSpec{EtcFilesReady: true})
},
),
)
} }
func (suite *StatusSuite) TearDownTest() { func (suite *StatusSuite) TearDownTest() {
@ -145,9 +163,24 @@ func (suite *StatusSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewNodeAddress(network.NamespaceName, "bar"))) suite.Assert().NoError(
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewResolverStatus(network.NamespaceName, "bar"))) suite.state.Create(
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewHostnameStatus(network.NamespaceName, "bar"))) context.Background(),
network.NewNodeAddress(network.NamespaceName, "bar"),
),
)
suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewResolverStatus(network.NamespaceName, "bar"),
),
)
suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewHostnameStatus(network.NamespaceName, "bar"),
),
)
suite.Assert().NoError(suite.state.Create(context.Background(), files.NewEtcFileStatus(files.NamespaceName, "bar"))) suite.Assert().NoError(suite.state.Create(context.Background(), files.NewEtcFileStatus(files.NamespaceName, "bar")))
} }

View File

@ -39,7 +39,7 @@ type TimeServerConfigSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -64,14 +64,20 @@ func (suite *TimeServerConfigSuite) startRuntime() {
}() }()
} }
func (suite *TimeServerConfigSuite) assertTimeServers(requiredIDs []string, check func(*network.TimeServerSpec) error) error { func (suite *TimeServerConfigSuite) assertTimeServers(
requiredIDs []string,
check func(*network.TimeServerSpec) error,
) error {
missingIDs := make(map[string]struct{}, len(requiredIDs)) missingIDs := make(map[string]struct{}, len(requiredIDs))
for _, id := range requiredIDs { for _, id := range requiredIDs {
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.ConfigNamespaceName, network.TimeServerSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.ConfigNamespaceName, network.TimeServerSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -97,7 +103,10 @@ func (suite *TimeServerConfigSuite) assertTimeServers(requiredIDs []string, chec
} }
func (suite *TimeServerConfigSuite) assertNoTimeServer(id string) error { func (suite *TimeServerConfigSuite) assertNoTimeServer(id string) error {
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.ConfigNamespaceName, network.TimeServerSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.ConfigNamespaceName, network.TimeServerSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -116,36 +125,50 @@ func (suite *TimeServerConfigSuite) TestDefaults() {
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertTimeServers([]string{ func() error {
"default/timeservers", return suite.assertTimeServers(
}, func(r *network.TimeServerSpec) error { []string{
suite.Assert().Equal([]string{constants.DefaultNTPServer}, r.TypedSpec().NTPServers) "default/timeservers",
suite.Assert().Equal(network.ConfigDefault, r.TypedSpec().ConfigLayer) }, func(r *network.TimeServerSpec) error {
suite.Assert().Equal([]string{constants.DefaultNTPServer}, r.TypedSpec().NTPServers)
suite.Assert().Equal(network.ConfigDefault, r.TypedSpec().ConfigLayer)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *TimeServerConfigSuite) TestCmdline() { func (suite *TimeServerConfigSuite) TestCmdline() {
suite.Require().NoError(suite.runtime.RegisterController(&netctrl.TimeServerConfigController{ suite.Require().NoError(
Cmdline: procfs.NewCmdline("ip=172.20.0.2:172.21.0.1:172.20.0.1:255.255.255.0:master1:eth1::10.0.0.1:10.0.0.2:10.0.0.1"), suite.runtime.RegisterController(
})) &netctrl.TimeServerConfigController{
Cmdline: procfs.NewCmdline("ip=172.20.0.2:172.21.0.1:172.20.0.1:255.255.255.0:master1:eth1::10.0.0.1:10.0.0.2:10.0.0.1"),
},
),
)
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertTimeServers([]string{ func() error {
"cmdline/timeservers", return suite.assertTimeServers(
}, func(r *network.TimeServerSpec) error { []string{
suite.Assert().Equal([]string{"10.0.0.1"}, r.TypedSpec().NTPServers) "cmdline/timeservers",
}, func(r *network.TimeServerSpec) error {
suite.Assert().Equal([]string{"10.0.0.1"}, r.TypedSpec().NTPServers)
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *TimeServerConfigSuite) TestMachineConfiguration() { func (suite *TimeServerConfigSuite) TestMachineConfiguration() {
@ -156,46 +179,58 @@ func (suite *TimeServerConfigSuite) TestMachineConfiguration() {
u, err := url.Parse("https://foo:6443") u, err := url.Parse("https://foo:6443")
suite.Require().NoError(err) suite.Require().NoError(err)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{ ConfigVersion: "v1alpha1",
MachineTime: &v1alpha1.TimeConfig{ MachineConfig: &v1alpha1.MachineConfig{
TimeServers: []string{"za.pool.ntp.org", "pool.ntp.org"}, MachineTime: &v1alpha1.TimeConfig{
TimeServers: []string{"za.pool.ntp.org", "pool.ntp.org"},
},
}, },
}, ClusterConfig: &v1alpha1.ClusterConfig{
ClusterConfig: &v1alpha1.ClusterConfig{ ControlPlane: &v1alpha1.ControlPlaneConfig{
ControlPlane: &v1alpha1.ControlPlaneConfig{ Endpoint: &v1alpha1.Endpoint{
Endpoint: &v1alpha1.Endpoint{ URL: u,
URL: u, },
}, },
}, },
}, },
}) )
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertTimeServers([]string{ func() error {
"configuration/timeservers", return suite.assertTimeServers(
}, func(r *network.TimeServerSpec) error { []string{
suite.Assert().Equal([]string{"za.pool.ntp.org", "pool.ntp.org"}, r.TypedSpec().NTPServers) "configuration/timeservers",
}, func(r *network.TimeServerSpec) error {
suite.Assert().Equal([]string{"za.pool.ntp.org", "pool.ntp.org"}, r.TypedSpec().NTPServers)
return nil return nil
}) },
})) )
},
),
)
_, err = suite.state.UpdateWithConflicts(suite.ctx, cfg.Metadata(), func(r resource.Resource) error { _, err = suite.state.UpdateWithConflicts(
r.(*config.MachineConfig).Config().(*v1alpha1.Config).MachineConfig.MachineTime = nil suite.ctx, cfg.Metadata(), func(r resource.Resource) error {
r.(*config.MachineConfig).Config().(*v1alpha1.Config).MachineConfig.MachineTime = nil
return nil return nil
}) },
)
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertNoTimeServer("configuration/timeservers") func() error {
})) return suite.assertNoTimeServer("configuration/timeservers")
},
),
)
} }
func (suite *TimeServerConfigSuite) TearDownTest() { func (suite *TimeServerConfigSuite) TearDownTest() {
@ -206,10 +241,14 @@ func (suite *TimeServerConfigSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ err := suite.state.Create(
ConfigVersion: "v1alpha1", context.Background(), config.NewMachineConfig(
MachineConfig: &v1alpha1.MachineConfig{}, &v1alpha1.Config{
})) ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{},
},
),
)
if state.IsConflictError(err) { if state.IsConflictError(err) {
err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata())
} }

View File

@ -36,7 +36,7 @@ type TimeServerMergeSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -65,14 +65,20 @@ func (suite *TimeServerMergeSuite) startRuntime() {
}() }()
} }
func (suite *TimeServerMergeSuite) assertTimeServers(requiredIDs []string, check func(*network.TimeServerSpec) error) error { func (suite *TimeServerMergeSuite) assertTimeServers(
requiredIDs []string,
check func(*network.TimeServerSpec) error,
) error {
missingIDs := make(map[string]struct{}, len(requiredIDs)) missingIDs := make(map[string]struct{}, len(requiredIDs))
for _, id := range requiredIDs { for _, id := range requiredIDs {
missingIDs[id] = struct{}{} missingIDs[id] = struct{}{}
} }
resources, err := suite.state.List(suite.ctx, resource.NewMetadata(network.NamespaceName, network.TimeServerSpecType, "", resource.VersionUndefined)) resources, err := suite.state.List(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.TimeServerSpecType, "", resource.VersionUndefined),
)
if err != nil { if err != nil {
return err return err
} }
@ -126,31 +132,41 @@ func (suite *TimeServerMergeSuite) TestMerge() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertTimeServers([]string{ func() error {
"timeservers", return suite.assertTimeServers(
}, func(r *network.TimeServerSpec) error { []string{
suite.Assert().Equal(*static.TypedSpec(), *r.TypedSpec()) "timeservers",
}, func(r *network.TimeServerSpec) error {
suite.Assert().Equal(*static.TypedSpec(), *r.TypedSpec())
return nil return nil
}) },
})) )
},
),
)
suite.Require().NoError(suite.state.Destroy(suite.ctx, static.Metadata())) suite.Require().NoError(suite.state.Destroy(suite.ctx, static.Metadata()))
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertTimeServers([]string{ func() error {
"timeservers", return suite.assertTimeServers(
}, func(r *network.TimeServerSpec) error { []string{
if !reflect.DeepEqual(r.TypedSpec().NTPServers, []string{"ntp.eth0", "ntp.eth1"}) { "timeservers",
return retry.ExpectedErrorf("unexpected servers %q", r.TypedSpec().NTPServers) }, func(r *network.TimeServerSpec) error {
} if !reflect.DeepEqual(r.TypedSpec().NTPServers, []string{"ntp.eth0", "ntp.eth1"}) {
return retry.ExpectedErrorf("unexpected servers %q", r.TypedSpec().NTPServers)
}
return nil return nil
}) },
})) )
},
),
)
} }
func (suite *TimeServerMergeSuite) TearDownTest() { func (suite *TimeServerMergeSuite) TearDownTest() {
@ -161,7 +177,12 @@ func (suite *TimeServerMergeSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewTimeServerSpec(network.ConfigNamespaceName, "bar"))) suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewTimeServerSpec(network.ConfigNamespaceName, "bar"),
),
)
} }
func TestTimeServerMergeSuite(t *testing.T) { func TestTimeServerMergeSuite(t *testing.T) {

View File

@ -35,7 +35,7 @@ type TimeServerSpecSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -65,7 +65,10 @@ func (suite *TimeServerSpecSuite) startRuntime() {
} }
func (suite *TimeServerSpecSuite) assertStatus(id string, servers ...string) error { func (suite *TimeServerSpecSuite) assertStatus(id string, servers ...string) error {
r, err := suite.state.Get(suite.ctx, resource.NewMetadata(network.NamespaceName, network.TimeServerStatusType, id, resource.VersionUndefined)) r, err := suite.state.Get(
suite.ctx,
resource.NewMetadata(network.NamespaceName, network.TimeServerStatusType, id, resource.VersionUndefined),
)
if err != nil { if err != nil {
if state.IsNotFoundError(err) { if state.IsNotFoundError(err) {
return retry.ExpectedError(err) return retry.ExpectedError(err)
@ -94,10 +97,13 @@ func (suite *TimeServerSpecSuite) TestSpec() {
suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec()) suite.Require().NoError(suite.state.Create(suite.ctx, res), "%v", res.Spec())
} }
suite.Assert().NoError(retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(3*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertStatus("timeservers", constants.DefaultNTPServer) func() error {
})) return suite.assertStatus("timeservers", constants.DefaultNTPServer)
},
),
)
} }
func (suite *TimeServerSpecSuite) TearDownTest() { func (suite *TimeServerSpecSuite) TearDownTest() {
@ -108,7 +114,12 @@ func (suite *TimeServerSpecSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
suite.Assert().NoError(suite.state.Create(context.Background(), network.NewTimeServerSpec(network.NamespaceName, "bar"))) suite.Assert().NoError(
suite.state.Create(
context.Background(),
network.NewTimeServerSpec(network.NamespaceName, "bar"),
),
)
} }
func TestTimeServerSpecSuite(t *testing.T) { func TestTimeServerSpecSuite(t *testing.T) {

View File

@ -33,6 +33,7 @@ type PerfSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
//nolint:containedctx
ctx context.Context ctx context.Context
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -65,36 +66,54 @@ func (suite *PerfSuite) TestReconcile() {
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
cpu, err := suite.state.Get(suite.ctx, resource.NewMetadata(perfresource.NamespaceName, perfresource.CPUType, perfresource.CPUID, resource.VersionUndefined)) func() error {
if err != nil { cpu, err := suite.state.Get(
if state.IsNotFoundError(err) { suite.ctx,
return retry.ExpectedError(err) resource.NewMetadata(
perfresource.NamespaceName,
perfresource.CPUType,
perfresource.CPUID,
resource.VersionUndefined,
),
)
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
}
return err
} }
return err mem, err := suite.state.Get(
} suite.ctx,
resource.NewMetadata(
perfresource.NamespaceName,
perfresource.MemoryType,
perfresource.MemoryID,
resource.VersionUndefined,
),
)
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
}
mem, err := suite.state.Get(suite.ctx, resource.NewMetadata(perfresource.NamespaceName, perfresource.MemoryType, perfresource.MemoryID, resource.VersionUndefined)) return err
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
} }
return err cpuSpec := cpu.Spec().(*perfresource.CPUSpec) //nolint:errcheck,forcetypeassert
} memSpec := mem.Spec().(*perfresource.MemorySpec) //nolint:errcheck,forcetypeassert
cpuSpec := cpu.Spec().(*perfresource.CPUSpec) //nolint:errcheck,forcetypeassert if len(cpuSpec.CPU) == 0 || memSpec.MemTotal == 0 {
memSpec := mem.Spec().(*perfresource.MemorySpec) //nolint:errcheck,forcetypeassert return retry.ExpectedError(fmt.Errorf("cpu spec does not contain any CPU or Total memory is zero"))
}
if len(cpuSpec.CPU) == 0 || memSpec.MemTotal == 0 { return nil
return retry.ExpectedError(fmt.Errorf("cpu spec does not contain any CPU or Total memory is zero")) },
} ),
)
return nil
},
))
} }
func (suite *PerfSuite) TearDownTest() { func (suite *PerfSuite) TearDownTest() {

View File

@ -38,7 +38,7 @@ type RuntimeSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -92,10 +92,14 @@ func (suite *RuntimeSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ err := suite.state.Create(
ConfigVersion: "v1alpha1", context.Background(), config.NewMachineConfig(
MachineConfig: &v1alpha1.MachineConfig{}, &v1alpha1.Config{
})) ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{},
},
),
)
if state.IsConflictError(err) { if state.IsConflictError(err) {
err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata())
} }

View File

@ -64,7 +64,7 @@ type EventsSinkSuite struct {
wg sync.WaitGroup wg sync.WaitGroup
eg errgroup.Group eg errgroup.Group
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -84,11 +84,15 @@ func (suite *EventsSinkSuite) SetupTest() {
suite.cmdline = procfs.NewCmdline(fmt.Sprintf("%s=%s", constants.KernelParamEventsSink, "localhost")) suite.cmdline = procfs.NewCmdline(fmt.Sprintf("%s=%s", constants.KernelParamEventsSink, "localhost"))
suite.drainer = talosruntime.NewDrainer() suite.drainer = talosruntime.NewDrainer()
suite.Require().NoError(suite.runtime.RegisterController(&controllerruntime.EventsSinkController{ suite.Require().NoError(
V1Alpha1Events: suite.events, suite.runtime.RegisterController(
Cmdline: suite.cmdline, &controllerruntime.EventsSinkController{
Drainer: suite.drainer, V1Alpha1Events: suite.events,
})) Cmdline: suite.cmdline,
Drainer: suite.drainer,
},
),
)
suite.startRuntime() suite.startRuntime()
} }
@ -121,46 +125,56 @@ func (suite *EventsSinkSuite) startServer(ctx context.Context) {
suite.server = grpc.NewServer() suite.server = grpc.NewServer()
eventsapi.RegisterEventSinkServiceServer(suite.server, suite.sink) eventsapi.RegisterEventSinkServiceServer(suite.server, suite.sink)
suite.eg.Go(func() error { suite.eg.Go(
<-ctx.Done() func() error {
<-ctx.Done()
suite.server.Stop() suite.server.Stop()
return nil return nil
}) },
)
suite.eg.Go(func() error { suite.eg.Go(
return suite.server.Serve(lis) func() error {
}) return suite.server.Serve(lis)
},
)
} }
func (suite *EventsSinkSuite) TestPublish() { func (suite *EventsSinkSuite) TestPublish() {
ctx, cancel := context.WithCancel(suite.ctx) ctx, cancel := context.WithCancel(suite.ctx)
defer cancel() defer cancel()
suite.events.Publish(&machine.AddressEvent{ suite.events.Publish(
Hostname: "localhost", &machine.AddressEvent{
}) Hostname: "localhost",
},
)
suite.events.Publish(&machine.PhaseEvent{ suite.events.Publish(
Phase: "test", &machine.PhaseEvent{
Action: machine.PhaseEvent_START, Phase: "test",
}) Action: machine.PhaseEvent_START,
},
)
suite.Require().Equal(0, len(suite.handler.events)) suite.Require().Equal(0, len(suite.handler.events))
suite.startServer(ctx) suite.startServer(ctx)
err := retry.Constant(time.Second*5, retry.WithUnits(time.Millisecond*100)).Retry(func() error { err := retry.Constant(time.Second*5, retry.WithUnits(time.Millisecond*100)).Retry(
suite.handler.eventsMu.Lock() func() error {
defer suite.handler.eventsMu.Unlock() suite.handler.eventsMu.Lock()
defer suite.handler.eventsMu.Unlock()
if len(suite.handler.events) != 2 { if len(suite.handler.events) != 2 {
return retry.ExpectedErrorf("expected 2 events") return retry.ExpectedErrorf("expected 2 events")
} }
return nil return nil
}) },
)
suite.Require().NoError(err) suite.Require().NoError(err)
} }
@ -169,14 +183,18 @@ func (suite *EventsSinkSuite) TestDrain() {
defer cancel() defer cancel()
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
suite.events.Publish(&machine.PhaseEvent{ suite.events.Publish(
Phase: "test", &machine.PhaseEvent{
Action: machine.PhaseEvent_START, Phase: "test",
}) Action: machine.PhaseEvent_START,
suite.events.Publish(&machine.PhaseEvent{ },
Phase: "test", )
Action: machine.PhaseEvent_STOP, suite.events.Publish(
}) &machine.PhaseEvent{
Phase: "test",
Action: machine.PhaseEvent_STOP,
},
)
} }
suite.Require().Equal(0, len(suite.handler.events)) suite.Require().Equal(0, len(suite.handler.events))
@ -188,28 +206,34 @@ func (suite *EventsSinkSuite) TestDrain() {
var eg errgroup.Group var eg errgroup.Group
eg.Go(func() error { eg.Go(
return suite.drainer.Drain(c) func() error {
}) return suite.drainer.Drain(c)
},
)
eg.Go(func() error { eg.Go(
time.Sleep(time.Millisecond * 300) func() error {
time.Sleep(time.Millisecond * 300)
suite.startServer(ctx) suite.startServer(ctx)
return nil return nil
}) },
)
err := retry.Constant(time.Second*5, retry.WithUnits(time.Millisecond*100)).Retry(func() error { err := retry.Constant(time.Second*5, retry.WithUnits(time.Millisecond*100)).Retry(
suite.handler.eventsMu.Lock() func() error {
defer suite.handler.eventsMu.Unlock() suite.handler.eventsMu.Lock()
defer suite.handler.eventsMu.Unlock()
if len(suite.handler.events) != 20 { if len(suite.handler.events) != 20 {
return retry.ExpectedErrorf("expected 20 events, got %d", len(suite.handler.events)) return retry.ExpectedErrorf("expected 20 events, got %d", len(suite.handler.events))
} }
return nil return nil
}) },
)
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Require().NoError(eg.Wait()) suite.Require().NoError(eg.Wait())

View File

@ -60,7 +60,7 @@ type KmsgLogDeliverySuite struct {
drainer *talosruntime.Drainer drainer *talosruntime.Drainer
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
handler *logHandler handler *logHandler
@ -92,13 +92,23 @@ func (suite *KmsgLogDeliverySuite) SetupTest() {
suite.srv.Serve() //nolint:errcheck suite.srv.Serve() //nolint:errcheck
}() }()
suite.cmdline = procfs.NewCmdline(fmt.Sprintf("%s=%s", constants.KernelParamLoggingKernel, fmt.Sprintf("tcp://%s", listener.Addr()))) suite.cmdline = procfs.NewCmdline(
fmt.Sprintf(
"%s=%s",
constants.KernelParamLoggingKernel,
fmt.Sprintf("tcp://%s", listener.Addr()),
),
)
suite.drainer = talosruntime.NewDrainer() suite.drainer = talosruntime.NewDrainer()
suite.Require().NoError(suite.runtime.RegisterController(&controllerruntime.KmsgLogDeliveryController{ suite.Require().NoError(
Cmdline: suite.cmdline, suite.runtime.RegisterController(
Drainer: suite.drainer, &controllerruntime.KmsgLogDeliveryController{
})) Cmdline: suite.cmdline,
Drainer: suite.drainer,
},
),
)
status := network.NewStatus(network.NamespaceName, network.StatusID) status := network.NewStatus(network.NamespaceName, network.StatusID)
status.TypedSpec().AddressReady = true status.TypedSpec().AddressReady = true
@ -120,13 +130,15 @@ func (suite *KmsgLogDeliverySuite) TestDelivery() {
suite.startRuntime() suite.startRuntime()
// controller should deliver some kernel logs from host's kmsg buffer // controller should deliver some kernel logs from host's kmsg buffer
err := retry.Constant(time.Second*5, retry.WithUnits(time.Millisecond*100)).Retry(func() error { err := retry.Constant(time.Second*5, retry.WithUnits(time.Millisecond*100)).Retry(
if suite.handler.getCount() == 0 { func() error {
return retry.ExpectedErrorf("no logs received") if suite.handler.getCount() == 0 {
} return retry.ExpectedErrorf("no logs received")
}
return nil return nil
}) },
)
suite.Require().NoError(err) suite.Require().NoError(err)
} }
@ -134,13 +146,15 @@ func (suite *KmsgLogDeliverySuite) TestDrain() {
suite.startRuntime() suite.startRuntime()
// wait for controller to start delivering some logs // wait for controller to start delivering some logs
err := retry.Constant(time.Second*5, retry.WithUnits(time.Millisecond*100)).Retry(func() error { err := retry.Constant(time.Second*5, retry.WithUnits(time.Millisecond*100)).Retry(
if suite.handler.getCount() == 0 { func() error {
return retry.ExpectedErrorf("no logs received") if suite.handler.getCount() == 0 {
} return retry.ExpectedErrorf("no logs received")
}
return nil return nil
}) },
)
suite.Require().NoError(err) suite.Require().NoError(err)
// drain should be successful, i.e. controller should stop on its own before context is canceled // drain should be successful, i.e. controller should stop on its own before context is canceled

View File

@ -332,7 +332,8 @@ func (ctrl *APIController) generateControlPlane(ctx context.Context, r controlle
} }
func (ctrl *APIController) generateJoin(ctx context.Context, r controller.Runtime, logger *zap.Logger, func (ctrl *APIController) generateJoin(ctx context.Context, r controller.Runtime, logger *zap.Logger,
rootSpec *secrets.OSRootSpec, endpointsStr []string, certSANs *secrets.CertSANSpec) error { rootSpec *secrets.OSRootSpec, endpointsStr []string, certSANs *secrets.CertSANSpec,
) error {
remoteGen, err := gen.NewRemoteGenerator(rootSpec.Token, endpointsStr, rootSpec.CA) remoteGen, err := gen.NewRemoteGenerator(rootSpec.Token, endpointsStr, rootSpec.CA)
if err != nil { if err != nil {
return fmt.Errorf("failed creating trustd client: %w", err) return fmt.Errorf("failed creating trustd client: %w", err)

View File

@ -37,7 +37,7 @@ type APICertSANsSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -78,30 +78,46 @@ func (suite *APICertSANsSuite) TestReconcileControlPlane() {
hostnameStatus.TypedSpec().Domainname = "some.org" hostnameStatus.TypedSpec().Domainname = "some.org"
suite.Require().NoError(suite.state.Create(suite.ctx, hostnameStatus)) suite.Require().NoError(suite.state.Create(suite.ctx, hostnameStatus))
nodeAddresses := network.NewNodeAddress(network.NamespaceName, network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, k8s.NodeAddressFilterNoK8s)) nodeAddresses := network.NewNodeAddress(
nodeAddresses.TypedSpec().Addresses = []netaddr.IPPrefix{netaddr.MustParseIPPrefix("10.2.1.3/24"), netaddr.MustParseIPPrefix("172.16.0.1/32")} network.NamespaceName,
network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, k8s.NodeAddressFilterNoK8s),
)
nodeAddresses.TypedSpec().Addresses = []netaddr.IPPrefix{
netaddr.MustParseIPPrefix("10.2.1.3/24"),
netaddr.MustParseIPPrefix("172.16.0.1/32"),
}
suite.Require().NoError(suite.state.Create(suite.ctx, nodeAddresses)) suite.Require().NoError(suite.state.Create(suite.ctx, nodeAddresses))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
certSANs, err := suite.state.Get(suite.ctx, resource.NewMetadata(secrets.NamespaceName, secrets.CertSANType, secrets.CertSANAPIID, resource.VersionUndefined)) func() error {
if err != nil { certSANs, err := suite.state.Get(
if state.IsNotFoundError(err) { suite.ctx,
return retry.ExpectedError(err) resource.NewMetadata(
secrets.NamespaceName,
secrets.CertSANType,
secrets.CertSANAPIID,
resource.VersionUndefined,
),
)
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
}
return err
} }
return err spec := certSANs.(*secrets.CertSAN).TypedSpec()
}
spec := certSANs.(*secrets.CertSAN).TypedSpec() suite.Assert().Equal([]string{"bar", "bar.some.org", "some.org"}, spec.DNSNames)
suite.Assert().Equal("[10.2.1.3 10.4.3.2 172.16.0.1]", fmt.Sprintf("%v", spec.IPs))
suite.Assert().Equal("bar.some.org", spec.FQDN)
suite.Assert().Equal([]string{"bar", "bar.some.org", "some.org"}, spec.DNSNames) return nil
suite.Assert().Equal("[10.2.1.3 10.4.3.2 172.16.0.1]", fmt.Sprintf("%v", spec.IPs)) },
suite.Assert().Equal("bar.some.org", spec.FQDN) ),
)
return nil
},
))
} }
func (suite *APICertSANsSuite) TearDownTest() { func (suite *APICertSANsSuite) TearDownTest() {

View File

@ -41,7 +41,7 @@ type APISuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -110,49 +110,65 @@ func (suite *APISuite) TestReconcileControlPlane() {
suite.Require().NoError(suite.state.Create(suite.ctx, certSANs)) suite.Require().NoError(suite.state.Create(suite.ctx, certSANs))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
certs, err := suite.state.Get(suite.ctx, resource.NewMetadata(secrets.NamespaceName, secrets.APIType, secrets.APIID, resource.VersionUndefined)) func() error {
if err != nil { certs, err := suite.state.Get(
if state.IsNotFoundError(err) { suite.ctx,
return retry.ExpectedError(err) resource.NewMetadata(
secrets.NamespaceName,
secrets.APIType,
secrets.APIID,
resource.VersionUndefined,
),
)
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
}
return err
} }
return err apiCerts := certs.(*secrets.API).TypedSpec()
}
apiCerts := certs.(*secrets.API).TypedSpec() suite.Assert().Equal(talosCA.CrtPEM, apiCerts.CA.Crt)
suite.Assert().Nil(apiCerts.CA.Key)
suite.Assert().Equal(talosCA.CrtPEM, apiCerts.CA.Crt) serverCert, err := apiCerts.Server.GetCert()
suite.Assert().Nil(apiCerts.CA.Key) suite.Require().NoError(err)
serverCert, err := apiCerts.Server.GetCert() suite.Assert().Equal([]string{"example.com", "foo", "foo.example.com"}, serverCert.DNSNames)
suite.Require().NoError(err) suite.Assert().Equal("[10.2.1.3 10.4.3.2 172.16.0.1]", fmt.Sprintf("%v", serverCert.IPAddresses))
suite.Assert().Equal([]string{"example.com", "foo", "foo.example.com"}, serverCert.DNSNames) suite.Assert().Equal("foo.example.com", serverCert.Subject.CommonName)
suite.Assert().Equal("[10.2.1.3 10.4.3.2 172.16.0.1]", fmt.Sprintf("%v", serverCert.IPAddresses)) suite.Assert().Empty(serverCert.Subject.Organization)
suite.Assert().Equal("foo.example.com", serverCert.Subject.CommonName) suite.Assert().Equal(
suite.Assert().Empty(serverCert.Subject.Organization) stdlibx509.KeyUsageDigitalSignature|stdlibx509.KeyUsageKeyEncipherment,
serverCert.KeyUsage,
)
suite.Assert().Equal([]stdlibx509.ExtKeyUsage{stdlibx509.ExtKeyUsageServerAuth}, serverCert.ExtKeyUsage)
suite.Assert().Equal(stdlibx509.KeyUsageDigitalSignature|stdlibx509.KeyUsageKeyEncipherment, serverCert.KeyUsage) clientCert, err := apiCerts.Client.GetCert()
suite.Assert().Equal([]stdlibx509.ExtKeyUsage{stdlibx509.ExtKeyUsageServerAuth}, serverCert.ExtKeyUsage) suite.Require().NoError(err)
clientCert, err := apiCerts.Client.GetCert() suite.Assert().Empty(clientCert.DNSNames)
suite.Require().NoError(err) suite.Assert().Empty(clientCert.IPAddresses)
suite.Assert().Empty(clientCert.DNSNames) suite.Assert().Equal("foo.example.com", clientCert.Subject.CommonName)
suite.Assert().Empty(clientCert.IPAddresses) suite.Assert().Equal([]string{string(role.Impersonator)}, clientCert.Subject.Organization)
suite.Assert().Equal("foo.example.com", clientCert.Subject.CommonName) suite.Assert().Equal(
suite.Assert().Equal([]string{string(role.Impersonator)}, clientCert.Subject.Organization) stdlibx509.KeyUsageDigitalSignature|stdlibx509.KeyUsageKeyEncipherment,
clientCert.KeyUsage,
)
suite.Assert().Equal([]stdlibx509.ExtKeyUsage{stdlibx509.ExtKeyUsageClientAuth}, clientCert.ExtKeyUsage)
suite.Assert().Equal(stdlibx509.KeyUsageDigitalSignature|stdlibx509.KeyUsageKeyEncipherment, clientCert.KeyUsage) return nil
suite.Assert().Equal([]stdlibx509.ExtKeyUsage{stdlibx509.ExtKeyUsageClientAuth}, clientCert.ExtKeyUsage) },
),
return nil )
},
))
} }
func (suite *APISuite) TearDownTest() { func (suite *APISuite) TearDownTest() {

View File

@ -37,7 +37,7 @@ type KubeletSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -75,43 +75,55 @@ func (suite *KubeletSuite) TestReconcile() {
k8sCA := x509.NewCertificateAndKeyFromCertificateAuthority(ca) k8sCA := x509.NewCertificateAndKeyFromCertificateAuthority(ca)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{}, ConfigVersion: "v1alpha1",
ClusterConfig: &v1alpha1.ClusterConfig{ MachineConfig: &v1alpha1.MachineConfig{},
ControlPlane: &v1alpha1.ControlPlaneConfig{ ClusterConfig: &v1alpha1.ClusterConfig{
Endpoint: &v1alpha1.Endpoint{ ControlPlane: &v1alpha1.ControlPlaneConfig{
URL: u, Endpoint: &v1alpha1.Endpoint{
URL: u,
},
}, },
ClusterCA: k8sCA,
BootstrapToken: "abc.def",
}, },
ClusterCA: k8sCA,
BootstrapToken: "abc.def",
}, },
}) )
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
kubeletSecrets, err := suite.state.Get(suite.ctx, resource.NewMetadata(secrets.NamespaceName, secrets.KubeletType, secrets.KubeletID, resource.VersionUndefined)) func() error {
if err != nil { kubeletSecrets, err := suite.state.Get(
if state.IsNotFoundError(err) { suite.ctx,
return retry.ExpectedError(err) resource.NewMetadata(
secrets.NamespaceName,
secrets.KubeletType,
secrets.KubeletID,
resource.VersionUndefined,
),
)
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
}
return err
} }
return err spec := kubeletSecrets.(*secrets.Kubelet).TypedSpec()
}
spec := kubeletSecrets.(*secrets.Kubelet).TypedSpec() suite.Assert().Equal("https://foo:6443", spec.Endpoint.String())
suite.Assert().Equal(k8sCA, spec.CA)
suite.Assert().Equal("abc", spec.BootstrapTokenID)
suite.Assert().Equal("def", spec.BootstrapTokenSecret)
suite.Assert().Equal("https://foo:6443", spec.Endpoint.String()) return nil
suite.Assert().Equal(k8sCA, spec.CA) },
suite.Assert().Equal("abc", spec.BootstrapTokenID) ),
suite.Assert().Equal("def", spec.BootstrapTokenSecret) )
return nil
},
))
} }
func (suite *KubeletSuite) TearDownTest() { func (suite *KubeletSuite) TearDownTest() {

View File

@ -177,7 +177,8 @@ func (ctrl *KubernetesController) Run(ctx context.Context, r controller.Runtime,
} }
func (ctrl *KubernetesController) updateSecrets(k8sRoot *secrets.KubernetesRootSpec, k8sSecrets *secrets.KubernetesCertsSpec, func (ctrl *KubernetesController) updateSecrets(k8sRoot *secrets.KubernetesRootSpec, k8sSecrets *secrets.KubernetesCertsSpec,
certSANs *secrets.CertSANSpec) error { certSANs *secrets.CertSANSpec,
) error {
ca, err := x509.NewCertificateAuthorityFromCertificateAndKey(k8sRoot.CA) ca, err := x509.NewCertificateAuthorityFromCertificateAndKey(k8sRoot.CA)
if err != nil { if err != nil {
return fmt.Errorf("failed to parse CA certificate: %w", err) return fmt.Errorf("failed to parse CA certificate: %w", err)

View File

@ -39,7 +39,7 @@ type KubernetesCertSANsSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -86,40 +86,57 @@ func (suite *KubernetesCertSANsSuite) TestReconcile() {
hostnameStatus.TypedSpec().Domainname = "example.com" hostnameStatus.TypedSpec().Domainname = "example.com"
suite.Require().NoError(suite.state.Create(suite.ctx, hostnameStatus)) suite.Require().NoError(suite.state.Create(suite.ctx, hostnameStatus))
nodeAddresses := network.NewNodeAddress(network.NamespaceName, network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, k8s.NodeAddressFilterNoK8s)) nodeAddresses := network.NewNodeAddress(
nodeAddresses.TypedSpec().Addresses = []netaddr.IPPrefix{netaddr.MustParseIPPrefix("10.2.1.3/24"), netaddr.MustParseIPPrefix("172.16.0.1/32")} network.NamespaceName,
network.FilteredNodeAddressID(network.NodeAddressAccumulativeID, k8s.NodeAddressFilterNoK8s),
)
nodeAddresses.TypedSpec().Addresses = []netaddr.IPPrefix{
netaddr.MustParseIPPrefix("10.2.1.3/24"),
netaddr.MustParseIPPrefix("172.16.0.1/32"),
}
suite.Require().NoError(suite.state.Create(suite.ctx, nodeAddresses)) suite.Require().NoError(suite.state.Create(suite.ctx, nodeAddresses))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
certSANs, err := suite.state.Get(suite.ctx, resource.NewMetadata(secrets.NamespaceName, secrets.CertSANType, secrets.CertSANKubernetesID, resource.VersionUndefined)) func() error {
if err != nil { certSANs, err := suite.state.Get(
if state.IsNotFoundError(err) { suite.ctx,
return retry.ExpectedError(err) resource.NewMetadata(
secrets.NamespaceName,
secrets.CertSANType,
secrets.CertSANKubernetesID,
resource.VersionUndefined,
),
)
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
}
return err
} }
return err spec := certSANs.(*secrets.CertSAN).TypedSpec()
}
spec := certSANs.(*secrets.CertSAN).TypedSpec() suite.Assert().Equal(
[]string{
"example.com",
"foo",
"foo.example.com",
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster.remote",
"localhost",
"some.url",
}, spec.DNSNames,
)
suite.Assert().Equal("[10.2.1.3 10.4.3.2 172.16.0.1]", fmt.Sprintf("%v", spec.IPs))
suite.Assert().Equal( return nil
[]string{ },
"example.com", ),
"foo", )
"foo.example.com",
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster.remote",
"localhost",
"some.url",
}, spec.DNSNames)
suite.Assert().Equal("[10.2.1.3 10.4.3.2 172.16.0.1]", fmt.Sprintf("%v", spec.IPs))
return nil
},
))
} }
func (suite *KubernetesCertSANsSuite) TearDownTest() { func (suite *KubernetesCertSANsSuite) TearDownTest() {

View File

@ -44,7 +44,7 @@ type KubernetesSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -138,81 +138,116 @@ func (suite *KubernetesSuite) TestReconcile() {
suite.Require().NoError(suite.state.Create(suite.ctx, certSANs)) suite.Require().NoError(suite.state.Create(suite.ctx, certSANs))
timeSync := timeresource.NewStatus() timeSync := timeresource.NewStatus()
timeSync.SetStatus(timeresource.StatusSpec{ timeSync.SetStatus(
Synced: true, timeresource.StatusSpec{
}) Synced: true,
},
)
suite.Require().NoError(suite.state.Create(suite.ctx, timeSync)) suite.Require().NoError(suite.state.Create(suite.ctx, timeSync))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
certs, err := suite.state.Get(suite.ctx, resource.NewMetadata(secrets.NamespaceName, secrets.KubernetesType, secrets.KubernetesID, resource.VersionUndefined)) func() error {
if err != nil { certs, err := suite.state.Get(
if state.IsNotFoundError(err) { suite.ctx,
return retry.ExpectedError(err) resource.NewMetadata(
secrets.NamespaceName,
secrets.KubernetesType,
secrets.KubernetesID,
resource.VersionUndefined,
),
)
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
}
return err
} }
return err kubernetesCerts := certs.(*secrets.Kubernetes).Certs()
}
kubernetesCerts := certs.(*secrets.Kubernetes).Certs() apiCert, err := kubernetesCerts.APIServer.GetCert()
apiCert, err := kubernetesCerts.APIServer.GetCert()
suite.Require().NoError(err)
suite.Assert().Equal(
[]string{
"example.com",
"foo",
"foo.example.com",
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster.remote",
"localhost",
"some.url",
}, apiCert.DNSNames)
suite.Assert().Equal("[10.2.1.3 10.4.3.2 172.16.0.1]", fmt.Sprintf("%v", apiCert.IPAddresses))
suite.Assert().Equal("kube-apiserver", apiCert.Subject.CommonName)
suite.Assert().Equal([]string{"kube-master"}, apiCert.Subject.Organization)
suite.Assert().Equal(stdlibx509.KeyUsageDigitalSignature|stdlibx509.KeyUsageKeyEncipherment, apiCert.KeyUsage)
suite.Assert().Equal([]stdlibx509.ExtKeyUsage{stdlibx509.ExtKeyUsageServerAuth}, apiCert.ExtKeyUsage)
clientCert, err := kubernetesCerts.APIServerKubeletClient.GetCert()
suite.Require().NoError(err)
suite.Assert().Empty(clientCert.DNSNames)
suite.Assert().Empty(clientCert.IPAddresses)
suite.Assert().Equal(constants.KubernetesAPIServerKubeletClientCommonName, clientCert.Subject.CommonName)
suite.Assert().Equal([]string{constants.KubernetesAdminCertOrganization}, clientCert.Subject.Organization)
suite.Assert().Equal(stdlibx509.KeyUsageDigitalSignature|stdlibx509.KeyUsageKeyEncipherment, clientCert.KeyUsage)
suite.Assert().Equal([]stdlibx509.ExtKeyUsage{stdlibx509.ExtKeyUsageClientAuth}, clientCert.ExtKeyUsage)
frontProxyCert, err := kubernetesCerts.FrontProxy.GetCert()
suite.Require().NoError(err)
suite.Assert().Empty(frontProxyCert.DNSNames)
suite.Assert().Empty(frontProxyCert.IPAddresses)
suite.Assert().Equal("front-proxy-client", frontProxyCert.Subject.CommonName)
suite.Assert().Empty(frontProxyCert.Subject.Organization)
suite.Assert().Equal(stdlibx509.KeyUsageDigitalSignature|stdlibx509.KeyUsageKeyEncipherment, frontProxyCert.KeyUsage)
suite.Assert().Equal([]stdlibx509.ExtKeyUsage{stdlibx509.ExtKeyUsageClientAuth}, frontProxyCert.ExtKeyUsage)
for _, kubeconfig := range []string{kubernetesCerts.ControllerManagerKubeconfig, kubernetesCerts.SchedulerKubeconfig, kubernetesCerts.AdminKubeconfig} {
config, err := clientcmd.Load([]byte(kubeconfig))
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().NoError(clientcmd.ConfirmUsable(*config, config.CurrentContext)) suite.Assert().Equal(
} []string{
"example.com",
"foo",
"foo.example.com",
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster.remote",
"localhost",
"some.url",
}, apiCert.DNSNames,
)
suite.Assert().Equal("[10.2.1.3 10.4.3.2 172.16.0.1]", fmt.Sprintf("%v", apiCert.IPAddresses))
return nil suite.Assert().Equal("kube-apiserver", apiCert.Subject.CommonName)
}, suite.Assert().Equal([]string{"kube-master"}, apiCert.Subject.Organization)
))
suite.Assert().Equal(
stdlibx509.KeyUsageDigitalSignature|stdlibx509.KeyUsageKeyEncipherment,
apiCert.KeyUsage,
)
suite.Assert().Equal([]stdlibx509.ExtKeyUsage{stdlibx509.ExtKeyUsageServerAuth}, apiCert.ExtKeyUsage)
clientCert, err := kubernetesCerts.APIServerKubeletClient.GetCert()
suite.Require().NoError(err)
suite.Assert().Empty(clientCert.DNSNames)
suite.Assert().Empty(clientCert.IPAddresses)
suite.Assert().Equal(
constants.KubernetesAPIServerKubeletClientCommonName,
clientCert.Subject.CommonName,
)
suite.Assert().Equal(
[]string{constants.KubernetesAdminCertOrganization},
clientCert.Subject.Organization,
)
suite.Assert().Equal(
stdlibx509.KeyUsageDigitalSignature|stdlibx509.KeyUsageKeyEncipherment,
clientCert.KeyUsage,
)
suite.Assert().Equal([]stdlibx509.ExtKeyUsage{stdlibx509.ExtKeyUsageClientAuth}, clientCert.ExtKeyUsage)
frontProxyCert, err := kubernetesCerts.FrontProxy.GetCert()
suite.Require().NoError(err)
suite.Assert().Empty(frontProxyCert.DNSNames)
suite.Assert().Empty(frontProxyCert.IPAddresses)
suite.Assert().Equal("front-proxy-client", frontProxyCert.Subject.CommonName)
suite.Assert().Empty(frontProxyCert.Subject.Organization)
suite.Assert().Equal(
stdlibx509.KeyUsageDigitalSignature|stdlibx509.KeyUsageKeyEncipherment,
frontProxyCert.KeyUsage,
)
suite.Assert().Equal(
[]stdlibx509.ExtKeyUsage{stdlibx509.ExtKeyUsageClientAuth},
frontProxyCert.ExtKeyUsage,
)
for _, kubeconfig := range []string{
kubernetesCerts.ControllerManagerKubeconfig,
kubernetesCerts.SchedulerKubeconfig,
kubernetesCerts.AdminKubeconfig,
} {
config, err := clientcmd.Load([]byte(kubeconfig))
suite.Require().NoError(err)
suite.Assert().NoError(clientcmd.ConfirmUsable(*config, config.CurrentContext))
}
return nil
},
),
)
} }
func (suite *KubernetesSuite) TearDownTest() { func (suite *KubernetesSuite) TearDownTest() {

View File

@ -40,7 +40,7 @@ type ManagerSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
s *grpc.Server s *grpc.Server
@ -90,9 +90,13 @@ func (suite *ManagerSuite) SetupTest() {
cmdline := procfs.NewCmdline(fmt.Sprintf("%s=%s", constants.KernelParamSideroLink, lis.Addr().String())) cmdline := procfs.NewCmdline(fmt.Sprintf("%s=%s", constants.KernelParamSideroLink, lis.Addr().String()))
suite.Require().NoError(suite.runtime.RegisterController(&siderolinkctrl.ManagerController{ suite.Require().NoError(
Cmdline: cmdline, suite.runtime.RegisterController(
})) &siderolinkctrl.ManagerController{
Cmdline: cmdline,
},
),
)
} }
func (suite *ManagerSuite) startRuntime() { func (suite *ManagerSuite) startRuntime() {
@ -113,56 +117,76 @@ func (suite *ManagerSuite) TestReconcile() {
nodeAddress := netaddr.MustParseIPPrefix(mockNodeAddressPrefix) nodeAddress := netaddr.MustParseIPPrefix(mockNodeAddressPrefix)
suite.Assert().NoError(retry.Constant(5*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(5*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
addressResource, err := suite.state.Get(suite.ctx, resource.NewMetadata( func() error {
network.ConfigNamespaceName, addressResource, err := suite.state.Get(
network.AddressSpecType, suite.ctx, resource.NewMetadata(
network.LayeredID(network.ConfigOperator, network.AddressID(constants.SideroLinkName, nodeAddress)), network.ConfigNamespaceName,
resource.VersionUndefined, network.AddressSpecType,
)) network.LayeredID(
if err != nil { network.ConfigOperator,
if state.IsNotFoundError(err) { network.AddressID(constants.SideroLinkName, nodeAddress),
return retry.ExpectedError(err) ),
resource.VersionUndefined,
),
)
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
}
return err
} }
return err address := addressResource.(*network.AddressSpec).TypedSpec()
}
address := addressResource.(*network.AddressSpec).TypedSpec() suite.Assert().Equal(nodeAddress, address.Address)
suite.Assert().Equal(network.ConfigOperator, address.ConfigLayer)
suite.Assert().Equal(nethelpers.FamilyInet6, address.Family)
suite.Assert().Equal(constants.SideroLinkName, address.LinkName)
suite.Assert().Equal(nodeAddress, address.Address) linkResource, err := suite.state.Get(
suite.Assert().Equal(network.ConfigOperator, address.ConfigLayer) suite.ctx, resource.NewMetadata(
suite.Assert().Equal(nethelpers.FamilyInet6, address.Family) network.ConfigNamespaceName,
suite.Assert().Equal(constants.SideroLinkName, address.LinkName) network.LinkSpecType,
network.LayeredID(network.ConfigOperator, network.LinkID(constants.SideroLinkName)),
resource.VersionUndefined,
),
)
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
}
linkResource, err := suite.state.Get(suite.ctx, resource.NewMetadata( return err
network.ConfigNamespaceName,
network.LinkSpecType,
network.LayeredID(network.ConfigOperator, network.LinkID(constants.SideroLinkName)),
resource.VersionUndefined,
))
if err != nil {
if state.IsNotFoundError(err) {
return retry.ExpectedError(err)
} }
return err link := linkResource.(*network.LinkSpec).TypedSpec()
}
link := linkResource.(*network.LinkSpec).TypedSpec() suite.Assert().Equal("wireguard", link.Kind)
suite.Assert().Equal(network.ConfigOperator, link.ConfigLayer)
suite.Assert().NotEmpty(link.Wireguard.PrivateKey)
suite.Assert().Len(link.Wireguard.Peers, 1)
suite.Assert().Equal(mockServerEndpoint, link.Wireguard.Peers[0].Endpoint)
suite.Assert().Equal(mockServerPublicKey, link.Wireguard.Peers[0].PublicKey)
suite.Assert().Equal(
[]netaddr.IPPrefix{
netaddr.IPPrefixFrom(
netaddr.MustParseIP(mockServerAddress),
128,
),
}, link.Wireguard.Peers[0].AllowedIPs,
)
suite.Assert().Equal(
constants.SideroLinkDefaultPeerKeepalive,
link.Wireguard.Peers[0].PersistentKeepaliveInterval,
)
suite.Assert().Equal("wireguard", link.Kind) return nil
suite.Assert().Equal(network.ConfigOperator, link.ConfigLayer) },
suite.Assert().NotEmpty(link.Wireguard.PrivateKey) ),
suite.Assert().Len(link.Wireguard.Peers, 1) )
suite.Assert().Equal(mockServerEndpoint, link.Wireguard.Peers[0].Endpoint)
suite.Assert().Equal(mockServerPublicKey, link.Wireguard.Peers[0].PublicKey)
suite.Assert().Equal([]netaddr.IPPrefix{netaddr.IPPrefixFrom(netaddr.MustParseIP(mockServerAddress), 128)}, link.Wireguard.Peers[0].AllowedIPs)
suite.Assert().Equal(constants.SideroLinkDefaultPeerKeepalive, link.Wireguard.Peers[0].PersistentKeepaliveInterval)
return nil
}))
} }
func (suite *ManagerSuite) TearDownTest() { func (suite *ManagerSuite) TearDownTest() {

View File

@ -41,7 +41,7 @@ type SyncSuite struct {
runtime *runtime.Runtime runtime *runtime.Runtime
wg sync.WaitGroup wg sync.WaitGroup
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
syncerMu sync.Mutex syncerMu sync.Mutex
@ -72,7 +72,15 @@ func (suite *SyncSuite) startRuntime() {
} }
func (suite *SyncSuite) assertTimeStatus(spec timeresource.StatusSpec) error { func (suite *SyncSuite) assertTimeStatus(spec timeresource.StatusSpec) error {
r, err := suite.state.Get(suite.ctx, resource.NewMetadata(v1alpha1resource.NamespaceName, timeresource.StatusType, timeresource.StatusID, resource.VersionUndefined)) r, err := suite.state.Get(
suite.ctx,
resource.NewMetadata(
v1alpha1resource.NamespaceName,
timeresource.StatusType,
timeresource.StatusID,
resource.VersionUndefined,
),
)
if err != nil { if err != nil {
if state.IsNotFoundError(err) { if state.IsNotFoundError(err) {
return retry.ExpectedError(err) return retry.ExpectedError(err)
@ -91,10 +99,14 @@ func (suite *SyncSuite) assertTimeStatus(spec timeresource.StatusSpec) error {
} }
func (suite *SyncSuite) TestReconcileContainerMode() { func (suite *SyncSuite) TestReconcileContainerMode() {
suite.Require().NoError(suite.runtime.RegisterController(&timectrl.SyncController{ suite.Require().NoError(
V1Alpha1Mode: v1alpha1runtime.ModeContainer, suite.runtime.RegisterController(
NewNTPSyncer: suite.newMockSyncer, &timectrl.SyncController{
})) V1Alpha1Mode: v1alpha1runtime.ModeContainer,
NewNTPSyncer: suite.newMockSyncer,
},
),
)
timeServers := network.NewTimeServerStatus(network.NamespaceName, network.TimeServerID) timeServers := network.NewTimeServerStatus(network.NamespaceName, network.TimeServerID)
timeServers.TypedSpec().NTPServers = []string{constants.DefaultNTPServer} timeServers.TypedSpec().NTPServers = []string{constants.DefaultNTPServer}
@ -102,24 +114,30 @@ func (suite *SyncSuite) TestReconcileContainerMode() {
suite.startRuntime() suite.startRuntime()
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertTimeStatus( func() error {
timeresource.StatusSpec{ return suite.assertTimeStatus(
Synced: true, timeresource.StatusSpec{
Epoch: 0, Synced: true,
SyncDisabled: true, Epoch: 0,
}, SyncDisabled: true,
) },
}, )
)) },
),
)
} }
func (suite *SyncSuite) TestReconcileSyncDisabled() { func (suite *SyncSuite) TestReconcileSyncDisabled() {
suite.Require().NoError(suite.runtime.RegisterController(&timectrl.SyncController{ suite.Require().NoError(
V1Alpha1Mode: v1alpha1runtime.ModeMetal, suite.runtime.RegisterController(
NewNTPSyncer: suite.newMockSyncer, &timectrl.SyncController{
})) V1Alpha1Mode: v1alpha1runtime.ModeMetal,
NewNTPSyncer: suite.newMockSyncer,
},
),
)
suite.startRuntime() suite.startRuntime()
@ -127,48 +145,58 @@ func (suite *SyncSuite) TestReconcileSyncDisabled() {
timeServers.TypedSpec().NTPServers = []string{constants.DefaultNTPServer} timeServers.TypedSpec().NTPServers = []string{constants.DefaultNTPServer}
suite.Require().NoError(suite.state.Create(suite.ctx, timeServers)) suite.Require().NoError(suite.state.Create(suite.ctx, timeServers))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertTimeStatus( func() error {
timeresource.StatusSpec{ return suite.assertTimeStatus(
Synced: false, timeresource.StatusSpec{
Epoch: 0, Synced: false,
SyncDisabled: false, Epoch: 0,
}, SyncDisabled: false,
) },
}, )
))
cfg := config.NewMachineConfig(&v1alpha1.Config{
ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{
MachineTime: &v1alpha1.TimeConfig{
TimeDisabled: true,
}, },
),
)
cfg := config.NewMachineConfig(
&v1alpha1.Config{
ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{
MachineTime: &v1alpha1.TimeConfig{
TimeDisabled: true,
},
},
ClusterConfig: &v1alpha1.ClusterConfig{},
}, },
ClusterConfig: &v1alpha1.ClusterConfig{}, )
})
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertTimeStatus( func() error {
timeresource.StatusSpec{ return suite.assertTimeStatus(
Synced: true, timeresource.StatusSpec{
Epoch: 0, Synced: true,
SyncDisabled: true, Epoch: 0,
}, SyncDisabled: true,
) },
}, )
)) },
),
)
} }
func (suite *SyncSuite) TestReconcileSyncDefaultConfig() { func (suite *SyncSuite) TestReconcileSyncDefaultConfig() {
suite.Require().NoError(suite.runtime.RegisterController(&timectrl.SyncController{ suite.Require().NoError(
V1Alpha1Mode: v1alpha1runtime.ModeMetal, suite.runtime.RegisterController(
NewNTPSyncer: suite.newMockSyncer, &timectrl.SyncController{
})) V1Alpha1Mode: v1alpha1runtime.ModeMetal,
NewNTPSyncer: suite.newMockSyncer,
},
),
)
suite.startRuntime() suite.startRuntime()
@ -176,32 +204,40 @@ func (suite *SyncSuite) TestReconcileSyncDefaultConfig() {
timeServers.TypedSpec().NTPServers = []string{constants.DefaultNTPServer} timeServers.TypedSpec().NTPServers = []string{constants.DefaultNTPServer}
suite.Require().NoError(suite.state.Create(suite.ctx, timeServers)) suite.Require().NoError(suite.state.Create(suite.ctx, timeServers))
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{}, ConfigVersion: "v1alpha1",
ClusterConfig: &v1alpha1.ClusterConfig{}, MachineConfig: &v1alpha1.MachineConfig{},
}) ClusterConfig: &v1alpha1.ClusterConfig{},
},
)
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertTimeStatus( func() error {
timeresource.StatusSpec{ return suite.assertTimeStatus(
Synced: false, timeresource.StatusSpec{
Epoch: 0, Synced: false,
SyncDisabled: false, Epoch: 0,
}, SyncDisabled: false,
) },
}, )
)) },
),
)
} }
func (suite *SyncSuite) TestReconcileSyncChangeConfig() { func (suite *SyncSuite) TestReconcileSyncChangeConfig() {
suite.Require().NoError(suite.runtime.RegisterController(&timectrl.SyncController{ suite.Require().NoError(
V1Alpha1Mode: v1alpha1runtime.ModeMetal, suite.runtime.RegisterController(
NewNTPSyncer: suite.newMockSyncer, &timectrl.SyncController{
})) V1Alpha1Mode: v1alpha1runtime.ModeMetal,
NewNTPSyncer: suite.newMockSyncer,
},
),
)
suite.startRuntime() suite.startRuntime()
@ -209,126 +245,150 @@ func (suite *SyncSuite) TestReconcileSyncChangeConfig() {
timeServers.TypedSpec().NTPServers = []string{constants.DefaultNTPServer} timeServers.TypedSpec().NTPServers = []string{constants.DefaultNTPServer}
suite.Require().NoError(suite.state.Create(suite.ctx, timeServers)) suite.Require().NoError(suite.state.Create(suite.ctx, timeServers))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertTimeStatus( func() error {
timeresource.StatusSpec{ return suite.assertTimeStatus(
Synced: false, timeresource.StatusSpec{
Epoch: 0, Synced: false,
SyncDisabled: false, Epoch: 0,
}, SyncDisabled: false,
) },
}, )
)) },
),
)
cfg := config.NewMachineConfig(&v1alpha1.Config{ cfg := config.NewMachineConfig(
ConfigVersion: "v1alpha1", &v1alpha1.Config{
MachineConfig: &v1alpha1.MachineConfig{}, ConfigVersion: "v1alpha1",
ClusterConfig: &v1alpha1.ClusterConfig{}, MachineConfig: &v1alpha1.MachineConfig{},
}) ClusterConfig: &v1alpha1.ClusterConfig{},
},
)
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
var mockSyncer *mockSyncer var mockSyncer *mockSyncer
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
mockSyncer = suite.getMockSyncer() func() error {
mockSyncer = suite.getMockSyncer()
if mockSyncer == nil { if mockSyncer == nil {
return retry.ExpectedError(fmt.Errorf("syncer not created yet")) return retry.ExpectedError(fmt.Errorf("syncer not created yet"))
} }
return nil return nil
}, },
)) ),
)
suite.Assert().Equal([]string{constants.DefaultNTPServer}, mockSyncer.getTimeServers()) suite.Assert().Equal([]string{constants.DefaultNTPServer}, mockSyncer.getTimeServers())
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertTimeStatus( func() error {
timeresource.StatusSpec{ return suite.assertTimeStatus(
Synced: false, timeresource.StatusSpec{
Epoch: 0, Synced: false,
SyncDisabled: false, Epoch: 0,
}, SyncDisabled: false,
) },
}, )
)) },
),
)
close(mockSyncer.syncedCh) close(mockSyncer.syncedCh)
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertTimeStatus( func() error {
timeresource.StatusSpec{ return suite.assertTimeStatus(
Synced: true, timeresource.StatusSpec{
Epoch: 0, Synced: true,
SyncDisabled: false, Epoch: 0,
}, SyncDisabled: false,
) },
)
},
),
)
_, err := suite.state.UpdateWithConflicts(
suite.ctx, timeServers.Metadata(), func(r resource.Resource) error {
r.(*network.TimeServerStatus).TypedSpec().NTPServers = []string{"127.0.0.1"}
return nil
}, },
)) )
_, err := suite.state.UpdateWithConflicts(suite.ctx, timeServers.Metadata(), func(r resource.Resource) error {
r.(*network.TimeServerStatus).TypedSpec().NTPServers = []string{"127.0.0.1"}
return nil
})
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
if !reflect.DeepEqual(mockSyncer.getTimeServers(), []string{"127.0.0.1"}) { func() error {
return retry.ExpectedError(fmt.Errorf("time servers not updated yet")) if !reflect.DeepEqual(mockSyncer.getTimeServers(), []string{"127.0.0.1"}) {
return retry.ExpectedError(fmt.Errorf("time servers not updated yet"))
}
return nil
},
),
)
mockSyncer.epochCh <- struct{}{}
suite.Assert().NoError(
retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
func() error {
return suite.assertTimeStatus(
timeresource.StatusSpec{
Synced: true,
Epoch: 1,
SyncDisabled: false,
},
)
},
),
)
_, err = suite.state.UpdateWithConflicts(
suite.ctx, cfg.Metadata(), func(r resource.Resource) error {
r.(*config.MachineConfig).Config().(*v1alpha1.Config).MachineConfig.MachineTime = &v1alpha1.TimeConfig{
TimeDisabled: true,
} }
return nil return nil
}, },
)) )
mockSyncer.epochCh <- struct{}{}
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
func() error {
return suite.assertTimeStatus(
timeresource.StatusSpec{
Synced: true,
Epoch: 1,
SyncDisabled: false,
},
)
},
))
_, err = suite.state.UpdateWithConflicts(suite.ctx, cfg.Metadata(), func(r resource.Resource) error {
r.(*config.MachineConfig).Config().(*v1alpha1.Config).MachineConfig.MachineTime = &v1alpha1.TimeConfig{
TimeDisabled: true,
}
return nil
})
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertTimeStatus( func() error {
timeresource.StatusSpec{ return suite.assertTimeStatus(
Synced: true, timeresource.StatusSpec{
Epoch: 1, Synced: true,
SyncDisabled: true, Epoch: 1,
}, SyncDisabled: true,
) },
}, )
)) },
),
)
} }
func (suite *SyncSuite) TestReconcileSyncBootTimeout() { func (suite *SyncSuite) TestReconcileSyncBootTimeout() {
suite.Require().NoError(suite.runtime.RegisterController(&timectrl.SyncController{ suite.Require().NoError(
V1Alpha1Mode: v1alpha1runtime.ModeMetal, suite.runtime.RegisterController(
NewNTPSyncer: suite.newMockSyncer, &timectrl.SyncController{
})) V1Alpha1Mode: v1alpha1runtime.ModeMetal,
NewNTPSyncer: suite.newMockSyncer,
},
),
)
suite.startRuntime() suite.startRuntime()
@ -336,41 +396,47 @@ func (suite *SyncSuite) TestReconcileSyncBootTimeout() {
timeServers.TypedSpec().NTPServers = []string{constants.DefaultNTPServer} timeServers.TypedSpec().NTPServers = []string{constants.DefaultNTPServer}
suite.Require().NoError(suite.state.Create(suite.ctx, timeServers)) suite.Require().NoError(suite.state.Create(suite.ctx, timeServers))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertTimeStatus( func() error {
timeresource.StatusSpec{ return suite.assertTimeStatus(
Synced: false, timeresource.StatusSpec{
Epoch: 0, Synced: false,
SyncDisabled: false, Epoch: 0,
}, SyncDisabled: false,
) },
}, )
))
cfg := config.NewMachineConfig(&v1alpha1.Config{
ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{
MachineTime: &v1alpha1.TimeConfig{
TimeBootTimeout: 5 * time.Second,
}, },
),
)
cfg := config.NewMachineConfig(
&v1alpha1.Config{
ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{
MachineTime: &v1alpha1.TimeConfig{
TimeBootTimeout: 5 * time.Second,
},
},
ClusterConfig: &v1alpha1.ClusterConfig{},
}, },
ClusterConfig: &v1alpha1.ClusterConfig{}, )
})
suite.Require().NoError(suite.state.Create(suite.ctx, cfg)) suite.Require().NoError(suite.state.Create(suite.ctx, cfg))
suite.Assert().NoError(retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry( suite.Assert().NoError(
func() error { retry.Constant(10*time.Second, retry.WithUnits(100*time.Millisecond)).Retry(
return suite.assertTimeStatus( func() error {
timeresource.StatusSpec{ return suite.assertTimeStatus(
Synced: true, timeresource.StatusSpec{
Epoch: 0, Synced: true,
SyncDisabled: false, Epoch: 0,
}, SyncDisabled: false,
) },
}, )
)) },
),
)
} }
func (suite *SyncSuite) TearDownTest() { func (suite *SyncSuite) TearDownTest() {
@ -381,10 +447,14 @@ func (suite *SyncSuite) TearDownTest() {
suite.wg.Wait() suite.wg.Wait()
// trigger updates in resources to stop watch loops // trigger updates in resources to stop watch loops
err := suite.state.Create(context.Background(), config.NewMachineConfig(&v1alpha1.Config{ err := suite.state.Create(
ConfigVersion: "v1alpha1", context.Background(), config.NewMachineConfig(
MachineConfig: &v1alpha1.MachineConfig{}, &v1alpha1.Config{
})) ConfigVersion: "v1alpha1",
MachineConfig: &v1alpha1.MachineConfig{},
},
),
)
if state.IsConflictError(err) { if state.IsConflictError(err) {
err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata()) err = suite.state.Destroy(context.Background(), config.NewMachineConfig(nil).Metadata())
} }

View File

@ -5,7 +5,7 @@
package rpi4 package rpi4
import ( import (
_ "embed" //nolint:gci _ "embed"
"io/ioutil" "io/ioutil"
"github.com/talos-systems/go-procfs/procfs" "github.com/talos-systems/go-procfs/procfs"

View File

@ -1845,7 +1845,8 @@ func StopDBus(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc
} }
func pauseOnFailure(callback func(runtime.Sequence, interface{}) (runtime.TaskExecutionFunc, string), func pauseOnFailure(callback func(runtime.Sequence, interface{}) (runtime.TaskExecutionFunc, string),
timeout time.Duration) func(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { timeout time.Duration,
) func(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) {
return func(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) { return func(seq runtime.Sequence, data interface{}) (runtime.TaskExecutionFunc, string) {
f, name := callback(seq, data) f, name := callback(seq, data)

View File

@ -34,7 +34,7 @@ type containerdRunner struct {
stopped chan struct{} stopped chan struct{}
client *containerd.Client client *containerd.Client
ctx context.Context ctx context.Context //nolint:containedctx
container containerd.Container container containerd.Container
stdinCloser *StdinCloser stdinCloser *StdinCloser
} }
@ -196,7 +196,13 @@ func (c *containerdRunner) Run(eventSink events.Recorder) error {
return nil return nil
case <-c.stop: case <-c.stop:
// graceful stop the task // graceful stop the task
eventSink(events.StateStopping, "Sending SIGTERM to task %s (PID %d, container %s)", task.ID(), task.Pid(), c.container.ID()) eventSink(
events.StateStopping,
"Sending SIGTERM to task %s (PID %d, container %s)",
task.ID(),
task.Pid(),
c.container.ID(),
)
if err = task.Kill(c.ctx, syscall.SIGTERM, containerd.WithKillAll); err != nil { if err = task.Kill(c.ctx, syscall.SIGTERM, containerd.WithKillAll); err != nil {
return fmt.Errorf("error sending SIGTERM: %w", err) return fmt.Errorf("error sending SIGTERM: %w", err)
@ -209,7 +215,13 @@ func (c *containerdRunner) Run(eventSink events.Recorder) error {
return nil return nil
case <-time.After(c.opts.GracefulShutdownTimeout): case <-time.After(c.opts.GracefulShutdownTimeout):
// kill the process // kill the process
eventSink(events.StateStopping, "Sending SIGKILL to task %s (PID %d, container %s)", task.ID(), task.Pid(), c.container.ID()) eventSink(
events.StateStopping,
"Sending SIGKILL to task %s (PID %d, container %s)",
task.ID(),
task.Pid(),
c.container.ID(),
)
if err = task.Kill(c.ctx, syscall.SIGKILL, containerd.WithKillAll); err != nil { if err = task.Kill(c.ctx, syscall.SIGKILL, containerd.WithKillAll); err != nil {
return fmt.Errorf("error sending SIGKILL: %w", err) return fmt.Errorf("error sending SIGKILL: %w", err)
@ -233,21 +245,27 @@ func (c *containerdRunner) Stop() error {
return nil return nil
} }
func (c *containerdRunner) newContainerOpts(image containerd.Image, specOpts []oci.SpecOpts) []containerd.NewContainerOpts { func (c *containerdRunner) newContainerOpts(
image containerd.Image,
specOpts []oci.SpecOpts,
) []containerd.NewContainerOpts {
containerOpts := []containerd.NewContainerOpts{} containerOpts := []containerd.NewContainerOpts{}
if image != nil { if image != nil {
containerOpts = append(containerOpts, containerOpts = append(
containerOpts,
containerd.WithImage(image), containerd.WithImage(image),
containerd.WithNewSnapshot(c.args.ID, image), containerd.WithNewSnapshot(c.args.ID, image),
) )
} }
containerOpts = append(containerOpts, containerOpts = append(
containerOpts,
containerd.WithNewSpec(specOpts...), containerd.WithNewSpec(specOpts...),
) )
containerOpts = append(containerOpts, containerOpts = append(
containerOpts,
c.opts.ContainerOpts..., c.opts.ContainerOpts...,
) )
@ -258,12 +276,14 @@ func (c *containerdRunner) newOCISpecOpts(image oci.Image) []oci.SpecOpts {
specOpts := []oci.SpecOpts{} specOpts := []oci.SpecOpts{}
if image != nil { if image != nil {
specOpts = append(specOpts, specOpts = append(
specOpts,
oci.WithImageConfig(image), oci.WithImageConfig(image),
) )
} }
specOpts = append(specOpts, specOpts = append(
specOpts,
oci.WithProcessArgs(c.args.ProcessArgs...), oci.WithProcessArgs(c.args.ProcessArgs...),
oci.WithEnv(c.opts.Env), oci.WithEnv(c.opts.Env),
oci.WithHostHostsFile, oci.WithHostHostsFile,
@ -272,27 +292,32 @@ func (c *containerdRunner) newOCISpecOpts(image oci.Image) []oci.SpecOpts {
) )
if c.opts.OOMScoreAdj != 0 { if c.opts.OOMScoreAdj != 0 {
specOpts = append(specOpts, specOpts = append(
specOpts,
WithOOMScoreAdj(c.opts.OOMScoreAdj), WithOOMScoreAdj(c.opts.OOMScoreAdj),
) )
} }
if c.opts.CgroupPath != "" { if c.opts.CgroupPath != "" {
specOpts = append(specOpts, specOpts = append(
specOpts,
oci.WithCgroup(c.opts.CgroupPath), oci.WithCgroup(c.opts.CgroupPath),
) )
} }
specOpts = append(specOpts, specOpts = append(
specOpts,
c.opts.OCISpecOpts..., c.opts.OCISpecOpts...,
) )
if c.opts.OverrideSeccompProfile != nil { if c.opts.OverrideSeccompProfile != nil {
specOpts = append(specOpts, specOpts = append(
specOpts,
WithCustomSeccompProfile(c.opts.OverrideSeccompProfile), WithCustomSeccompProfile(c.opts.OverrideSeccompProfile),
) )
} else { } else {
specOpts = append(specOpts, specOpts = append(
specOpts,
seccomp.WithDefaultProfile(), // add seccomp profile last, as it depends on process capabilities seccomp.WithDefaultProfile(), // add seccomp profile last, as it depends on process capabilities
) )
} }

View File

@ -25,7 +25,7 @@ type goroutineRunner struct {
opts *runner.Options opts *runner.Options
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
wg sync.WaitGroup wg sync.WaitGroup

View File

@ -41,7 +41,7 @@ type ServiceRunner struct {
stateSubscribers map[StateEvent][]chan<- struct{} stateSubscribers map[StateEvent][]chan<- struct{}
ctxMu sync.Mutex ctxMu sync.Mutex
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -291,7 +291,12 @@ func (svcrunner *ServiceRunner) run(ctx context.Context, runnr runner.Runner) er
defer healthWg.Done() defer healthWg.Done()
//nolint:errcheck //nolint:errcheck
health.Run(ctx, healthSvc.HealthSettings(svcrunner.runtime), &svcrunner.healthState, healthSvc.HealthFunc(svcrunner.runtime)) health.Run(
ctx,
healthSvc.HealthSettings(svcrunner.runtime),
&svcrunner.healthState,
healthSvc.HealthFunc(svcrunner.runtime),
)
}() }()
notifyCh := make(chan health.StateChange, 2) notifyCh := make(chan health.StateChange, 2)

View File

@ -51,7 +51,7 @@ const assertRebootedRebootTimeout = 10 * time.Minute
type ApplyConfigSuite struct { type ApplyConfigSuite struct {
base.K8sSuite base.K8sSuite
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -109,30 +109,38 @@ func (suite *ApplyConfigSuite) TestApply() {
cfgDataOut, err := cfg.Bytes() cfgDataOut, err := cfg.Bytes()
suite.Assert().Nilf(err, "failed to marshal updated machine config data (node %q): %w", node, err) suite.Assert().Nilf(err, "failed to marshal updated machine config data (node %q): %w", node, err)
suite.AssertRebooted(suite.ctx, node, func(nodeCtx context.Context) error { suite.AssertRebooted(
_, err = suite.Client.ApplyConfiguration(nodeCtx, &machineapi.ApplyConfigurationRequest{ suite.ctx, node, func(nodeCtx context.Context) error {
Data: cfgDataOut, _, err = suite.Client.ApplyConfiguration(
Mode: machineapi.ApplyConfigurationRequest_REBOOT, nodeCtx, &machineapi.ApplyConfigurationRequest{
}) Data: cfgDataOut,
if err != nil { Mode: machineapi.ApplyConfigurationRequest_REBOOT,
// It is expected that the connection will EOF here, so just log the error },
suite.Assert().Nilf("failed to apply configuration (node %q): %w", node, err) )
} if err != nil {
// It is expected that the connection will EOF here, so just log the error
suite.Assert().Nilf("failed to apply configuration (node %q): %w", node, err)
}
return nil return nil
}, assertRebootedRebootTimeout) }, assertRebootedRebootTimeout,
)
// Verify configuration change // Verify configuration change
var newProvider config.Provider var newProvider config.Provider
suite.Require().Nilf(retry.Constant(time.Minute, retry.WithUnits(time.Second)).Retry(func() error { suite.Require().Nilf(
newProvider, err = suite.ReadConfigFromNode(nodeCtx) retry.Constant(time.Minute, retry.WithUnits(time.Second)).Retry(
if err != nil { func() error {
return retry.ExpectedError(err) newProvider, err = suite.ReadConfigFromNode(nodeCtx)
} if err != nil {
return retry.ExpectedError(err)
}
return nil return nil
}), "failed to read updated configuration from node %q: %w", node, err) },
), "failed to read updated configuration from node %q: %w", node, err,
)
suite.Assert().Equal( suite.Assert().Equal(
newProvider.Machine().Sysctls()[applyConfigTestSysctl], newProvider.Machine().Sysctls()[applyConfigTestSysctl],
@ -168,10 +176,12 @@ func (suite *ApplyConfigSuite) TestApplyWithoutReboot() {
cfgDataOut, err := cfg.Bytes() cfgDataOut, err := cfg.Bytes()
suite.Require().NoError(err, "failed to marshal updated machine config data (node %q)", node) suite.Require().NoError(err, "failed to marshal updated machine config data (node %q)", node)
_, err = suite.Client.ApplyConfiguration(nodeCtx, &machineapi.ApplyConfigurationRequest{ _, err = suite.Client.ApplyConfiguration(
Data: cfgDataOut, nodeCtx, &machineapi.ApplyConfigurationRequest{
Mode: mode, Data: cfgDataOut,
}) Mode: mode,
},
)
suite.Require().NoError(err, "failed to apply deferred configuration (node %q): %w", node) suite.Require().NoError(err, "failed to apply deferred configuration (node %q): %w", node)
// Verify configuration change // Verify configuration change
@ -195,10 +205,12 @@ func (suite *ApplyConfigSuite) TestApplyWithoutReboot() {
cfgDataOut, err = cfg.Bytes() cfgDataOut, err = cfg.Bytes()
suite.Require().NoError(err, "failed to marshal updated machine config data (node %q)", node) suite.Require().NoError(err, "failed to marshal updated machine config data (node %q)", node)
_, err = suite.Client.ApplyConfiguration(nodeCtx, &machineapi.ApplyConfigurationRequest{ _, err = suite.Client.ApplyConfiguration(
Data: cfgDataOut, nodeCtx, &machineapi.ApplyConfigurationRequest{
Mode: mode, Data: cfgDataOut,
}) Mode: mode,
},
)
suite.Require().NoError(err, "failed to apply deferred configuration (node %q): %w", node) suite.Require().NoError(err, "failed to apply deferred configuration (node %q): %w", node)
} }
} }
@ -295,32 +307,40 @@ func (suite *ApplyConfigSuite) TestApplyConfigRotateEncryptionSecrets() {
data, err := machineConfig.Bytes() data, err := machineConfig.Bytes()
suite.Require().NoError(err) suite.Require().NoError(err)
suite.AssertRebooted(suite.ctx, node, func(nodeCtx context.Context) error { suite.AssertRebooted(
_, err = suite.Client.ApplyConfiguration(nodeCtx, &machineapi.ApplyConfigurationRequest{ suite.ctx, node, func(nodeCtx context.Context) error {
Data: data, _, err = suite.Client.ApplyConfiguration(
Mode: machineapi.ApplyConfigurationRequest_REBOOT, nodeCtx, &machineapi.ApplyConfigurationRequest{
}) Data: data,
if err != nil { Mode: machineapi.ApplyConfigurationRequest_REBOOT,
// It is expected that the connection will EOF here, so just log the error },
suite.Assert().Nilf("failed to apply configuration (node %q): %w", node, err) )
} if err != nil {
// It is expected that the connection will EOF here, so just log the error
suite.Assert().Nilf("failed to apply configuration (node %q): %w", node, err)
}
return nil return nil
}, assertRebootedRebootTimeout) }, assertRebootedRebootTimeout,
)
suite.ClearConnectionRefused(suite.ctx, node) suite.ClearConnectionRefused(suite.ctx, node)
// Verify configuration change // Verify configuration change
var newProvider config.Provider var newProvider config.Provider
suite.Require().Nilf(retry.Constant(time.Minute, retry.WithUnits(time.Second)).Retry(func() error { suite.Require().Nilf(
newProvider, err = suite.ReadConfigFromNode(nodeCtx) retry.Constant(time.Minute, retry.WithUnits(time.Second)).Retry(
if err != nil { func() error {
return retry.ExpectedError(err) newProvider, err = suite.ReadConfigFromNode(nodeCtx)
} if err != nil {
return retry.ExpectedError(err)
}
return nil return nil
}), "failed to read updated configuration from node %q: %w", node, err) },
), "failed to read updated configuration from node %q: %w", node, err,
)
e := newProvider.Machine().SystemDiskEncryption().Get(constants.EphemeralPartitionLabel) e := newProvider.Machine().SystemDiskEncryption().Get(constants.EphemeralPartitionLabel)
@ -370,10 +390,12 @@ func (suite *ApplyConfigSuite) TestApplyNoReboot() {
cfgDataOut, err := cfg.Bytes() cfgDataOut, err := cfg.Bytes()
suite.Assert().Nilf(err, "failed to marshal updated machine config data (node %q): %w", node, err) suite.Assert().Nilf(err, "failed to marshal updated machine config data (node %q): %w", node, err)
_, err = suite.Client.ApplyConfiguration(nodeCtx, &machineapi.ApplyConfigurationRequest{ _, err = suite.Client.ApplyConfiguration(
Data: cfgDataOut, nodeCtx, &machineapi.ApplyConfigurationRequest{
Mode: machineapi.ApplyConfigurationRequest_NO_REBOOT, Data: cfgDataOut,
}) Mode: machineapi.ApplyConfigurationRequest_NO_REBOOT,
},
)
suite.Require().Error(err) suite.Require().Error(err)
var ( var (

View File

@ -28,7 +28,7 @@ import (
type DiscoverySuite struct { type DiscoverySuite struct {
base.APISuite base.APISuite
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }

View File

@ -23,10 +23,10 @@ import (
type DiskUsageSuite struct { type DiskUsageSuite struct {
base.APISuite base.APISuite
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
nodeCtx context.Context nodeCtx context.Context //nolint:containedctx
} }
// SuiteName ... // SuiteName ...

View File

@ -22,7 +22,7 @@ import (
type DmesgSuite struct { type DmesgSuite struct {
base.APISuite base.APISuite
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }

View File

@ -30,7 +30,7 @@ import (
type EtcdRecoverSuite struct { type EtcdRecoverSuite struct {
base.K8sSuite base.K8sSuite
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -112,39 +112,52 @@ func (suite *EtcdRecoverSuite) TestSnapshotRecover() {
return fmt.Errorf("error reading pre-reset boot ID: %w", err) return fmt.Errorf("error reading pre-reset boot ID: %w", err)
} }
if err = base.IgnoreGRPCUnavailable(suite.Client.ResetGeneric(nodeCtx, &machineapi.ResetRequest{ if err = base.IgnoreGRPCUnavailable(
Reboot: true, suite.Client.ResetGeneric(
Graceful: false, nodeCtx, &machineapi.ResetRequest{
SystemPartitionsToWipe: []*machineapi.ResetPartitionSpec{ Reboot: true,
{ Graceful: false,
Label: constants.EphemeralPartitionLabel, SystemPartitionsToWipe: []*machineapi.ResetPartitionSpec{
Wipe: true, {
Label: constants.EphemeralPartitionLabel,
Wipe: true,
},
},
}, },
}, ),
})); err != nil { ); err != nil {
return fmt.Errorf("error resetting the node %q: %w", node, err) return fmt.Errorf("error resetting the node %q: %w", node, err)
} }
var bootIDAfter string var bootIDAfter string
return retry.Constant(5 * time.Minute).Retry(func() error { return retry.Constant(5 * time.Minute).Retry(
requestCtx, requestCtxCancel := context.WithTimeout(nodeCtx, 5*time.Second) func() error {
defer requestCtxCancel() requestCtx, requestCtxCancel := context.WithTimeout(nodeCtx, 5*time.Second)
defer requestCtxCancel()
bootIDAfter, err = suite.ReadBootID(requestCtx) bootIDAfter, err = suite.ReadBootID(requestCtx)
if err != nil { if err != nil {
// API might be unresponsive during reboot // API might be unresponsive during reboot
return retry.ExpectedError(err) return retry.ExpectedError(err)
} }
if bootIDAfter == bootIDBefore { if bootIDAfter == bootIDBefore {
// bootID should be different after reboot // bootID should be different after reboot
return retry.ExpectedError(fmt.Errorf("bootID didn't change for node %q: before %s, after %s", node, bootIDBefore, bootIDAfter)) return retry.ExpectedError(
} fmt.Errorf(
"bootID didn't change for node %q: before %s, after %s",
node,
bootIDBefore,
bootIDAfter,
),
)
}
return nil return nil
}) },
)
}() }()
}() }()
} }
@ -203,36 +216,42 @@ func (suite *EtcdRecoverSuite) recoverEtcd(recoverNode string, src io.ReadSeeker
suite.T().Log("uploading the snapshot") suite.T().Log("uploading the snapshot")
if err := retry.Constant(time.Minute, retry.WithUnits(time.Millisecond*200)).RetryWithContext(ctx, func(ctx context.Context) error { if err := retry.Constant(time.Minute, retry.WithUnits(time.Millisecond*200)).RetryWithContext(
_, err := src.Seek(0, io.SeekStart) ctx, func(ctx context.Context) error {
if err != nil { _, err := src.Seek(0, io.SeekStart)
if err != nil {
return err
}
_, err = suite.Client.EtcdRecover(ctx, src)
if client.StatusCode(err) == codes.FailedPrecondition {
return retry.ExpectedError(err)
}
return err return err
} },
); err != nil {
_, err = suite.Client.EtcdRecover(ctx, src)
if client.StatusCode(err) == codes.FailedPrecondition {
return retry.ExpectedError(err)
}
return err
}); err != nil {
return fmt.Errorf("error uploading snapshot: %w", err) return fmt.Errorf("error uploading snapshot: %w", err)
} }
suite.T().Log("bootstrapping from the snapshot") suite.T().Log("bootstrapping from the snapshot")
return retry.Constant(time.Minute, retry.WithUnits(time.Millisecond*200)).RetryWithContext(ctx, func(ctx context.Context) error { return retry.Constant(time.Minute, retry.WithUnits(time.Millisecond*200)).RetryWithContext(
err := suite.Client.Bootstrap(ctx, &machineapi.BootstrapRequest{ ctx, func(ctx context.Context) error {
RecoverEtcd: true, err := suite.Client.Bootstrap(
}) ctx, &machineapi.BootstrapRequest{
RecoverEtcd: true,
},
)
if client.StatusCode(err) == codes.FailedPrecondition || client.StatusCode(err) == codes.DeadlineExceeded { if client.StatusCode(err) == codes.FailedPrecondition || client.StatusCode(err) == codes.DeadlineExceeded {
return retry.ExpectedError(err) return retry.ExpectedError(err)
} }
return err return err
}) },
)
} }
func init() { func init() {

View File

@ -26,7 +26,7 @@ import (
type EtcdSuite struct { type EtcdSuite struct {
base.APISuite base.APISuite
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -67,7 +67,10 @@ func (suite *EtcdSuite) TestEtcdForfeitLeadership() {
var leader string var leader string
for _, node := range nodes { for _, node := range nodes {
resp, err := suite.Client.EtcdForfeitLeadership(client.WithNodes(suite.ctx, node), &machineapi.EtcdForfeitLeadershipRequest{}) resp, err := suite.Client.EtcdForfeitLeadership(
client.WithNodes(suite.ctx, node),
&machineapi.EtcdForfeitLeadershipRequest{},
)
suite.Require().NoError(err) suite.Require().NoError(err)
if resp.Messages[0].GetMember() != "" { if resp.Messages[0].GetMember() != "" {
@ -130,16 +133,21 @@ func (suite *EtcdSuite) TestEtcdLeaveCluster() {
} }
} }
suite.Assert().Equal("rpc error: code = Unknown desc = lstat /var/lib/etcd: no such file or directory", info.Metadata.Error) suite.Assert().Equal(
"rpc error: code = Unknown desc = lstat /var/lib/etcd: no such file or directory",
info.Metadata.Error,
)
} }
// NB: Reboot the node so that it can rejoin the etcd cluster. This allows us // NB: Reboot the node so that it can rejoin the etcd cluster. This allows us
// to check the cluster health and catch any issues in rejoining. // to check the cluster health and catch any issues in rejoining.
suite.AssertRebooted(suite.ctx, node, func(nodeCtx context.Context) error { suite.AssertRebooted(
_, err = suite.Client.MachineClient.Reboot(nodeCtx, &machineapi.RebootRequest{}) suite.ctx, node, func(nodeCtx context.Context) error {
_, err = suite.Client.MachineClient.Reboot(nodeCtx, &machineapi.RebootRequest{})
return err return err
}, 10*time.Minute) }, 10*time.Minute,
)
} }
func init() { func init() {

View File

@ -20,10 +20,10 @@ import (
type EventsSuite struct { type EventsSuite struct {
base.APISuite base.APISuite
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
nodeCtx context.Context nodeCtx context.Context //nolint:containedctx
} }
// SuiteName ... // SuiteName ...
@ -54,25 +54,29 @@ func (suite *EventsSuite) TestEventsWatch() {
watchCtx, watchCtxCancel := context.WithCancel(suite.nodeCtx) watchCtx, watchCtxCancel := context.WithCancel(suite.nodeCtx)
defer watchCtxCancel() defer watchCtxCancel()
suite.Assert().NoError(suite.Client.EventsWatch(watchCtx, func(ch <-chan client.Event) { suite.Assert().NoError(
defer watchCtxCancel() suite.Client.EventsWatch(
watchCtx, func(ch <-chan client.Event) {
defer watchCtxCancel()
timer := time.NewTimer(500 * time.Millisecond) timer := time.NewTimer(500 * time.Millisecond)
defer timer.Stop() defer timer.Stop()
for { for {
select { select {
case event, ok := <-ch: case event, ok := <-ch:
if !ok { if !ok {
return return
}
result = append(result, event)
case <-timer.C:
return
}
} }
}, opts...,
result = append(result, event) ),
case <-timer.C: )
return
}
}
}, opts...))
return result return result
} }
@ -88,7 +92,10 @@ func (suite *EventsSuite) TestEventsWatch() {
// (as check excludes that event with picked ID) // (as check excludes that event with picked ID)
id := allEvents[len(allEvents)-15].ID id := allEvents[len(allEvents)-15].ID
eventsSinceID := receiveEvents(client.WithTailID(id)) eventsSinceID := receiveEvents(client.WithTailID(id))
suite.Require().GreaterOrEqual(len(eventsSinceID), 14) // there might some new events since allEvents, but at least 15 should be received suite.Require().GreaterOrEqual(
len(eventsSinceID),
14,
) // there might some new events since allEvents, but at least 15 should be received
} }
func init() { func init() {

View File

@ -26,7 +26,7 @@ import (
type GenerateConfigSuite struct { type GenerateConfigSuite struct {
base.K8sSuite base.K8sSuite
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -104,9 +104,18 @@ func (suite *GenerateConfigSuite) TestGenerate() {
suite.Require().EqualValues(request.ClusterConfig.Name, config.Cluster().Name()) suite.Require().EqualValues(request.ClusterConfig.Name, config.Cluster().Name())
suite.Require().EqualValues(request.ClusterConfig.ControlPlane.Endpoint, config.Cluster().Endpoint().String()) suite.Require().EqualValues(request.ClusterConfig.ControlPlane.Endpoint, config.Cluster().Endpoint().String())
suite.Require().EqualValues(request.ClusterConfig.ClusterNetwork.DnsDomain, config.Cluster().Network().DNSDomain()) suite.Require().EqualValues(request.ClusterConfig.ClusterNetwork.DnsDomain, config.Cluster().Network().DNSDomain())
suite.Require().EqualValues(request.ClusterConfig.ClusterNetwork.CniConfig.Name, config.Cluster().Network().CNI().Name()) suite.Require().EqualValues(
suite.Require().EqualValues(request.ClusterConfig.ClusterNetwork.CniConfig.Urls, config.Cluster().Network().CNI().URLs()) request.ClusterConfig.ClusterNetwork.CniConfig.Name,
suite.Require().EqualValues(fmt.Sprintf("%s:v%s", constants.KubeletImage, request.MachineConfig.KubernetesVersion), config.Machine().Kubelet().Image()) config.Cluster().Network().CNI().Name(),
)
suite.Require().EqualValues(
request.ClusterConfig.ClusterNetwork.CniConfig.Urls,
config.Cluster().Network().CNI().URLs(),
)
suite.Require().EqualValues(
fmt.Sprintf("%s:v%s", constants.KubeletImage, request.MachineConfig.KubernetesVersion),
config.Machine().Kubelet().Image(),
)
suite.Require().EqualValues(request.MachineConfig.InstallConfig.InstallDisk, disk) suite.Require().EqualValues(request.MachineConfig.InstallConfig.InstallDisk, disk)
suite.Require().EqualValues(request.MachineConfig.InstallConfig.InstallImage, config.Machine().Install().Image()) suite.Require().EqualValues(request.MachineConfig.InstallConfig.InstallImage, config.Machine().Install().Image())
suite.Require().EqualValues(request.MachineConfig.NetworkConfig.Hostname, config.Machine().Network().Hostname()) suite.Require().EqualValues(request.MachineConfig.NetworkConfig.Hostname, config.Machine().Network().Hostname())
@ -149,15 +158,30 @@ func (suite *GenerateConfigSuite) TestGenerate() {
suite.Require().EqualValues(request.ConfigVersion, joinedConfig.Version()) suite.Require().EqualValues(request.ConfigVersion, joinedConfig.Version())
suite.Require().EqualValues(request.ClusterConfig.Name, joinedConfig.Cluster().Name()) suite.Require().EqualValues(request.ClusterConfig.Name, joinedConfig.Cluster().Name())
suite.Require().EqualValues(request.ClusterConfig.ControlPlane.Endpoint, joinedConfig.Cluster().Endpoint().String()) suite.Require().EqualValues(request.ClusterConfig.ControlPlane.Endpoint, joinedConfig.Cluster().Endpoint().String())
suite.Require().EqualValues(request.ClusterConfig.ClusterNetwork.DnsDomain, joinedConfig.Cluster().Network().DNSDomain()) suite.Require().EqualValues(
suite.Require().EqualValues(fmt.Sprintf("%s:v%s", constants.KubeletImage, request.MachineConfig.KubernetesVersion), joinedConfig.Machine().Kubelet().Image()) request.ClusterConfig.ClusterNetwork.DnsDomain,
joinedConfig.Cluster().Network().DNSDomain(),
)
suite.Require().EqualValues(
fmt.Sprintf("%s:v%s", constants.KubeletImage, request.MachineConfig.KubernetesVersion),
joinedConfig.Machine().Kubelet().Image(),
)
suite.Require().EqualValues(request.MachineConfig.InstallConfig.InstallDisk, disk) suite.Require().EqualValues(request.MachineConfig.InstallConfig.InstallDisk, disk)
suite.Require().EqualValues(request.MachineConfig.InstallConfig.InstallImage, joinedConfig.Machine().Install().Image()) suite.Require().EqualValues(
suite.Require().EqualValues(request.MachineConfig.NetworkConfig.Hostname, joinedConfig.Machine().Network().Hostname()) request.MachineConfig.InstallConfig.InstallImage,
joinedConfig.Machine().Install().Image(),
)
suite.Require().EqualValues(
request.MachineConfig.NetworkConfig.Hostname,
joinedConfig.Machine().Network().Hostname(),
)
suite.Require().EqualValues(config.Machine().Security().CA(), joinedConfig.Machine().Security().CA()) suite.Require().EqualValues(config.Machine().Security().CA(), joinedConfig.Machine().Security().CA())
suite.Require().EqualValues(config.Machine().Security().Token(), joinedConfig.Machine().Security().Token()) suite.Require().EqualValues(config.Machine().Security().Token(), joinedConfig.Machine().Security().Token())
suite.Require().EqualValues(config.Cluster().AESCBCEncryptionSecret(), joinedConfig.Cluster().AESCBCEncryptionSecret()) suite.Require().EqualValues(
config.Cluster().AESCBCEncryptionSecret(),
joinedConfig.Cluster().AESCBCEncryptionSecret(),
)
suite.Require().EqualValues(config.Cluster().CA(), joinedConfig.Cluster().CA()) suite.Require().EqualValues(config.Cluster().CA(), joinedConfig.Cluster().CA())
suite.Require().EqualValues(config.Cluster().Token(), joinedConfig.Cluster().Token()) suite.Require().EqualValues(config.Cluster().Token(), joinedConfig.Cluster().Token())
suite.Require().EqualValues(config.Cluster().Etcd().CA(), config.Cluster().Etcd().CA()) suite.Require().EqualValues(config.Cluster().Etcd().CA(), config.Cluster().Etcd().CA())

View File

@ -25,10 +25,10 @@ import (
type LogsSuite struct { type LogsSuite struct {
base.APISuite base.APISuite
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
nodeCtx context.Context nodeCtx context.Context //nolint:containedctx
} }
// SuiteName ... // SuiteName ...
@ -167,7 +167,11 @@ func (suite *LogsSuite) testStreaming(tailLines int32) {
// invoke machined enough times to generate // invoke machined enough times to generate
// some logs // some logs
for i := int32(0); i < tailLines; i++ { for i := int32(0); i < tailLines; i++ {
_, err := suite.Client.Stats(suite.nodeCtx, constants.SystemContainerdNamespace, common.ContainerDriver_CONTAINERD) _, err := suite.Client.Stats(
suite.nodeCtx,
constants.SystemContainerdNamespace,
common.ContainerDriver_CONTAINERD,
)
suite.Require().NoError(err) suite.Require().NoError(err)
} }
} }

View File

@ -24,7 +24,7 @@ import (
type RebootSuite struct { type RebootSuite struct {
base.APISuite base.APISuite
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -62,9 +62,11 @@ func (suite *RebootSuite) TestRebootNodeByNode() {
for _, node := range nodes { for _, node := range nodes {
suite.T().Log("rebooting node", node) suite.T().Log("rebooting node", node)
suite.AssertRebooted(suite.ctx, node, func(nodeCtx context.Context) error { suite.AssertRebooted(
return base.IgnoreGRPCUnavailable(suite.Client.Reboot(nodeCtx)) suite.ctx, node, func(nodeCtx context.Context) error {
}, 10*time.Minute) return base.IgnoreGRPCUnavailable(suite.Client.Reboot(nodeCtx))
}, 10*time.Minute,
)
} }
} }
@ -123,23 +125,32 @@ func (suite *RebootSuite) TestRebootAllNodes() {
nodeCtx := client.WithNodes(suite.ctx, node) nodeCtx := client.WithNodes(suite.ctx, node)
return retry.Constant(10 * time.Minute).Retry(func() error { return retry.Constant(10 * time.Minute).Retry(
requestCtx, requestCtxCancel := context.WithTimeout(nodeCtx, 5*time.Second) func() error {
defer requestCtxCancel() requestCtx, requestCtxCancel := context.WithTimeout(nodeCtx, 5*time.Second)
defer requestCtxCancel()
bootIDAfter, err := suite.ReadBootID(requestCtx) bootIDAfter, err := suite.ReadBootID(requestCtx)
if err != nil { if err != nil {
// API might be unresponsive during reboot // API might be unresponsive during reboot
return retry.ExpectedError(fmt.Errorf("error reading bootID for node %q: %w", node, err)) return retry.ExpectedError(fmt.Errorf("error reading bootID for node %q: %w", node, err))
} }
if bootIDAfter == bootIDBefore { if bootIDAfter == bootIDBefore {
// bootID should be different after reboot // bootID should be different after reboot
return retry.ExpectedError(fmt.Errorf("bootID didn't change for node %q: before %s, after %s", node, bootIDBefore, bootIDAfter)) return retry.ExpectedError(
} fmt.Errorf(
"bootID didn't change for node %q: before %s, after %s",
node,
bootIDBefore,
bootIDAfter,
),
)
}
return nil return nil
}) },
)
}() }()
}(node) }(node)
} }

View File

@ -23,7 +23,7 @@ import (
type ResetSuite struct { type ResetSuite struct {
base.APISuite base.APISuite
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -88,10 +88,12 @@ func (suite *ResetSuite) TestResetNodeByNode() {
preReset, err := suite.HashKubeletCert(suite.ctx, node) preReset, err := suite.HashKubeletCert(suite.ctx, node)
suite.Require().NoError(err) suite.Require().NoError(err)
suite.AssertRebooted(suite.ctx, node, func(nodeCtx context.Context) error { suite.AssertRebooted(
// force reboot after reset, as this is the only mode we can test suite.ctx, node, func(nodeCtx context.Context) error {
return base.IgnoreGRPCUnavailable(suite.Client.Reset(nodeCtx, true, true)) // force reboot after reset, as this is the only mode we can test
}, 10*time.Minute) return base.IgnoreGRPCUnavailable(suite.Client.Reset(nodeCtx, true, true))
}, 10*time.Minute,
)
suite.ClearConnectionRefused(suite.ctx, node) suite.ClearConnectionRefused(suite.ctx, node)
@ -118,10 +120,12 @@ func (suite *ResetSuite) testResetNoGraceful(nodeType machine.Type) {
preReset, err := suite.HashKubeletCert(suite.ctx, node) preReset, err := suite.HashKubeletCert(suite.ctx, node)
suite.Require().NoError(err) suite.Require().NoError(err)
suite.AssertRebooted(suite.ctx, node, func(nodeCtx context.Context) error { suite.AssertRebooted(
// force reboot after reset, as this is the only mode we can test suite.ctx, node, func(nodeCtx context.Context) error {
return base.IgnoreGRPCUnavailable(suite.Client.Reset(nodeCtx, false, true)) // force reboot after reset, as this is the only mode we can test
}, 5*time.Minute) return base.IgnoreGRPCUnavailable(suite.Client.Reset(nodeCtx, false, true))
}, 5*time.Minute,
)
suite.ClearConnectionRefused(suite.ctx, node) suite.ClearConnectionRefused(suite.ctx, node)
@ -162,19 +166,25 @@ func (suite *ResetSuite) TestResetWithSpecEphemeral() {
preReset, err := suite.HashKubeletCert(suite.ctx, node) preReset, err := suite.HashKubeletCert(suite.ctx, node)
suite.Require().NoError(err) suite.Require().NoError(err)
suite.AssertRebooted(suite.ctx, node, func(nodeCtx context.Context) error { suite.AssertRebooted(
// force reboot after reset, as this is the only mode we can test suite.ctx, node, func(nodeCtx context.Context) error {
return base.IgnoreGRPCUnavailable(suite.Client.ResetGeneric(nodeCtx, &machineapi.ResetRequest{ // force reboot after reset, as this is the only mode we can test
Reboot: true, return base.IgnoreGRPCUnavailable(
Graceful: true, suite.Client.ResetGeneric(
SystemPartitionsToWipe: []*machineapi.ResetPartitionSpec{ nodeCtx, &machineapi.ResetRequest{
{ Reboot: true,
Label: constants.EphemeralPartitionLabel, Graceful: true,
Wipe: true, SystemPartitionsToWipe: []*machineapi.ResetPartitionSpec{
}, {
}, Label: constants.EphemeralPartitionLabel,
})) Wipe: true,
}, 5*time.Minute) },
},
},
),
)
}, 5*time.Minute,
)
suite.ClearConnectionRefused(suite.ctx, node) suite.ClearConnectionRefused(suite.ctx, node)
@ -205,19 +215,25 @@ func (suite *ResetSuite) TestResetWithSpecState() {
preReset, err := suite.HashKubeletCert(suite.ctx, node) preReset, err := suite.HashKubeletCert(suite.ctx, node)
suite.Require().NoError(err) suite.Require().NoError(err)
suite.AssertRebooted(suite.ctx, node, func(nodeCtx context.Context) error { suite.AssertRebooted(
// force reboot after reset, as this is the only mode we can test suite.ctx, node, func(nodeCtx context.Context) error {
return base.IgnoreGRPCUnavailable(suite.Client.ResetGeneric(nodeCtx, &machineapi.ResetRequest{ // force reboot after reset, as this is the only mode we can test
Reboot: true, return base.IgnoreGRPCUnavailable(
Graceful: true, suite.Client.ResetGeneric(
SystemPartitionsToWipe: []*machineapi.ResetPartitionSpec{ nodeCtx, &machineapi.ResetRequest{
{ Reboot: true,
Label: constants.StatePartitionLabel, Graceful: true,
Wipe: true, SystemPartitionsToWipe: []*machineapi.ResetPartitionSpec{
}, {
}, Label: constants.StatePartitionLabel,
})) Wipe: true,
}, 5*time.Minute) },
},
},
),
)
}, 5*time.Minute,
)
suite.ClearConnectionRefused(suite.ctx, node) suite.ClearConnectionRefused(suite.ctx, node)

View File

@ -22,7 +22,7 @@ import (
type VersionSuite struct { type VersionSuite struct {
base.APISuite base.APISuite
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }

View File

@ -87,8 +87,13 @@ func upgradePreviousToStable() upgradeSpec {
return upgradeSpec{ return upgradeSpec{
ShortName: fmt.Sprintf("%s-%s", previousRelease, stableRelease), ShortName: fmt.Sprintf("%s-%s", previousRelease, stableRelease),
SourceKernelPath: helpers.ArtifactPath(filepath.Join(trimVersion(previousRelease), constants.KernelAsset)), SourceKernelPath: helpers.ArtifactPath(filepath.Join(trimVersion(previousRelease), constants.KernelAsset)),
SourceInitramfsPath: helpers.ArtifactPath(filepath.Join(trimVersion(previousRelease), constants.InitramfsAsset)), SourceInitramfsPath: helpers.ArtifactPath(
filepath.Join(
trimVersion(previousRelease),
constants.InitramfsAsset,
),
),
SourceInstallerImage: fmt.Sprintf("%s:%s", "ghcr.io/siderolabs/installer", previousRelease), SourceInstallerImage: fmt.Sprintf("%s:%s", "ghcr.io/siderolabs/installer", previousRelease),
SourceVersion: previousRelease, SourceVersion: previousRelease,
SourceK8sVersion: previousK8sVersion, SourceK8sVersion: previousK8sVersion,
@ -116,9 +121,14 @@ func upgradeStableToCurrent() upgradeSpec {
SourceVersion: stableRelease, SourceVersion: stableRelease,
SourceK8sVersion: stableK8sVersion, SourceK8sVersion: stableK8sVersion,
TargetInstallerImage: fmt.Sprintf("%s/%s:%s", DefaultSettings.TargetInstallImageRegistry, images.DefaultInstallerImageName, DefaultSettings.CurrentVersion), TargetInstallerImage: fmt.Sprintf(
TargetVersion: DefaultSettings.CurrentVersion, "%s/%s:%s",
TargetK8sVersion: currentK8sVersion, DefaultSettings.TargetInstallImageRegistry,
images.DefaultInstallerImageName,
DefaultSettings.CurrentVersion,
),
TargetVersion: DefaultSettings.CurrentVersion,
TargetK8sVersion: currentK8sVersion,
MasterNodes: DefaultSettings.MasterNodes, MasterNodes: DefaultSettings.MasterNodes,
WorkerNodes: DefaultSettings.WorkerNodes, WorkerNodes: DefaultSettings.WorkerNodes,
@ -127,7 +137,12 @@ func upgradeStableToCurrent() upgradeSpec {
// upgradeCurrentToCurrent upgrades the current version to itself. // upgradeCurrentToCurrent upgrades the current version to itself.
func upgradeCurrentToCurrent() upgradeSpec { func upgradeCurrentToCurrent() upgradeSpec {
installerImage := fmt.Sprintf("%s/%s:%s", DefaultSettings.TargetInstallImageRegistry, images.DefaultInstallerImageName, DefaultSettings.CurrentVersion) installerImage := fmt.Sprintf(
"%s/%s:%s",
DefaultSettings.TargetInstallImageRegistry,
images.DefaultInstallerImageName,
DefaultSettings.CurrentVersion,
)
return upgradeSpec{ return upgradeSpec{
ShortName: fmt.Sprintf("%s-%s", DefaultSettings.CurrentVersion, DefaultSettings.CurrentVersion), ShortName: fmt.Sprintf("%s-%s", DefaultSettings.CurrentVersion, DefaultSettings.CurrentVersion),
@ -160,9 +175,14 @@ func upgradeStableToCurrentPreserve() upgradeSpec {
SourceVersion: stableRelease, SourceVersion: stableRelease,
SourceK8sVersion: stableK8sVersion, SourceK8sVersion: stableK8sVersion,
TargetInstallerImage: fmt.Sprintf("%s/%s:%s", DefaultSettings.TargetInstallImageRegistry, images.DefaultInstallerImageName, DefaultSettings.CurrentVersion), TargetInstallerImage: fmt.Sprintf(
TargetVersion: DefaultSettings.CurrentVersion, "%s/%s:%s",
TargetK8sVersion: currentK8sVersion, DefaultSettings.TargetInstallImageRegistry,
images.DefaultInstallerImageName,
DefaultSettings.CurrentVersion,
),
TargetVersion: DefaultSettings.CurrentVersion,
TargetK8sVersion: currentK8sVersion,
MasterNodes: 1, MasterNodes: 1,
WorkerNodes: 0, WorkerNodes: 0,
@ -181,9 +201,14 @@ func upgradeStableToCurrentPreserveStage() upgradeSpec {
SourceVersion: stableRelease, SourceVersion: stableRelease,
SourceK8sVersion: stableK8sVersion, SourceK8sVersion: stableK8sVersion,
TargetInstallerImage: fmt.Sprintf("%s/%s:%s", DefaultSettings.TargetInstallImageRegistry, images.DefaultInstallerImageName, DefaultSettings.CurrentVersion), TargetInstallerImage: fmt.Sprintf(
TargetVersion: DefaultSettings.CurrentVersion, "%s/%s:%s",
TargetK8sVersion: currentK8sVersion, DefaultSettings.TargetInstallImageRegistry,
images.DefaultInstallerImageName,
DefaultSettings.CurrentVersion,
),
TargetVersion: DefaultSettings.CurrentVersion,
TargetK8sVersion: currentK8sVersion,
MasterNodes: 1, MasterNodes: 1,
WorkerNodes: 0, WorkerNodes: 0,
@ -209,6 +234,7 @@ type UpgradeSuite struct {
clusterAccess *access.Adapter clusterAccess *access.Adapter
controlPlaneEndpoint string controlPlaneEndpoint string
//nolint:containedctx
ctx context.Context ctx context.Context
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
@ -333,55 +359,67 @@ func (suite *UpgradeSuite) setupCluster() {
} }
if DefaultSettings.CustomCNIURL != "" { if DefaultSettings.CustomCNIURL != "" {
genOptions = append(genOptions, generate.WithClusterCNIConfig(&v1alpha1.CNIConfig{ genOptions = append(
CNIName: constants.CustomCNI, genOptions, generate.WithClusterCNIConfig(
CNIUrls: []string{DefaultSettings.CustomCNIURL}, &v1alpha1.CNIConfig{
})) CNIName: constants.CustomCNI,
CNIUrls: []string{DefaultSettings.CustomCNIURL},
},
),
)
} }
if suite.spec.WithEncryption { if suite.spec.WithEncryption {
genOptions = append(genOptions, generate.WithSystemDiskEncryption(&v1alpha1.SystemDiskEncryptionConfig{ genOptions = append(
StatePartition: &v1alpha1.EncryptionConfig{ genOptions, generate.WithSystemDiskEncryption(
EncryptionProvider: encryption.LUKS2, &v1alpha1.SystemDiskEncryptionConfig{
EncryptionKeys: []*v1alpha1.EncryptionKey{ StatePartition: &v1alpha1.EncryptionConfig{
{ EncryptionProvider: encryption.LUKS2,
KeyNodeID: &v1alpha1.EncryptionKeyNodeID{}, EncryptionKeys: []*v1alpha1.EncryptionKey{
KeySlot: 0, {
KeyNodeID: &v1alpha1.EncryptionKeyNodeID{},
KeySlot: 0,
},
},
},
EphemeralPartition: &v1alpha1.EncryptionConfig{
EncryptionProvider: encryption.LUKS2,
EncryptionKeys: []*v1alpha1.EncryptionKey{
{
KeyNodeID: &v1alpha1.EncryptionKeyNodeID{},
KeySlot: 0,
},
},
}, },
}, },
}, ),
EphemeralPartition: &v1alpha1.EncryptionConfig{ )
EncryptionProvider: encryption.LUKS2,
EncryptionKeys: []*v1alpha1.EncryptionKey{
{
KeyNodeID: &v1alpha1.EncryptionKeyNodeID{},
KeySlot: 0,
},
},
},
}))
} }
versionContract, err := config.ParseContractFromVersion(suite.spec.SourceVersion) versionContract, err := config.ParseContractFromVersion(suite.spec.SourceVersion)
suite.Require().NoError(err) suite.Require().NoError(err)
suite.configBundle, err = bundle.NewConfigBundle(bundle.WithInputOptions( suite.configBundle, err = bundle.NewConfigBundle(
&bundle.InputOptions{ bundle.WithInputOptions(
ClusterName: clusterName, &bundle.InputOptions{
Endpoint: suite.controlPlaneEndpoint, ClusterName: clusterName,
KubeVersion: suite.spec.SourceK8sVersion, Endpoint: suite.controlPlaneEndpoint,
GenOptions: append( KubeVersion: suite.spec.SourceK8sVersion,
genOptions, GenOptions: append(
generate.WithEndpointList(masterEndpoints), genOptions,
generate.WithInstallImage(suite.spec.SourceInstallerImage), generate.WithEndpointList(masterEndpoints),
generate.WithDNSDomain("cluster.local"), generate.WithInstallImage(suite.spec.SourceInstallerImage),
generate.WithVersionContract(versionContract), generate.WithDNSDomain("cluster.local"),
), generate.WithVersionContract(versionContract),
})) ),
},
),
)
suite.Require().NoError(err) suite.Require().NoError(err)
for i := 0; i < suite.spec.MasterNodes; i++ { for i := 0; i < suite.spec.MasterNodes; i++ {
request.Nodes = append(request.Nodes, request.Nodes = append(
request.Nodes,
provision.NodeRequest{ provision.NodeRequest{
Name: fmt.Sprintf("master-%d", i+1), Name: fmt.Sprintf("master-%d", i+1),
Type: machine.TypeControlPlane, Type: machine.TypeControlPlane,
@ -394,11 +432,13 @@ func (suite *UpgradeSuite) setupCluster() {
}, },
}, },
Config: suite.configBundle.ControlPlane(), Config: suite.configBundle.ControlPlane(),
}) },
)
} }
for i := 1; i <= suite.spec.WorkerNodes; i++ { for i := 1; i <= suite.spec.WorkerNodes; i++ {
request.Nodes = append(request.Nodes, request.Nodes = append(
request.Nodes,
provision.NodeRequest{ provision.NodeRequest{
Name: fmt.Sprintf("worker-%d", i), Name: fmt.Sprintf("worker-%d", i),
Type: machine.TypeWorker, Type: machine.TypeWorker,
@ -411,10 +451,12 @@ func (suite *UpgradeSuite) setupCluster() {
}, },
}, },
Config: suite.configBundle.Worker(), Config: suite.configBundle.Worker(),
}) },
)
} }
suite.Cluster, err = suite.provisioner.Create(suite.ctx, request, suite.Cluster, err = suite.provisioner.Create(
suite.ctx, request,
provision.WithBootlader(true), provision.WithBootlader(true),
provision.WithUEFI(true), provision.WithUEFI(true),
provision.WithTalosConfig(suite.configBundle.TalosConfig()), provision.WithTalosConfig(suite.configBundle.TalosConfig()),
@ -457,7 +499,14 @@ func (suite *UpgradeSuite) waitForClusterHealth() {
checkCtx, checkCtxCancel := context.WithTimeout(suite.ctx, 15*time.Minute) checkCtx, checkCtxCancel := context.WithTimeout(suite.ctx, 15*time.Minute)
defer checkCtxCancel() defer checkCtxCancel()
suite.Require().NoError(check.Wait(checkCtx, suite.clusterAccess, check.DefaultClusterChecks(), check.StderrReporter())) suite.Require().NoError(
check.Wait(
checkCtx,
suite.clusterAccess,
check.DefaultClusterChecks(),
check.StderrReporter(),
),
)
} }
} }
@ -487,12 +536,14 @@ func (suite *UpgradeSuite) assertSameVersionCluster(client *talosclient.Client,
err := retry.Constant( err := retry.Constant(
time.Minute, time.Minute,
).Retry(func() error { ).Retry(
var e error func() error {
v, e = client.Version(ctx) var e error
v, e = client.Version(ctx)
return retry.ExpectedError(e) return retry.ExpectedError(e)
}) },
)
suite.Require().NoError(err) suite.Require().NoError(err)
@ -503,7 +554,10 @@ func (suite *UpgradeSuite) assertSameVersionCluster(client *talosclient.Client,
} }
} }
func (suite *UpgradeSuite) readVersion(nodeCtx context.Context, client *talosclient.Client) (version string, err error) { func (suite *UpgradeSuite) readVersion(nodeCtx context.Context, client *talosclient.Client) (
version string,
err error,
) {
var v *machineapi.VersionResponse var v *machineapi.VersionResponse
v, err = client.Version(nodeCtx) v, err = client.Version(nodeCtx)
@ -526,22 +580,30 @@ func (suite *UpgradeSuite) upgradeNode(client *talosclient.Client, node provisio
err error err error
) )
err = retry.Constant(time.Minute, retry.WithUnits(10*time.Second)).Retry(func() error { err = retry.Constant(time.Minute, retry.WithUnits(10*time.Second)).Retry(
resp, err = client.Upgrade(nodeCtx, suite.spec.TargetInstallerImage, suite.spec.UpgradePreserve, suite.spec.UpgradeStage, false) func() error {
if err != nil { resp, err = client.Upgrade(
if strings.Contains(err.Error(), "leader changed") { nodeCtx,
return retry.ExpectedError(err) suite.spec.TargetInstallerImage,
suite.spec.UpgradePreserve,
suite.spec.UpgradeStage,
false,
)
if err != nil {
if strings.Contains(err.Error(), "leader changed") {
return retry.ExpectedError(err)
}
if strings.Contains(err.Error(), "failed to acquire upgrade lock") {
return retry.ExpectedError(err)
}
return err
} }
if strings.Contains(err.Error(), "failed to acquire upgrade lock") { return nil
return retry.ExpectedError(err) },
} )
return err
}
return nil
})
err = base.IgnoreGRPCUnavailable(err) err = base.IgnoreGRPCUnavailable(err)
suite.Require().NoError(err) suite.Require().NoError(err)
@ -554,22 +616,33 @@ func (suite *UpgradeSuite) upgradeNode(client *talosclient.Client, node provisio
time.Sleep(10 * time.Second) time.Sleep(10 * time.Second)
// wait for the version to be equal to target version // wait for the version to be equal to target version
suite.Require().NoError(retry.Constant(10 * time.Minute).Retry(func() error { suite.Require().NoError(
var version string retry.Constant(10 * time.Minute).Retry(
func() error {
var version string
version, err = suite.readVersion(nodeCtx, client) version, err = suite.readVersion(nodeCtx, client)
if err != nil { if err != nil {
// API might be unresponsive during upgrade // API might be unresponsive during upgrade
return retry.ExpectedError(err) return retry.ExpectedError(err)
} }
if version != suite.spec.TargetVersion { if version != suite.spec.TargetVersion {
// upgrade not finished yet // upgrade not finished yet
return retry.ExpectedError(fmt.Errorf("node %q version doesn't match expected: expected %q, got %q", node.IPs[0].String(), suite.spec.TargetVersion, version)) return retry.ExpectedError(
} fmt.Errorf(
"node %q version doesn't match expected: expected %q, got %q",
node.IPs[0].String(),
suite.spec.TargetVersion,
version,
),
)
}
return nil return nil
})) },
),
)
suite.waitForClusterHealth() suite.waitForClusterHealth()
} }
@ -622,7 +695,13 @@ func (suite *UpgradeSuite) untaint(name string) {
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, corev1.Node{}) patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, corev1.Node{})
suite.Require().NoError(err) suite.Require().NoError(err)
_, err = client.CoreV1().Nodes().Patch(suite.ctx, n.Name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{}) _, err = client.CoreV1().Nodes().Patch(
suite.ctx,
n.Name,
types.StrategicMergePatchType,
patchBytes,
metav1.PatchOptions{},
)
suite.Require().NoError(err) suite.Require().NoError(err)
} }
@ -670,7 +749,8 @@ func (suite *UpgradeSuite) SuiteName() string {
} }
func init() { func init() {
allSuites = append(allSuites, allSuites = append(
allSuites,
&UpgradeSuite{specGen: upgradePreviousToStable, track: 0}, &UpgradeSuite{specGen: upgradePreviousToStable, track: 0},
&UpgradeSuite{specGen: upgradeStableToCurrent, track: 1}, &UpgradeSuite{specGen: upgradeStableToCurrent, track: 1},
&UpgradeSuite{specGen: upgradeCurrentToCurrent, track: 2}, &UpgradeSuite{specGen: upgradeCurrentToCurrent, track: 2},

View File

@ -29,7 +29,8 @@ import (
type inspector struct { type inspector struct {
client *containerd.Client client *containerd.Client
nsctx context.Context //nolint:containedctx
nsctx context.Context
} }
type inspectorOptions struct { type inspectorOptions struct {
@ -97,7 +98,11 @@ func (i *inspector) Images() (map[string]string, error) {
} }
//nolint:gocyclo,cyclop //nolint:gocyclo,cyclop
func (i *inspector) containerInfo(cntr containerd.Container, imageList map[string]string, singleLookup bool) (*ctrs.Container, error) { func (i *inspector) containerInfo(
cntr containerd.Container,
imageList map[string]string,
singleLookup bool,
) (*ctrs.Container, error) {
cp := &ctrs.Container{} cp := &ctrs.Container{}
info, err := cntr.Info(i.nsctx) info, err := cntr.Info(i.nsctx)
@ -222,7 +227,11 @@ func (i *inspector) containerInfo(cntr containerd.Container, imageList map[strin
cp.IsPodSandbox = true cp.IsPodSandbox = true
} else if singleLookup && cns != "" && cname != "" { } else if singleLookup && cns != "" && cname != "" {
// try to find matching infrastructure container and pull sandbox from it // try to find matching infrastructure container and pull sandbox from it
query := fmt.Sprintf("labels.\"io.kubernetes.pod.namespace\"==%q,labels.\"io.kubernetes.pod.name\"==%q", cns, cname) query := fmt.Sprintf(
"labels.\"io.kubernetes.pod.namespace\"==%q,labels.\"io.kubernetes.pod.name\"==%q",
cns,
cname,
)
infraContainers, err := i.client.Containers(i.nsctx, query) infraContainers, err := i.client.Containers(i.nsctx, query)
if err == nil { if err == nil {
@ -274,7 +283,11 @@ func (i *inspector) Container(id string) (*ctrs.Container, error) {
pod = pod[:semicolonIdx] pod = pod[:semicolonIdx]
} }
query = fmt.Sprintf("labels.\"io.kubernetes.pod.namespace\"==%q,labels.\"io.kubernetes.pod.name\"==%q", namespace, pod) query = fmt.Sprintf(
"labels.\"io.kubernetes.pod.namespace\"==%q,labels.\"io.kubernetes.pod.name\"==%q",
namespace,
pod,
)
if name != "" { if name != "" {
query += fmt.Sprintf(",labels.\"io.kubernetes.container.name\"==%q", name) query += fmt.Sprintf(",labels.\"io.kubernetes.container.name\"==%q", name)

View File

@ -21,7 +21,7 @@ import (
type inspector struct { type inspector struct {
client *criclient.Client client *criclient.Client
ctx context.Context ctx context.Context //nolint:containedctx
} }
type inspectorOptions struct { type inspectorOptions struct {
@ -112,15 +112,17 @@ func (i *inspector) Container(id string) (*ctrs.Container, error) {
} }
if name == "" { // request for a pod sandbox if name == "" { // request for a pod sandbox
sandboxes, err := i.client.ListPodSandbox(i.ctx, &runtimeapi.PodSandboxFilter{ sandboxes, err := i.client.ListPodSandbox(
State: &runtimeapi.PodSandboxStateValue{ i.ctx, &runtimeapi.PodSandboxFilter{
State: runtimeapi.PodSandboxState_SANDBOX_READY, State: &runtimeapi.PodSandboxStateValue{
State: runtimeapi.PodSandboxState_SANDBOX_READY,
},
LabelSelector: map[string]string{
"io.kubernetes.pod.name": pod,
"io.kubernetes.pod.namespace": namespace,
},
}, },
LabelSelector: map[string]string{ )
"io.kubernetes.pod.name": pod,
"io.kubernetes.pod.namespace": namespace,
},
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -138,13 +140,15 @@ func (i *inspector) Container(id string) (*ctrs.Container, error) {
} }
// request for a container // request for a container
containers, err := i.client.ListContainers(i.ctx, &runtimeapi.ContainerFilter{ containers, err := i.client.ListContainers(
LabelSelector: map[string]string{ i.ctx, &runtimeapi.ContainerFilter{
"io.kubernetes.pod.name": pod, LabelSelector: map[string]string{
"io.kubernetes.pod.namespace": namespace, "io.kubernetes.pod.name": pod,
"io.kubernetes.container.name": name, "io.kubernetes.pod.namespace": namespace,
"io.kubernetes.container.name": name,
},
}, },
}) )
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -242,11 +246,13 @@ func (i *inspector) buildContainer(container *runtimeapi.Container) (*ctrs.Conta
// //
//nolint:gocyclo //nolint:gocyclo
func (i *inspector) Pods() ([]*ctrs.Pod, error) { func (i *inspector) Pods() ([]*ctrs.Pod, error) {
sandboxes, err := i.client.ListPodSandbox(i.ctx, &runtimeapi.PodSandboxFilter{ sandboxes, err := i.client.ListPodSandbox(
State: &runtimeapi.PodSandboxStateValue{ i.ctx, &runtimeapi.PodSandboxFilter{
State: runtimeapi.PodSandboxState_SANDBOX_READY, State: &runtimeapi.PodSandboxStateValue{
State: runtimeapi.PodSandboxState_SANDBOX_READY,
},
}, },
}) )
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -50,7 +50,7 @@ type CRISuite struct {
containerdAddress string containerdAddress string
client *criclient.Client client *criclient.Client
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
inspector ctrs.Inspector inspector ctrs.Inspector
@ -175,12 +175,15 @@ func (suite *CRISuite) SetupTest() {
suite.pods = append(suite.pods, podSandboxID) suite.pods = append(suite.pods, podSandboxID)
suite.Require().Len(podSandboxID, 64) suite.Require().Len(podSandboxID, 64)
imageRef, err := suite.client.PullImage(suite.ctx, &runtimeapi.ImageSpec{ imageRef, err := suite.client.PullImage(
Image: busyboxImage, suite.ctx, &runtimeapi.ImageSpec{
}, podSandboxConfig) Image: busyboxImage,
}, podSandboxConfig,
)
suite.Require().NoError(err) suite.Require().NoError(err)
ctrID, err := suite.client.CreateContainer(suite.ctx, podSandboxID, ctrID, err := suite.client.CreateContainer(
suite.ctx, podSandboxID,
&runtimeapi.ContainerConfig{ &runtimeapi.ContainerConfig{
Metadata: &runtimeapi.ContainerMetadata{ Metadata: &runtimeapi.ContainerMetadata{
Name: "etcd", Name: "etcd",
@ -197,7 +200,8 @@ func (suite *CRISuite) SetupTest() {
Image: imageRef, Image: imageRef,
}, },
Command: []string{"/bin/sh", "-c", "sleep 3600"}, Command: []string{"/bin/sh", "-c", "sleep 3600"},
}, podSandboxConfig) }, podSandboxConfig,
)
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Require().Len(ctrID, 64) suite.Require().Len(ctrID, 64)

View File

@ -47,7 +47,7 @@ type CRISuite struct {
containerdAddress string containerdAddress string
client *cri.Client client *cri.Client
ctx context.Context ctx context.Context //nolint:containedctx
ctxCancel context.CancelFunc ctxCancel context.CancelFunc
} }
@ -165,17 +165,22 @@ func (suite *CRISuite) TestRunSandboxContainer() {
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Require().Len(podSandboxID, 64) suite.Require().Len(podSandboxID, 64)
imageRef, err := suite.client.PullImage(suite.ctx, &runtimeapi.ImageSpec{ imageRef, err := suite.client.PullImage(
Image: busyboxImage, suite.ctx, &runtimeapi.ImageSpec{
}, podSandboxConfig) Image: busyboxImage,
}, podSandboxConfig,
)
suite.Require().NoError(err) suite.Require().NoError(err)
_, err = suite.client.ImageStatus(suite.ctx, &runtimeapi.ImageSpec{ _, err = suite.client.ImageStatus(
Image: imageRef, suite.ctx, &runtimeapi.ImageSpec{
}) Image: imageRef,
},
)
suite.Require().NoError(err) suite.Require().NoError(err)
ctrID, err := suite.client.CreateContainer(suite.ctx, podSandboxID, ctrID, err := suite.client.CreateContainer(
suite.ctx, podSandboxID,
&runtimeapi.ContainerConfig{ &runtimeapi.ContainerConfig{
Metadata: &runtimeapi.ContainerMetadata{ Metadata: &runtimeapi.ContainerMetadata{
Name: "etcd", Name: "etcd",
@ -192,7 +197,8 @@ func (suite *CRISuite) TestRunSandboxContainer() {
Image: imageRef, Image: imageRef,
}, },
Command: []string{"/bin/sh", "-c", "sleep 3600"}, Command: []string{"/bin/sh", "-c", "sleep 3600"},
}, podSandboxConfig) }, podSandboxConfig,
)
suite.Require().NoError(err) suite.Require().NoError(err)
suite.Require().Len(ctrID, 64) suite.Require().Len(ctrID, 64)

View File

@ -25,12 +25,15 @@ type Connection struct {
bootstrapEndpoint string bootstrapEndpoint string
nodeClient *client.Client nodeClient *client.Client
bootstrapClient *client.Client bootstrapClient *client.Client
nodeCtx context.Context nodeCtx context.Context //nolint:containedctx
bootstrapCtx context.Context bootstrapCtx context.Context //nolint:containedctx
} }
// NewConnection creates new installer connection. // NewConnection creates new installer connection.
func NewConnection(ctx context.Context, nodeClient *client.Client, endpoint string, options ...Option) (*Connection, error) { func NewConnection(ctx context.Context, nodeClient *client.Client, endpoint string, options ...Option) (
*Connection,
error,
) {
c := &Connection{ c := &Connection{
nodeEndpoint: endpoint, nodeEndpoint: endpoint,
nodeClient: nodeClient, nodeClient: nodeClient,
@ -48,7 +51,10 @@ func NewConnection(ctx context.Context, nodeClient *client.Client, endpoint stri
} }
// GenerateConfiguration calls GenerateConfiguration on the target/bootstrap node. // GenerateConfiguration calls GenerateConfiguration on the target/bootstrap node.
func (c *Connection) GenerateConfiguration(req *machine.GenerateConfigurationRequest, callOptions ...grpc.CallOption) (*machine.GenerateConfigurationResponse, error) { func (c *Connection) GenerateConfiguration(
req *machine.GenerateConfigurationRequest,
callOptions ...grpc.CallOption,
) (*machine.GenerateConfigurationResponse, error) {
if c.bootstrapClient != nil { if c.bootstrapClient != nil {
return c.bootstrapClient.GenerateConfiguration(c.bootstrapCtx, req, callOptions...) return c.bootstrapClient.GenerateConfiguration(c.bootstrapCtx, req, callOptions...)
} }
@ -57,7 +63,10 @@ func (c *Connection) GenerateConfiguration(req *machine.GenerateConfigurationReq
} }
// ApplyConfiguration calls ApplyConfiguration on the target node using appropriate node context. // ApplyConfiguration calls ApplyConfiguration on the target node using appropriate node context.
func (c *Connection) ApplyConfiguration(req *machine.ApplyConfigurationRequest, callOptions ...grpc.CallOption) (*machine.ApplyConfigurationResponse, error) { func (c *Connection) ApplyConfiguration(
req *machine.ApplyConfigurationRequest,
callOptions ...grpc.CallOption,
) (*machine.ApplyConfigurationResponse, error) {
return c.nodeClient.ApplyConfiguration(c.nodeCtx, req, callOptions...) return c.nodeClient.ApplyConfiguration(c.nodeCtx, req, callOptions...)
} }

View File

@ -41,7 +41,7 @@ type Installer struct {
app *tview.Application app *tview.Application
wg sync.WaitGroup wg sync.WaitGroup
err error err error
ctx context.Context ctx context.Context //nolint:containedctx
cancel context.CancelFunc cancel context.CancelFunc
addedPages map[string]bool addedPages map[string]bool
state *State state *State
@ -204,30 +204,32 @@ func (installer *Installer) configure() error {
} }
capture := installer.app.GetInputCapture() capture := installer.app.GetInputCapture()
installer.app.SetInputCapture(func(e *tcell.EventKey) *tcell.EventKey { installer.app.SetInputCapture(
//nolint:exhaustive func(e *tcell.EventKey) *tcell.EventKey {
switch e.Key() { //nolint:exhaustive
case tcell.KeyCtrlN: switch e.Key() {
setPage(currentPage + 1) case tcell.KeyCtrlN:
case tcell.KeyCtrlB: setPage(currentPage + 1)
setPage(currentPage - 1) case tcell.KeyCtrlB:
} setPage(currentPage - 1)
// page jump by ctrl/alt + N
if e.Rune() >= '1' && e.Rune() < '9' {
if e.Modifiers()&(tcell.ModAlt|tcell.ModCtrl) != 0 {
setPage(int(e.Rune()) - 49)
return nil
} }
}
if capture != nil { // page jump by ctrl/alt + N
return capture(e) if e.Rune() >= '1' && e.Rune() < '9' {
} if e.Modifiers()&(tcell.ModAlt|tcell.ModCtrl) != 0 {
setPage(int(e.Rune()) - 49)
return e return nil
}) }
}
if capture != nil {
return capture(e)
}
return e
},
)
defer installer.app.SetInputCapture(capture) defer installer.app.SetInputCapture(capture)
@ -240,9 +242,11 @@ func (installer *Installer) configure() error {
button.SetInactiveColors(inactiveColor, tcell.ColorIvory) button.SetInactiveColors(inactiveColor, tcell.ColorIvory)
func(page int) { func(page int) {
button.SetSelectedFunc(func() { button.SetSelectedFunc(
setPage(page) func() {
}) setPage(page)
},
)
}(index) }(index)
menu.AddItem(button, len(name)+4, 1, false) menu.AddItem(button, len(name)+4, 1, false)
@ -267,9 +271,11 @@ func (installer *Installer) configure() error {
if index > 0 { if index > 0 {
back := form.AddMenuButton("[::u]B[::-]ack", false) back := form.AddMenuButton("[::u]B[::-]ack", false)
back.SetSelectedFunc(func() { back.SetSelectedFunc(
setPage(index - 1) func() {
}) setPage(index - 1)
},
)
} }
addMenuItem(p.name, index) addMenuItem(p.name, index)
@ -278,15 +284,19 @@ func (installer *Installer) configure() error {
if index < len(state.pages)-1 { if index < len(state.pages)-1 {
next := form.AddMenuButton("[::u]N[::-]ext", index == 0) next := form.AddMenuButton("[::u]N[::-]ext", index == 0)
next.SetSelectedFunc(func() { next.SetSelectedFunc(
setPage(index + 1) func() {
}) setPage(index + 1)
},
)
} else { } else {
install := form.AddMenuButton("Install", false) install := form.AddMenuButton("Install", false)
install.SetBackgroundColor(tcell.ColorGreen) install.SetBackgroundColor(tcell.ColorGreen)
install.SetSelectedFunc(func() { install.SetSelectedFunc(
close(done) func() {
}) close(done)
},
)
} }
installer.addPage(p.name, form, index == 0, menu) installer.addPage(p.name, form, index == 0, menu)
@ -362,9 +372,11 @@ func (installer *Installer) apply(conn *Connection) error {
// TODO: progress bar, logs? // TODO: progress bar, logs?
list.AddItem(s, 1, 1, false) list.AddItem(s, 1, 1, false)
_, err = conn.ApplyConfiguration(&machineapi.ApplyConfigurationRequest{ _, err = conn.ApplyConfiguration(
Data: config, &machineapi.ApplyConfigurationRequest{
}) Data: config,
},
)
s.Stop(err == nil) s.Stop(err == nil)
@ -453,19 +465,21 @@ func (installer *Installer) writeTalosconfig(list *tview.Flex, talosconfig *clie
func (installer *Installer) awaitKey(keys ...tcell.Key) { func (installer *Installer) awaitKey(keys ...tcell.Key) {
done := make(chan struct{}) done := make(chan struct{})
installer.app.SetInputCapture(func(e *tcell.EventKey) *tcell.EventKey { installer.app.SetInputCapture(
for _, key := range keys { func(e *tcell.EventKey) *tcell.EventKey {
if e.Key() == key { for _, key := range keys {
if e.Key() == key {
close(done)
}
}
if len(keys) == 0 {
close(done) close(done)
} }
}
if len(keys) == 0 { return e
close(done) },
} )
return e
})
select { select {
case <-done: case <-done:
@ -482,10 +496,12 @@ func (installer *Installer) showModal(title, text string, buttons ...string) int
modal := tview.NewModal(). modal := tview.NewModal().
SetText(text). SetText(text).
AddButtons(buttons). AddButtons(buttons).
SetDoneFunc(func(buttonIndex int, buttonLabel string) { SetDoneFunc(
index = buttonIndex func(buttonIndex int, buttonLabel string) {
close(done) index = buttonIndex
}) close(done)
},
)
installer.addPage(title, modal, true, nil) installer.addPage(title, modal, true, nil)
installer.app.SetFocus(modal) installer.app.SetFocus(modal)
@ -524,8 +540,10 @@ func (installer *Installer) addPage(name string, primitive tview.Primitive, swit
if switchToPage { if switchToPage {
installer.pages.AddAndSwitchToPage(name, frame, true) installer.pages.AddAndSwitchToPage(name, frame, true)
} else { } else {
installer.pages.AddPage(name, installer.pages.AddPage(
frame, true, false) name,
frame, true, false,
)
} }
} else if switchToPage { } else if switchToPage {
installer.pages.SwitchToPage(name) installer.pages.SwitchToPage(name)

View File

@ -32,7 +32,7 @@ type Stream struct {
source Source source Source
options *Options options *Options
ctx context.Context ctx context.Context //nolint:containedctx
} }
// Source is an interface describing the source of a Stream. // Source is an interface describing the source of a Stream.

View File

@ -184,9 +184,11 @@ func upgradeKubeletOnNode(ctx context.Context, cluster UpgradeProvider, options
options.Log(" > %q: waiting for node update", node) options.Log(" > %q: waiting for node update", node)
if err = retry.Constant(3*time.Minute, retry.WithUnits(10*time.Second)).Retry(func() error { if err = retry.Constant(3*time.Minute, retry.WithUnits(10*time.Second)).Retry(
return checkNodeKubeletVersion(ctx, cluster, node, "v"+options.ToVersion) func() error {
}); err != nil { return checkNodeKubeletVersion(ctx, cluster, node, "v"+options.ToVersion)
},
); err != nil {
return err return err
} }
@ -195,7 +197,10 @@ func upgradeKubeletOnNode(ctx context.Context, cluster UpgradeProvider, options
return nil return nil
} }
func upgradeKubeletPatcher(options UpgradeOptions, kubeletSpec resource.Resource) func(config *v1alpha1config.Config) error { func upgradeKubeletPatcher(
options UpgradeOptions,
kubeletSpec resource.Resource,
) func(config *v1alpha1config.Config) error {
return func(config *v1alpha1config.Config) error { return func(config *v1alpha1config.Config) error {
if config.MachineConfig == nil { if config.MachineConfig == nil {
config.MachineConfig = &v1alpha1config.MachineConfig{} config.MachineConfig = &v1alpha1config.MachineConfig{}
@ -206,15 +211,15 @@ func upgradeKubeletPatcher(options UpgradeOptions, kubeletSpec resource.Resource
} }
var ( var (
any *resource.Any anyResource *resource.Any
ok bool ok bool
) )
if any, ok = kubeletSpec.(*resource.Any); !ok { if anyResource, ok = kubeletSpec.(*resource.Any); !ok {
return fmt.Errorf("unexpected resource type") return fmt.Errorf("unexpected resource type")
} }
oldImage := any.Value().(map[string]interface{})["image"].(string) //nolint:errcheck,forcetypeassert oldImage := anyResource.Value().(map[string]interface{})["image"].(string) //nolint:errcheck,forcetypeassert
logUpdate := func(oldImage string) { logUpdate := func(oldImage string) {
parts := strings.Split(oldImage, ":") parts := strings.Split(oldImage, ":")
@ -287,7 +292,13 @@ func checkNodeKubeletVersion(ctx context.Context, cluster UpgradeProvider, nodeT
nodeFound = true nodeFound = true
if node.Status.NodeInfo.KubeletVersion != version { if node.Status.NodeInfo.KubeletVersion != version {
return retry.ExpectedError(fmt.Errorf("node version mismatch: got %q, expected %q", node.Status.NodeInfo.KubeletVersion, version)) return retry.ExpectedError(
fmt.Errorf(
"node version mismatch: got %q, expected %q",
node.Status.NodeInfo.KubeletVersion,
version,
),
)
} }
ready := false ready := false

View File

@ -22,6 +22,7 @@ import (
type Reader struct { type Reader struct {
source *os.File source *os.File
//nolint:containedctx
ctx context.Context ctx context.Context
ctxCancel context.CancelFunc ctxCancel context.CancelFunc

View File

@ -23,7 +23,7 @@ import (
"google.golang.org/grpc/reflection" "google.golang.org/grpc/reflection"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
_ "github.com/talos-systems/talos/pkg/grpc/codec" //nolint:gci // register codec _ "github.com/talos-systems/talos/pkg/grpc/codec" // register codec
grpclog "github.com/talos-systems/talos/pkg/grpc/middleware/log" grpclog "github.com/talos-systems/talos/pkg/grpc/middleware/log"
) )
@ -150,19 +150,32 @@ func NewDefaultOptions(setters ...Option) *Options {
// Recovery is installed as the the first middleware in the chain to handle panics (via defer and recover()) in all subsequent middlewares. // Recovery is installed as the the first middleware in the chain to handle panics (via defer and recover()) in all subsequent middlewares.
recoveryOpt := grpc_recovery.WithRecoveryHandler(recoveryHandler(logger)) recoveryOpt := grpc_recovery.WithRecoveryHandler(recoveryHandler(logger))
opts.UnaryInterceptors = append([]grpc.UnaryServerInterceptor{grpc_recovery.UnaryServerInterceptor(recoveryOpt)}, opts.UnaryInterceptors...) opts.UnaryInterceptors = append(
opts.StreamInterceptors = append([]grpc.StreamServerInterceptor{grpc_recovery.StreamServerInterceptor(recoveryOpt)}, opts.StreamInterceptors...) []grpc.UnaryServerInterceptor{grpc_recovery.UnaryServerInterceptor(recoveryOpt)},
opts.UnaryInterceptors...,
)
opts.StreamInterceptors = append(
[]grpc.StreamServerInterceptor{grpc_recovery.StreamServerInterceptor(recoveryOpt)},
opts.StreamInterceptors...,
)
if logger != nil { if logger != nil {
// Logging is installed as the first middleware (even before recovery middleware) in the chain // Logging is installed as the first middleware (even before recovery middleware) in the chain
// so that request in the form it was received and status sent on the wire is logged (error/success). // so that request in the form it was received and status sent on the wire is logged (error/success).
// It also tracks the whole duration of the request, including other middleware overhead. // It also tracks the whole duration of the request, including other middleware overhead.
logMiddleware := grpclog.NewMiddleware(logger) logMiddleware := grpclog.NewMiddleware(logger)
opts.UnaryInterceptors = append([]grpc.UnaryServerInterceptor{logMiddleware.UnaryInterceptor()}, opts.UnaryInterceptors...) opts.UnaryInterceptors = append(
opts.StreamInterceptors = append([]grpc.StreamServerInterceptor{logMiddleware.StreamInterceptor()}, opts.StreamInterceptors...) []grpc.UnaryServerInterceptor{logMiddleware.UnaryInterceptor()},
opts.UnaryInterceptors...,
)
opts.StreamInterceptors = append(
[]grpc.StreamServerInterceptor{logMiddleware.StreamInterceptor()},
opts.StreamInterceptors...,
)
} }
opts.ServerOptions = append(opts.ServerOptions, opts.ServerOptions = append(
opts.ServerOptions,
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(opts.UnaryInterceptors...)), grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(opts.UnaryInterceptors...)),
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(opts.StreamInterceptors...)), grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(opts.StreamInterceptors...)),
) )

Some files were not shown because too many files have changed in this diff Show More