No actual changes, adapting to use new APIs. Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
133 lines
3.6 KiB
Go
133 lines
3.6 KiB
Go
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
// Package cluster provides functions to access, check and inspect Talos clusters.
|
|
package cluster
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net/netip"
|
|
"sort"
|
|
|
|
"github.com/siderolabs/gen/maps"
|
|
"github.com/siderolabs/gen/xslices"
|
|
"k8s.io/client-go/kubernetes"
|
|
"k8s.io/client-go/rest"
|
|
|
|
k8s "github.com/siderolabs/talos/pkg/kubernetes"
|
|
"github.com/siderolabs/talos/pkg/machinery/client"
|
|
"github.com/siderolabs/talos/pkg/machinery/config/machine"
|
|
)
|
|
|
|
// ClientProvider builds Talos client by endpoint.
|
|
//
|
|
// Client instance should be cached and closed when Close() is called.
|
|
type ClientProvider interface {
|
|
// Client returns Talos client instance for default (if no endpoints are given) or
|
|
// specific endpoint.
|
|
Client(endpoints ...string) (*client.Client, error)
|
|
// Close client connections.
|
|
Close() error
|
|
}
|
|
|
|
// K8sProvider builds Kubernetes client to access Talos cluster.
|
|
type K8sProvider interface {
|
|
Kubeconfig(ctx context.Context) ([]byte, error)
|
|
K8sRestConfig(ctx context.Context) (*rest.Config, error)
|
|
K8sClient(ctx context.Context) (*kubernetes.Clientset, error)
|
|
K8sHelper(ctx context.Context) (*k8s.Client, error)
|
|
K8sClose() error
|
|
}
|
|
|
|
// CrashDumper captures Talos cluster state to the specified writer for debugging.
|
|
type CrashDumper interface {
|
|
CrashDump(ctx context.Context, out io.Writer)
|
|
}
|
|
|
|
// NodeInfo describes a Talos node.
|
|
type NodeInfo struct {
|
|
InternalIP netip.Addr
|
|
IPs []netip.Addr
|
|
}
|
|
|
|
// Info describes the Talos cluster.
|
|
type Info interface {
|
|
// Nodes returns list of all node infos.
|
|
Nodes() []NodeInfo
|
|
// NodesByType return list of node endpoints by type.
|
|
NodesByType(machine.Type) []NodeInfo
|
|
}
|
|
|
|
// Bootstrapper performs Talos cluster bootstrap.
|
|
type Bootstrapper interface {
|
|
Bootstrap(ctx context.Context, out io.Writer) error
|
|
}
|
|
|
|
// IPsToNodeInfos converts list of IPs to a list of NodeInfos.
|
|
func IPsToNodeInfos(ips []string) ([]NodeInfo, error) {
|
|
result := make([]NodeInfo, len(ips))
|
|
|
|
for i, ip := range ips {
|
|
info, err := IPToNodeInfo(ip)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result[i] = *info
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// IPToNodeInfo converts a node internal IP to a NodeInfo.
|
|
func IPToNodeInfo(ip string) (*NodeInfo, error) {
|
|
parsed, err := netip.ParseAddr(ip)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &NodeInfo{
|
|
InternalIP: parsed,
|
|
IPs: []netip.Addr{parsed},
|
|
}, nil
|
|
}
|
|
|
|
// NodesMatch asserts that the provided expected set of nodes match the actual set of nodes.
|
|
//
|
|
// Each expectedNode IPs should have a non-empty intersection with actualNode IPs.
|
|
func NodesMatch(expected, actual []NodeInfo) error {
|
|
actualNodes := xslices.ToMap(actual, func(n NodeInfo) (*NodeInfo, struct{}) { return &n, struct{}{} })
|
|
|
|
for _, expectedNodeInfo := range expected {
|
|
found := false
|
|
|
|
for actualNodeInfo := range actualNodes {
|
|
// expectedNodeInfo.IPs intersection with actualNodeInfo.IPs is not empty
|
|
if len(maps.Intersect(xslices.ToSet(actualNodeInfo.IPs), xslices.ToSet(expectedNodeInfo.IPs))) > 0 {
|
|
delete(actualNodes, actualNodeInfo)
|
|
|
|
found = true
|
|
|
|
break
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
return fmt.Errorf("can't find expected node with IPs %q", expectedNodeInfo.IPs)
|
|
}
|
|
}
|
|
|
|
if len(actualNodes) > 0 {
|
|
unexpectedIPs := xslices.FlatMap(maps.Keys(actualNodes), func(n *NodeInfo) []netip.Addr { return n.IPs })
|
|
|
|
sort.Slice(unexpectedIPs, func(i, j int) bool { return unexpectedIPs[i].Less(unexpectedIPs[j]) })
|
|
|
|
return fmt.Errorf("unexpected nodes with IPs %q", unexpectedIPs)
|
|
}
|
|
|
|
return nil
|
|
}
|