mirror of
https://github.com/siderolabs/talos.git
synced 2025-08-21 06:31:11 +02:00
This PR contains generic simple TCP loadbalancer code, and glue code for firecracker provisioner to use this loadbalancer. K8s control plane is passed through the load balancer, and Talos API is passed only to the init node (for now, as some APIs, including kubeconfig, don't work with non-init node). Signed-off-by: Andrey Smirnov <smirnov.andrey@gmail.com>
136 lines
3.4 KiB
Go
136 lines
3.4 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 check provides set of checks to verify cluster readiness.
|
|
package check
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/talos-systems/talos/cmd/osctl/pkg/client"
|
|
"github.com/talos-systems/talos/internal/pkg/provision"
|
|
"github.com/talos-systems/talos/pkg/config/machine"
|
|
)
|
|
|
|
// ServiceStateAssertion checks whether service reached some specified state.
|
|
//
|
|
//nolint: gocyclo
|
|
func ServiceStateAssertion(ctx context.Context, cluster provision.ClusterAccess, service string, states ...string) error {
|
|
cli, err := cluster.Client()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// perform check against "init" node
|
|
var initNode string
|
|
|
|
for _, node := range cluster.Info().Nodes {
|
|
if node.Type == machine.TypeInit {
|
|
initNode = node.PrivateIP.String()
|
|
break
|
|
}
|
|
}
|
|
|
|
if initNode == "" {
|
|
return fmt.Errorf("init node not discovered")
|
|
}
|
|
|
|
nodeCtx := client.WithNodes(ctx, initNode)
|
|
|
|
servicesInfo, err := cli.ServiceInfo(nodeCtx, service)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
serviceOk := false
|
|
|
|
acceptedStates := map[string]struct{}{}
|
|
for _, state := range states {
|
|
acceptedStates[state] = struct{}{}
|
|
}
|
|
|
|
for _, serviceInfo := range servicesInfo {
|
|
if len(serviceInfo.Service.Events.Events) == 0 {
|
|
return fmt.Errorf("no events recorded yet for service %q", service)
|
|
}
|
|
|
|
lastEvent := serviceInfo.Service.Events.Events[len(serviceInfo.Service.Events.Events)-1]
|
|
if _, ok := acceptedStates[lastEvent.State]; !ok {
|
|
return fmt.Errorf("service %q not in expected state %q: current state [%s] %s", service, states, lastEvent.State, lastEvent.Msg)
|
|
}
|
|
|
|
serviceOk = true
|
|
}
|
|
|
|
if !serviceOk {
|
|
return fmt.Errorf("service %q not found", service)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// ServiceHealthAssertion checks whether service reached some specified state.
|
|
//nolint: gocyclo
|
|
func ServiceHealthAssertion(ctx context.Context, cluster provision.ClusterAccess, service string, setters ...Option) error {
|
|
opts := DefaultOptions()
|
|
|
|
for _, setter := range setters {
|
|
if err := setter(opts); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
cli, err := cluster.Client()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
nodes := make([]string, 0, len(cluster.Info().Nodes))
|
|
|
|
for _, node := range cluster.Info().Nodes {
|
|
if len(opts.Types) > 0 {
|
|
for _, t := range opts.Types {
|
|
if node.Type == t {
|
|
nodes = append(nodes, node.PrivateIP.String())
|
|
}
|
|
}
|
|
|
|
continue
|
|
}
|
|
|
|
nodes = append(nodes, node.PrivateIP.String())
|
|
}
|
|
|
|
count := len(nodes)
|
|
|
|
nodesCtx := client.WithNodes(ctx, nodes...)
|
|
|
|
servicesInfo, err := cli.ServiceInfo(nodesCtx, service)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(servicesInfo) != count {
|
|
return fmt.Errorf("expected a response with %d node(s), got %d", count, len(servicesInfo))
|
|
}
|
|
|
|
for _, serviceInfo := range servicesInfo {
|
|
if len(serviceInfo.Service.Events.Events) == 0 {
|
|
return fmt.Errorf("no events recorded yet for service %q", service)
|
|
}
|
|
|
|
lastEvent := serviceInfo.Service.Events.Events[len(serviceInfo.Service.Events.Events)-1]
|
|
if lastEvent.State != "Running" {
|
|
return fmt.Errorf("service %q not in expected state %q: current state [%s] %s", service, "Running", lastEvent.State, lastEvent.Msg)
|
|
}
|
|
|
|
if !serviceInfo.Service.GetHealth().GetHealthy() {
|
|
return fmt.Errorf("service is not healthy: %s", service)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|