overall: make error handling and error logs a bit more streamlined
This commit is contained in:
parent
b4158a1dc1
commit
9efe980789
@ -426,7 +426,7 @@ func applyCLIOverrides(cfg conf.SimpleConfig) (conf.SimpleConfig, error) {
|
||||
}
|
||||
exposeAPI, err = cliutil.ParsePortExposureSpec(ppViper.GetString("cli.api-port"), k3d.DefaultAPIPort)
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
return cfg, fmt.Errorf("failed to parse API Port spec: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ func ParsePortExposureSpec(exposedPortSpec, internalPort string) (*k3d.ExposureO
|
||||
|
||||
portMapping, err := nat.ParsePortSpec(realPortString)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to parse port spec for Port Exposure '%s': %+v", realPortString, err)
|
||||
return nil, fmt.Errorf("failed to parse port spec for Port Exposure '%s': %+v", realPortString, err)
|
||||
}
|
||||
|
||||
api.Port = portMapping[0].Port // there can be only one due to our regexp
|
||||
@ -112,14 +112,12 @@ func ValidatePortMap(portmap string) (string, error) {
|
||||
func GetFreePort() (int, error) {
|
||||
tcpAddress, err := net.ResolveTCPAddr("tcp", "localhost:0")
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to resolve address")
|
||||
return 0, err
|
||||
return 0, fmt.Errorf("failed to resolve address 'localhost:0': %w", err)
|
||||
}
|
||||
|
||||
tcpListener, err := net.ListenTCP("tcp", tcpAddress)
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create TCP Listener")
|
||||
return 0, err
|
||||
return 0, fmt.Errorf("failed to create tcp listener: %w", err)
|
||||
}
|
||||
defer tcpListener.Close()
|
||||
|
||||
|
@ -98,7 +98,7 @@ func ValidateVolumeMount(runtime runtimes.Runtime, volumeMount string) (string,
|
||||
func verifyNamedVolume(runtime runtimes.Runtime, volumeName string) error {
|
||||
volumeName, err := runtime.GetVolume(volumeName)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("Failed to verify named volume: %w", err)
|
||||
}
|
||||
if volumeName == "" {
|
||||
return fmt.Errorf("Failed to find named volume '%s'", volumeName)
|
||||
|
@ -72,11 +72,11 @@ func ClusterRun(ctx context.Context, runtime k3drt.Runtime, clusterConfig *confi
|
||||
*/
|
||||
_, err := EnsureToolsNode(ctx, runtime, &clusterConfig.Cluster)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to ensure k3d-tools node: %w", err)
|
||||
}
|
||||
envInfo, err := GatherEnvironmentInfo(ctx, runtime, &clusterConfig.Cluster)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to gather environment information used for cluster creation: %w", err)
|
||||
}
|
||||
|
||||
/*
|
||||
@ -155,7 +155,7 @@ func ClusterPrep(ctx context.Context, runtime k3drt.Runtime, clusterConfig *conf
|
||||
}
|
||||
regFromNode, err := RegistryFromNode(regNode)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to translate node to registry spec: %w", err)
|
||||
}
|
||||
*reg = *regFromNode
|
||||
}
|
||||
@ -273,8 +273,7 @@ func ClusterPrepNetwork(ctx context.Context, runtime k3drt.Runtime, cluster *k3d
|
||||
// create cluster network or use an existing one
|
||||
network, networkExists, err := runtime.CreateNetworkIfNotPresent(ctx, &cluster.Network)
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create cluster network")
|
||||
return err
|
||||
return fmt.Errorf("failed to create cluster network: %w", err)
|
||||
}
|
||||
cluster.Network = *network
|
||||
clusterCreateOpts.GlobalLabels[k3d.LabelNetworkID] = network.ID
|
||||
@ -296,8 +295,7 @@ func ClusterPrepImageVolume(ctx context.Context, runtime k3drt.Runtime, cluster
|
||||
*/
|
||||
imageVolumeName := fmt.Sprintf("%s-%s-images", k3d.DefaultObjectNamePrefix, cluster.Name)
|
||||
if err := runtime.CreateVolume(ctx, imageVolumeName, map[string]string{k3d.LabelClusterName: cluster.Name}); err != nil {
|
||||
l.Log().Errorf("Failed to create image volume '%s' for cluster '%s'", imageVolumeName, cluster.Name)
|
||||
return err
|
||||
return fmt.Errorf("failed to create image volume '%s' for cluster '%s': %w", imageVolumeName, cluster.Name, err)
|
||||
}
|
||||
|
||||
clusterCreateOpts.GlobalLabels[k3d.LabelImageVolume] = imageVolumeName
|
||||
@ -400,7 +398,7 @@ ClusterCreatOpts:
|
||||
if cluster.Network.IPAM.Managed {
|
||||
ip, err := GetIP(ctx, runtime, &cluster.Network)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to find free IP in network %s: %w", cluster.Network.Name, err)
|
||||
}
|
||||
cluster.Network.IPAM.IPsUsed = append(cluster.Network.IPAM.IPsUsed, ip) // make sure that we're not reusing the same IP next time
|
||||
node.IP.Static = true
|
||||
@ -427,8 +425,7 @@ ClusterCreatOpts:
|
||||
// create node
|
||||
l.Log().Infof("Creating node '%s'", node.Name)
|
||||
if err := NodeCreate(clusterCreateCtx, runtime, node, k3d.NodeCreateOpts{}); err != nil {
|
||||
l.Log().Errorln("Failed to create node")
|
||||
return err
|
||||
return fmt.Errorf("failed to create node: %w", err)
|
||||
}
|
||||
l.Log().Debugf("Created node '%s'", node.Name)
|
||||
|
||||
@ -458,7 +455,7 @@ ClusterCreatOpts:
|
||||
}
|
||||
|
||||
if err := nodeSetup(cluster.InitNode); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed init node setup: %w", err)
|
||||
}
|
||||
serverCount++
|
||||
|
||||
@ -486,7 +483,7 @@ ClusterCreatOpts:
|
||||
}
|
||||
if node.Role == k3d.ServerRole || node.Role == k3d.AgentRole {
|
||||
if err := nodeSetup(node); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed setup of server/agent node %s: %w", node.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -504,7 +501,7 @@ ClusterCreatOpts:
|
||||
if cluster.ServerLoadBalancer == nil {
|
||||
lbNode, err := LoadbalancerPrepare(ctx, runtime, cluster, &k3d.LoadbalancerCreateOpts{Labels: clusterCreateOpts.GlobalLabels})
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to prepare loadbalancer: %w", err)
|
||||
}
|
||||
cluster.Nodes = append(cluster.Nodes, lbNode) // append lbNode to list of cluster nodes, so it will be considered during rollback
|
||||
}
|
||||
@ -522,7 +519,7 @@ ClusterCreatOpts:
|
||||
// prepare to write config to lb container
|
||||
configyaml, err := yaml.Marshal(cluster.ServerLoadBalancer.Config)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to marshal loadbalancer config: %w", err)
|
||||
}
|
||||
|
||||
writeLbConfigAction := k3d.NodeHook{
|
||||
@ -542,7 +539,6 @@ ClusterCreatOpts:
|
||||
return fmt.Errorf("error creating loadbalancer: %v", err)
|
||||
}
|
||||
l.Log().Debugf("Created loadbalancer '%s'", cluster.ServerLoadBalancer.Node.Name)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -554,7 +550,7 @@ func ClusterDelete(ctx context.Context, runtime k3drt.Runtime, cluster *k3d.Clus
|
||||
l.Log().Infof("Deleting cluster '%s'", cluster.Name)
|
||||
cluster, err := ClusterGet(ctx, runtime, cluster)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to get cluster %s: %w", cluster.Name, err)
|
||||
}
|
||||
l.Log().Debugf("Cluster Details: %+v", cluster)
|
||||
|
||||
@ -656,8 +652,7 @@ func ClusterList(ctx context.Context, runtime k3drt.Runtime) ([]*k3d.Cluster, er
|
||||
l.Log().Traceln("Listing Clusters...")
|
||||
nodes, err := runtime.GetNodesByLabel(ctx, k3d.DefaultRuntimeLabels)
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to get clusters")
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("runtime failed to list nodes: %w", err)
|
||||
}
|
||||
|
||||
l.Log().Debugf("Found %d nodes", len(nodes))
|
||||
@ -804,8 +799,7 @@ func ClusterGet(ctx context.Context, runtime k3drt.Runtime, cluster *k3d.Cluster
|
||||
}
|
||||
|
||||
if err := populateClusterFieldsFromLabels(cluster); err != nil {
|
||||
l.Log().Warnf("Failed to populate cluster fields from node labels")
|
||||
l.Log().Warnln(err)
|
||||
l.Log().Warnf("Failed to populate cluster fields from node labels: %v", err)
|
||||
}
|
||||
|
||||
return cluster, nil
|
||||
@ -943,12 +937,12 @@ func ClusterStart(ctx context.Context, runtime k3drt.Runtime, cluster *k3d.Clust
|
||||
|
||||
// add /etc/hosts and CoreDNS entry for host.k3d.internal, referring to the host system
|
||||
if err := prepInjectHostIP(ctx, runtime, cluster); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to inject host IP: %w", err)
|
||||
}
|
||||
|
||||
// create host records in CoreDNS for external registries
|
||||
if err := prepCoreDNSInjectNetworkMembers(ctx, runtime, cluster); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to patch CoreDNS with network members: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -970,6 +964,8 @@ func ClusterStop(ctx context.Context, runtime k3drt.Runtime, cluster *k3d.Cluste
|
||||
if failed > 0 {
|
||||
return fmt.Errorf("Failed to stop %d nodes: Try to stop them manually", failed)
|
||||
}
|
||||
|
||||
l.Log().Infof("Stopped cluster '%s'", cluster.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1107,7 +1103,7 @@ func ClusterEditChangesetSimple(ctx context.Context, runtime k3drt.Runtime, clus
|
||||
for _, portWithNodeFilters := range changeset.Ports {
|
||||
filteredNodes, err := util.FilterNodesWithSuffix(nodeList, portWithNodeFilters.NodeFilters)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to filter nodes: %w", err)
|
||||
}
|
||||
|
||||
for suffix := range filteredNodes {
|
||||
@ -1132,7 +1128,7 @@ func ClusterEditChangesetSimple(ctx context.Context, runtime k3drt.Runtime, clus
|
||||
// prepare to write config to lb container
|
||||
configyaml, err := yaml.Marshal(lbChangeset.Config)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to marshal loadbalancer config changeset: %w", err)
|
||||
}
|
||||
writeLbConfigAction := k3d.NodeHook{
|
||||
Stage: k3d.LifecycleStagePreStart,
|
||||
|
@ -23,6 +23,7 @@ package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/rancher/k3d/v4/pkg/runtimes"
|
||||
|
||||
@ -34,7 +35,7 @@ func GatherEnvironmentInfo(ctx context.Context, runtime runtimes.Runtime, cluste
|
||||
|
||||
hostIP, err := GetHostIP(ctx, runtime, cluster)
|
||||
if err != nil {
|
||||
return envInfo, err
|
||||
return envInfo, fmt.Errorf("failed to get host IP: %w", err)
|
||||
}
|
||||
|
||||
envInfo.HostGateway = hostIP
|
||||
|
@ -50,7 +50,7 @@ func GetHostIP(ctx context.Context, rtime rt.Runtime, cluster *k3d.Cluster) (net
|
||||
if runtime.GOOS == "linux" {
|
||||
ip, err := rtime.GetHostIP(ctx, cluster.Network.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("runtime failed to get host IP: %w", err)
|
||||
}
|
||||
return ip, nil
|
||||
}
|
||||
@ -60,12 +60,12 @@ func GetHostIP(ctx context.Context, rtime rt.Runtime, cluster *k3d.Cluster) (net
|
||||
|
||||
toolsNode, err := EnsureToolsNode(ctx, rtime, cluster)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to ensure that k3d-tools node is running to get host IP :%w", err)
|
||||
}
|
||||
|
||||
ip, err := resolveHostnameFromInside(ctx, rtime, toolsNode, "host.docker.internal")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to resolve 'host.docker.internal' from inside the k3d-tools node: %w", err)
|
||||
}
|
||||
return ip, nil
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
l "github.com/rancher/k3d/v4/pkg/logger"
|
||||
k3drt "github.com/rancher/k3d/v4/pkg/runtimes"
|
||||
@ -30,11 +31,12 @@ import (
|
||||
"inet.af/netaddr"
|
||||
)
|
||||
|
||||
// GetIP checks a given network for a free IP and returns it, if possible
|
||||
func GetIP(ctx context.Context, runtime k3drt.Runtime, network *k3d.ClusterNetwork) (netaddr.IP, error) {
|
||||
|
||||
network, err := runtime.GetNetwork(ctx, network)
|
||||
if err != nil {
|
||||
return netaddr.IP{}, err
|
||||
return netaddr.IP{}, fmt.Errorf("runtime failed to get network '%s': %w", network.Name, err)
|
||||
}
|
||||
|
||||
var ipsetbuilder netaddr.IPSetBuilder
|
||||
|
@ -53,14 +53,14 @@ func KubeconfigGetWrite(ctx context.Context, runtime runtimes.Runtime, cluster *
|
||||
// get kubeconfig from cluster node
|
||||
kubeconfig, err := KubeconfigGet(ctx, runtime, cluster)
|
||||
if err != nil {
|
||||
return output, err
|
||||
return output, fmt.Errorf("failed to get kubeconfig for cluster '%s': %w", cluster.Name, err)
|
||||
}
|
||||
|
||||
// empty output parameter = write to default
|
||||
if output == "" {
|
||||
output, err = KubeconfigGetDefaultPath()
|
||||
if err != nil {
|
||||
return output, err
|
||||
return output, fmt.Errorf("failed to get default kubeconfig path: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,15 +82,13 @@ func KubeconfigGetWrite(ctx context.Context, runtime runtimes.Runtime, cluster *
|
||||
|
||||
// create directory path
|
||||
if err := os.MkdirAll(filepath.Dir(output), 0755); err != nil {
|
||||
l.Log().Errorf("Failed to create output directory '%s'", filepath.Dir(output))
|
||||
return output, err
|
||||
return output, fmt.Errorf("failed to create output directory '%s': %w", filepath.Dir(output), err)
|
||||
}
|
||||
|
||||
// try create output file
|
||||
f, err := os.Create(output)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to create output file '%s'", output)
|
||||
return output, err
|
||||
return output, fmt.Errorf("failed to create output file '%s': %w", output, err)
|
||||
}
|
||||
f.Close()
|
||||
|
||||
@ -98,8 +96,7 @@ func KubeconfigGetWrite(ctx context.Context, runtime runtimes.Runtime, cluster *
|
||||
firstRun = false
|
||||
continue
|
||||
}
|
||||
l.Log().Errorf("Failed to open output file '%s' or it's not a KubeConfig", output)
|
||||
return output, err
|
||||
return output, fmt.Errorf("failed to open output file '%s' or it's not a kubeconfig: %w", output, err)
|
||||
}
|
||||
break
|
||||
}
|
||||
@ -117,11 +114,10 @@ func KubeconfigGet(ctx context.Context, runtime runtimes.Runtime, cluster *k3d.C
|
||||
// TODO: getKubeconfig: we should make sure, that the server node we're trying to fetch from is actually running
|
||||
serverNodes, err := runtime.GetNodesByLabel(ctx, map[string]string{k3d.LabelClusterName: cluster.Name, k3d.LabelRole: string(k3d.ServerRole)})
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to get server nodes")
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("runtime failed to get server nodes for cluster '%s': %w", cluster.Name, err)
|
||||
}
|
||||
if len(serverNodes) == 0 {
|
||||
return nil, fmt.Errorf("Didn't find any server node")
|
||||
return nil, fmt.Errorf("didn't find any server node for cluster '%s'", cluster.Name)
|
||||
}
|
||||
|
||||
// prefer a server node, which actually has the port exposed
|
||||
@ -147,15 +143,13 @@ func KubeconfigGet(ctx context.Context, runtime runtimes.Runtime, cluster *k3d.C
|
||||
// get the kubeconfig from the first server node
|
||||
reader, err := runtime.GetKubeconfig(ctx, chosenServer)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to get kubeconfig from node '%s'", chosenServer.Name)
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("runtime failed to pull kubeconfig from node '%s': %w", chosenServer.Name, err)
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
readBytes, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
l.Log().Errorln("Couldn't read kubeconfig file")
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to read kubeconfig file: %w", err)
|
||||
}
|
||||
|
||||
// drop the first 512 bytes which contain file metadata/control characters
|
||||
@ -167,8 +161,7 @@ func KubeconfigGet(ctx context.Context, runtime runtimes.Runtime, cluster *k3d.C
|
||||
*/
|
||||
kc, err := clientcmd.Load(trimBytes)
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to parse the KubeConfig")
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to parse kubeconfig: %w", err)
|
||||
}
|
||||
|
||||
// update the server URL
|
||||
@ -212,22 +205,19 @@ func KubeconfigWriteToPath(ctx context.Context, kubeconfig *clientcmdapi.Config,
|
||||
} else {
|
||||
output, err = os.Create(path)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to create file '%s'", path)
|
||||
return err
|
||||
return fmt.Errorf("failed to create file '%s': %w", path, err)
|
||||
}
|
||||
defer output.Close()
|
||||
}
|
||||
|
||||
kubeconfigBytes, err := clientcmd.Write(*kubeconfig)
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to write KubeConfig")
|
||||
return err
|
||||
return fmt.Errorf("failed to write kubeconfig: %w", err)
|
||||
}
|
||||
|
||||
_, err = output.Write(kubeconfigBytes)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to write to file '%s'", output.Name())
|
||||
return err
|
||||
return fmt.Errorf("failed to write file '%s': %w", output.Name(), err)
|
||||
}
|
||||
|
||||
l.Log().Debugf("Wrote kubeconfig to '%s'", output.Name())
|
||||
@ -285,14 +275,12 @@ func KubeconfigMerge(ctx context.Context, newKubeConfig *clientcmdapi.Config, ex
|
||||
func KubeconfigWrite(ctx context.Context, kubeconfig *clientcmdapi.Config, path string) error {
|
||||
tempPath := fmt.Sprintf("%s.k3d_%s", path, time.Now().Format("20060102_150405.000000"))
|
||||
if err := clientcmd.WriteToFile(*kubeconfig, tempPath); err != nil {
|
||||
l.Log().Errorf("Failed to write merged kubeconfig to temporary file '%s'", tempPath)
|
||||
return err
|
||||
return fmt.Errorf("failed to write merged kubeconfig to temporary file '%s': %w", tempPath, err)
|
||||
}
|
||||
|
||||
// Move temporary file over existing KubeConfig
|
||||
if err := os.Rename(tempPath, path); err != nil {
|
||||
l.Log().Errorf("Failed to overwrite existing KubeConfig '%s' with new KubeConfig '%s'", path, tempPath)
|
||||
return err
|
||||
return fmt.Errorf("failed to overwrite existing KubeConfig '%s' with new kubeconfig '%s': %w", path, tempPath, err)
|
||||
}
|
||||
|
||||
l.Log().Debugf("Wrote kubeconfig to '%s'", path)
|
||||
@ -304,7 +292,7 @@ func KubeconfigWrite(ctx context.Context, kubeconfig *clientcmdapi.Config, path
|
||||
func KubeconfigGetDefaultFile() (*clientcmdapi.Config, error) {
|
||||
path, err := KubeconfigGetDefaultPath()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to get default kubeconfig path: %w", err)
|
||||
}
|
||||
l.Log().Debugf("Using default kubeconfig '%s'", path)
|
||||
return clientcmd.LoadFromFile(path)
|
||||
@ -314,7 +302,7 @@ func KubeconfigGetDefaultFile() (*clientcmdapi.Config, error) {
|
||||
func KubeconfigGetDefaultPath() (string, error) {
|
||||
defaultKubeConfigLoadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
|
||||
if len(defaultKubeConfigLoadingRules.GetLoadingPrecedence()) > 1 {
|
||||
return "", fmt.Errorf("Multiple kubeconfigs specified via KUBECONFIG env var: Please reduce to one entry, unset KUBECONFIG or explicitly choose an output")
|
||||
return "", fmt.Errorf("multiple kubeconfigs specified via KUBECONFIG env var: Please reduce to one entry, unset KUBECONFIG or explicitly choose an output")
|
||||
}
|
||||
return defaultKubeConfigLoadingRules.GetDefaultFilename(), nil
|
||||
}
|
||||
@ -323,11 +311,11 @@ func KubeconfigGetDefaultPath() (string, error) {
|
||||
func KubeconfigRemoveClusterFromDefaultConfig(ctx context.Context, cluster *k3d.Cluster) error {
|
||||
defaultKubeConfigPath, err := KubeconfigGetDefaultPath()
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to get default kubeconfig path: %w", err)
|
||||
}
|
||||
kubeconfig, err := KubeconfigGetDefaultFile()
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to get default kubeconfig file: %w", err)
|
||||
}
|
||||
kubeconfig = KubeconfigRemoveCluster(ctx, cluster, kubeconfig)
|
||||
return KubeconfigWrite(ctx, kubeconfig, defaultKubeConfigPath)
|
||||
|
@ -51,8 +51,7 @@ func UpdateLoadbalancerConfig(ctx context.Context, runtime runtimes.Runtime, clu
|
||||
// update cluster details to ensure that we have the latest node list
|
||||
cluster, err = ClusterGet(ctx, runtime, cluster)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to update details for cluster '%s'", cluster.Name)
|
||||
return err
|
||||
return fmt.Errorf("failed to update details for cluster '%s': %w", cluster.Name, err)
|
||||
}
|
||||
|
||||
currentConfig, err := GetLoadbalancerConfig(ctx, runtime, cluster)
|
||||
@ -120,7 +119,7 @@ func GetLoadbalancerConfig(ctx context.Context, runtime runtimes.Runtime, cluste
|
||||
var err error
|
||||
cluster.ServerLoadBalancer.Node, err = NodeGet(ctx, runtime, node)
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
return cfg, fmt.Errorf("failed to get loadbalancer node '%s': %w", node.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -128,13 +127,13 @@ func GetLoadbalancerConfig(ctx context.Context, runtime runtimes.Runtime, cluste
|
||||
|
||||
reader, err := runtime.ReadFromNode(ctx, types.DefaultLoadbalancerConfigPath, cluster.ServerLoadBalancer.Node)
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
return cfg, fmt.Errorf("runtime failed to read loadbalancer config '%s' from node '%s': %w", types.DefaultLoadbalancerConfigPath, cluster.ServerLoadBalancer.Node.Name, err)
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
file, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
return cfg, err
|
||||
return cfg, fmt.Errorf("failed to read loadbalancer config file: %w", err)
|
||||
}
|
||||
|
||||
file = bytes.Trim(file[512:], "\x00") // trim control characters, etc.
|
||||
@ -213,7 +212,7 @@ func loadbalancerAddPortConfigs(loadbalancer *k3d.Loadbalancer, portmapping nat.
|
||||
nodenames := []string{}
|
||||
for _, node := range targetNodes {
|
||||
if node.Role == k3d.LoadBalancerRole {
|
||||
return fmt.Errorf("error adding port config to loadbalancer: cannot add port config referencing the loadbalancer itself (loop)")
|
||||
return fmt.Errorf("cannot add port config referencing the loadbalancer itself (loop)")
|
||||
}
|
||||
nodenames = append(nodenames, node.Name)
|
||||
}
|
||||
|
@ -56,8 +56,7 @@ func NodeAddToCluster(ctx context.Context, runtime runtimes.Runtime, node *k3d.N
|
||||
targetClusterName := cluster.Name
|
||||
cluster, err := ClusterGet(ctx, runtime, cluster)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to find specified cluster '%s'", targetClusterName)
|
||||
return err
|
||||
return fmt.Errorf("Failed to find specified cluster '%s': %w", targetClusterName, err)
|
||||
}
|
||||
|
||||
// network
|
||||
@ -159,8 +158,7 @@ func NodeAddToCluster(ctx context.Context, runtime runtimes.Runtime, node *k3d.N
|
||||
|
||||
// merge node config of new node into existing node config
|
||||
if err := mergo.MergeWithOverwrite(srcNode, *node); err != nil {
|
||||
l.Log().Errorln("Failed to merge new node config into existing node config")
|
||||
return err
|
||||
return fmt.Errorf("failed to merge new node config into existing node config: %w", err)
|
||||
}
|
||||
|
||||
node = srcNode
|
||||
@ -203,7 +201,7 @@ func NodeAddToCluster(ctx context.Context, runtime runtimes.Runtime, node *k3d.N
|
||||
node.State.Status = ""
|
||||
|
||||
if err := NodeRun(ctx, runtime, node, createNodeOpts); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to run node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
// if it's a server node, then update the loadbalancer configuration
|
||||
@ -280,7 +278,7 @@ func NodeCreateMulti(ctx context.Context, runtime runtimes.Runtime, nodes []*k3d
|
||||
// NodeRun creates and starts a node
|
||||
func NodeRun(ctx context.Context, runtime runtimes.Runtime, node *k3d.Node, nodeCreateOpts k3d.NodeCreateOpts) error {
|
||||
if err := NodeCreate(ctx, runtime, node, nodeCreateOpts); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to create node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
if err := NodeStart(ctx, runtime, node, &k3d.NodeStartOpts{
|
||||
@ -289,7 +287,7 @@ func NodeRun(ctx context.Context, runtime runtimes.Runtime, node *k3d.Node, node
|
||||
NodeHooks: nodeCreateOpts.NodeHooks,
|
||||
EnvironmentInfo: nodeCreateOpts.EnvironmentInfo,
|
||||
}); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to start node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -305,7 +303,7 @@ func NodeStart(ctx context.Context, runtime runtimes.Runtime, node *k3d.Node, no
|
||||
}
|
||||
|
||||
if err := enableFixes(ctx, runtime, node, nodeStartOpts); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to enable k3d fixes: %w", err)
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
@ -325,8 +323,7 @@ func NodeStart(ctx context.Context, runtime runtimes.Runtime, node *k3d.Node, no
|
||||
l.Log().Tracef("Starting node '%s'", node.Name)
|
||||
|
||||
if err := runtime.StartNode(ctx, node); err != nil {
|
||||
l.Log().Errorf("Failed to start node '%s'", node.Name)
|
||||
return err
|
||||
return fmt.Errorf("runtime failed to start node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
if node.State.Started != "" {
|
||||
@ -453,11 +450,11 @@ func NodeCreate(ctx context.Context, runtime runtimes.Runtime, node *k3d.Node, c
|
||||
// specify options depending on node role
|
||||
if node.Role == k3d.AgentRole { // TODO: check here AND in CLI or only here?
|
||||
if err := patchAgentSpec(node); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to patch agent spec on node %s: %w", node.Name, err)
|
||||
}
|
||||
} else if node.Role == k3d.ServerRole {
|
||||
if err := patchServerSpec(node, runtime); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to patch server spec on node %s: %w", node.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -496,7 +493,7 @@ func NodeCreate(ctx context.Context, runtime runtimes.Runtime, node *k3d.Node, c
|
||||
* CREATION
|
||||
*/
|
||||
if err := runtime.CreateNode(ctx, node); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("runtime failed to create node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -524,15 +521,14 @@ func NodeDelete(ctx context.Context, runtime runtimes.Runtime, node *k3d.Node, o
|
||||
if !opts.SkipLBUpdate && (node.Role == k3d.ServerRole || node.Role == k3d.AgentRole) {
|
||||
cluster, err := ClusterGet(ctx, runtime, &k3d.Cluster{Name: node.RuntimeLabels[k3d.LabelClusterName]})
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to find cluster for node '%s'", node.Name)
|
||||
return err
|
||||
return fmt.Errorf("failed fo find cluster for node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
// if it's a server node, then update the loadbalancer configuration
|
||||
if node.Role == k3d.ServerRole {
|
||||
if err := UpdateLoadbalancerConfig(ctx, runtime, cluster); err != nil {
|
||||
if !errors.Is(err, ErrLBConfigHostNotFound) {
|
||||
return fmt.Errorf("Failed to update cluster loadbalancer: %w", err)
|
||||
return fmt.Errorf("failed to update cluster loadbalancer: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -583,8 +579,7 @@ func patchServerSpec(node *k3d.Node, runtime runtimes.Runtime) error {
|
||||
func NodeList(ctx context.Context, runtime runtimes.Runtime) ([]*k3d.Node, error) {
|
||||
nodes, err := runtime.GetNodesByLabel(ctx, k3d.DefaultRuntimeLabels)
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to get nodes")
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to list nodes: %w", err)
|
||||
}
|
||||
|
||||
return nodes, nil
|
||||
@ -595,8 +590,7 @@ func NodeGet(ctx context.Context, runtime runtimes.Runtime, node *k3d.Node) (*k3
|
||||
// get node
|
||||
node, err := runtime.GetNode(ctx, node)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to get node '%s'", node.Name)
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to get node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
return node, nil
|
||||
@ -706,7 +700,7 @@ func NodeEdit(ctx context.Context, runtime runtimes.Runtime, existingNode, chang
|
||||
|
||||
result, err := CopyNode(ctx, existingNode, CopyNodeOpts{keepState: false})
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to copy node %s: %w", existingNode.Name, err)
|
||||
}
|
||||
|
||||
/*
|
||||
@ -751,7 +745,7 @@ func NodeEdit(ctx context.Context, runtime runtimes.Runtime, existingNode, chang
|
||||
// prepare to write config to lb container
|
||||
configyaml, err := yaml.Marshal(lbConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to marshal loadbalancer config: %w", err)
|
||||
}
|
||||
|
||||
writeLbConfigAction := k3d.NodeHook{
|
||||
@ -778,7 +772,7 @@ func NodeReplace(ctx context.Context, runtime runtimes.Runtime, old, new *k3d.No
|
||||
oldNameOriginal := old.Name
|
||||
l.Log().Infof("Renaming existing node %s to %s...", old.Name, oldNameTemp)
|
||||
if err := runtime.RenameNode(ctx, old, oldNameTemp); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("runtime failed to rename node '%s': %w", old.Name, err)
|
||||
}
|
||||
old.Name = oldNameTemp
|
||||
|
||||
@ -794,7 +788,7 @@ func NodeReplace(ctx context.Context, runtime runtimes.Runtime, old, new *k3d.No
|
||||
// stop existing/old node
|
||||
l.Log().Infof("Stopping existing node %s...", old.Name)
|
||||
if err := runtime.StopNode(ctx, old); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("runtime failed to stop node '%s': %w", old.Name, err)
|
||||
}
|
||||
|
||||
// start new node
|
||||
@ -816,7 +810,7 @@ func NodeReplace(ctx context.Context, runtime runtimes.Runtime, old, new *k3d.No
|
||||
// cleanup: delete old node
|
||||
l.Log().Infof("Deleting old node %s...", old.Name)
|
||||
if err := NodeDelete(ctx, runtime, old, k3d.NodeDeleteOpts{SkipLBUpdate: true}); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to delete old node '%s': %w", old.Name, err)
|
||||
}
|
||||
|
||||
// done
|
||||
@ -831,7 +825,7 @@ func CopyNode(ctx context.Context, src *k3d.Node, opts CopyNodeOpts) (*k3d.Node,
|
||||
|
||||
targetCopy, err := copystruct.Copy(src)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to copy node struct: %w", err)
|
||||
}
|
||||
|
||||
result := targetCopy.(*k3d.Node)
|
||||
@ -841,5 +835,5 @@ func CopyNode(ctx context.Context, src *k3d.Node, opts CopyNodeOpts) (*k3d.Node,
|
||||
result.State = k3d.NodeState{}
|
||||
}
|
||||
|
||||
return result, err
|
||||
return result, nil
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ func TransformPorts(ctx context.Context, runtime runtimes.Runtime, cluster *k3d.
|
||||
}
|
||||
for _, pm := range portmappings {
|
||||
if err := loadbalancerAddPortConfigs(cluster.ServerLoadBalancer, pm, nodes); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("error adding port config to loadbalancer: %w", err)
|
||||
}
|
||||
}
|
||||
} else if suffix == "direct" {
|
||||
|
@ -47,7 +47,7 @@ func RegistryRun(ctx context.Context, runtime runtimes.Runtime, reg *k3d.Registr
|
||||
return nil, fmt.Errorf("Failed to start registry: %+v", err)
|
||||
}
|
||||
|
||||
return regNode, err
|
||||
return regNode, nil
|
||||
}
|
||||
|
||||
// RegistryCreate creates a registry node
|
||||
@ -99,8 +99,7 @@ func RegistryCreate(ctx context.Context, runtime runtimes.Runtime, reg *k3d.Regi
|
||||
// create the registry node
|
||||
l.Log().Infof("Creating node '%s'", registryNode.Name)
|
||||
if err := NodeCreate(ctx, runtime, registryNode, k3d.NodeCreateOpts{}); err != nil {
|
||||
l.Log().Errorln("Failed to create registry node")
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to create registry node '%s': %w", registryNode.Name, err)
|
||||
}
|
||||
|
||||
l.Log().Infof("Successfully created registry '%s'", registryNode.Name)
|
||||
@ -115,8 +114,7 @@ func RegistryConnectClusters(ctx context.Context, runtime runtimes.Runtime, regi
|
||||
// find registry node
|
||||
registryNode, err := NodeGet(ctx, runtime, registryNode)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to find registry node '%s'", registryNode.Name)
|
||||
return err
|
||||
return fmt.Errorf("Failed to find registry node '%s': %w", registryNode.Name, err)
|
||||
}
|
||||
|
||||
// get cluster details and connect
|
||||
@ -148,8 +146,7 @@ func RegistryConnectNetworks(ctx context.Context, runtime runtimes.Runtime, regi
|
||||
// find registry node
|
||||
registryNode, err := NodeGet(ctx, runtime, registryNode)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to find registry node '%s'", registryNode.Name)
|
||||
return err
|
||||
return fmt.Errorf("Failed to find registry node '%s': %w", registryNode.Name, err)
|
||||
}
|
||||
|
||||
// get cluster details and connect
|
||||
@ -317,7 +314,7 @@ func RegistryGenerateLocalRegistryHostingConfigMapYAML(ctx context.Context, runt
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to marshal LocalRegistryHosting configmap data: %w", err)
|
||||
}
|
||||
|
||||
cm := configmap{
|
||||
@ -334,7 +331,7 @@ func RegistryGenerateLocalRegistryHostingConfigMapYAML(ctx context.Context, runt
|
||||
|
||||
cmYaml, err := yaml.Marshal(cm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to marshal LocalRegistryHosting configmap: %w", err)
|
||||
}
|
||||
|
||||
l.Log().Tracef("LocalRegistryHostingConfigMapYaml: %s", string(cmYaml))
|
||||
@ -345,7 +342,7 @@ func RegistryGenerateLocalRegistryHostingConfigMapYAML(ctx context.Context, runt
|
||||
// RegistryMergeConfig merges a source registry config into an existing dest registry cofnig
|
||||
func RegistryMergeConfig(ctx context.Context, dest, src *k3s.Registry) error {
|
||||
if err := mergo.MergeWithOverwrite(dest, src); err != nil {
|
||||
return fmt.Errorf("Failed to merge registry configs: %+v", err)
|
||||
return fmt.Errorf("failed to merge registry configs: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ import (
|
||||
func ImageImportIntoClusterMulti(ctx context.Context, runtime runtimes.Runtime, images []string, cluster *k3d.Cluster, opts k3d.ImageImportOpts) error {
|
||||
imagesFromRuntime, imagesFromTar, err := findImages(ctx, runtime, images)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to find images: %w", err)
|
||||
}
|
||||
|
||||
// no images found to load -> exit early
|
||||
@ -52,7 +52,7 @@ func ImageImportIntoClusterMulti(ctx context.Context, runtime runtimes.Runtime,
|
||||
// create tools node to export images
|
||||
toolsNode, err := EnsureToolsNode(ctx, runtime, cluster)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to ensure that tools node is running: %w", err)
|
||||
}
|
||||
|
||||
/* TODO:
|
||||
@ -70,8 +70,7 @@ func ImageImportIntoClusterMulti(ctx context.Context, runtime runtimes.Runtime,
|
||||
l.Log().Infof("Saving %d image(s) from runtime...", len(imagesFromRuntime))
|
||||
tarName := fmt.Sprintf("%s/k3d-%s-images-%s.tar", k3d.DefaultImageVolumeMountPath, cluster.Name, time.Now().Format("20060102150405"))
|
||||
if err := runtime.ExecInNode(ctx, toolsNode, append([]string{"./k3d-tools", "save-image", "-d", tarName}, imagesFromRuntime...)); err != nil {
|
||||
l.Log().Errorf("Failed to save image(s) in tools container for cluster '%s'", cluster.Name)
|
||||
return err
|
||||
return fmt.Errorf("failed to save image(s) in tools container for cluster '%s': %w", cluster.Name, err)
|
||||
}
|
||||
importTarNames = append(importTarNames, tarName)
|
||||
}
|
||||
@ -82,7 +81,7 @@ func ImageImportIntoClusterMulti(ctx context.Context, runtime runtimes.Runtime,
|
||||
for _, file := range imagesFromTar {
|
||||
tarName := fmt.Sprintf("%s/k3d-%s-images-%s-file-%s", k3d.DefaultImageVolumeMountPath, cluster.Name, time.Now().Format("20060102150405"), path.Base(file))
|
||||
if err := runtime.CopyToNode(ctx, file, tarName, toolsNode); err != nil {
|
||||
l.Log().Errorf("Failed to copy image tar '%s' to tools node! Error below:\n%+v", file, err)
|
||||
l.Log().Errorf("failed to copy image tar '%s' to tools node! Error below:\n%+v", file, err)
|
||||
continue
|
||||
}
|
||||
importTarNames = append(importTarNames, tarName)
|
||||
@ -100,8 +99,7 @@ func ImageImportIntoClusterMulti(ctx context.Context, runtime runtimes.Runtime,
|
||||
go func(node *k3d.Node, wg *sync.WaitGroup, tarPath string) {
|
||||
l.Log().Infof("Importing images from tarball '%s' into node '%s'...", tarPath, node.Name)
|
||||
if err := runtime.ExecInNode(ctx, node, []string{"ctr", "image", "import", tarPath}); err != nil {
|
||||
l.Log().Errorf("Failed to import images in node '%s'", node.Name)
|
||||
l.Log().Errorln(err)
|
||||
l.Log().Errorf("failed to import images in node '%s': %v", node.Name, err)
|
||||
}
|
||||
wg.Done()
|
||||
}(node, &importWaitgroup, tarName)
|
||||
@ -114,8 +112,7 @@ func ImageImportIntoClusterMulti(ctx context.Context, runtime runtimes.Runtime,
|
||||
if !opts.KeepTar && len(importTarNames) > 0 {
|
||||
l.Log().Infoln("Removing the tarball(s) from image volume...")
|
||||
if err := runtime.ExecInNode(ctx, toolsNode, []string{"rm", "-f", strings.Join(importTarNames, " ")}); err != nil {
|
||||
l.Log().Errorf("Failed to delete one or more tarballs from '%+v'", importTarNames)
|
||||
l.Log().Errorln(err)
|
||||
l.Log().Errorf("failed to delete one or more tarballs from '%+v': %v", importTarNames, err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,7 +120,7 @@ func ImageImportIntoClusterMulti(ctx context.Context, runtime runtimes.Runtime,
|
||||
if !opts.KeepToolsNode {
|
||||
l.Log().Infoln("Removing k3d-tools node...")
|
||||
if err := runtime.DeleteNode(ctx, toolsNode); err != nil {
|
||||
l.Log().Errorf("Failed to delete tools node '%s': Try to delete it manually", toolsNode.Name)
|
||||
l.Log().Errorf("failed to delete tools node '%s' (try to delete it manually): %v", toolsNode.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,8 +137,7 @@ type runtimeImageGetter interface {
|
||||
func findImages(ctx context.Context, runtime runtimeImageGetter, requestedImages []string) (imagesFromRuntime, imagesFromTar []string, err error) {
|
||||
runtimeImages, err := runtime.GetImages(ctx)
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to fetch list of existing images from runtime")
|
||||
return nil, nil, err
|
||||
return nil, nil, fmt.Errorf("failed to fetch list of existing images from runtime: %w", err)
|
||||
}
|
||||
|
||||
for _, requestedImage := range requestedImages {
|
||||
@ -160,7 +156,7 @@ func findImages(ctx context.Context, runtime runtimeImageGetter, requestedImages
|
||||
|
||||
l.Log().Warnf("Image '%s' is not a file and couldn't be found in the container runtime", requestedImage)
|
||||
}
|
||||
return imagesFromRuntime, imagesFromTar, err
|
||||
return imagesFromRuntime, imagesFromTar, nil
|
||||
}
|
||||
|
||||
func findRuntimeImage(requestedImage string, runtimeImages []string) (string, bool) {
|
||||
@ -253,8 +249,7 @@ func runToolsNode(ctx context.Context, runtime runtimes.Runtime, cluster *k3d.Cl
|
||||
}
|
||||
node.RuntimeLabels[k3d.LabelClusterName] = cluster.Name
|
||||
if err := NodeRun(ctx, runtime, node, k3d.NodeCreateOpts{}); err != nil {
|
||||
l.Log().Errorf("Failed to create tools container for cluster '%s'", cluster.Name)
|
||||
return node, err
|
||||
return node, fmt.Errorf("failed to run k3d-tools node for cluster '%s': %w", cluster.Name, err)
|
||||
}
|
||||
|
||||
return node, nil
|
||||
@ -265,12 +260,11 @@ func EnsureToolsNode(ctx context.Context, runtime runtimes.Runtime, cluster *k3d
|
||||
|
||||
cluster, err = ClusterGet(ctx, runtime, cluster)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to find the specified cluster")
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to retrieve cluster '%s': %w", cluster.Name, err)
|
||||
}
|
||||
|
||||
if cluster.Network.Name == "" {
|
||||
return nil, fmt.Errorf("Failed to get network for cluster '%s'", cluster.Name)
|
||||
return nil, fmt.Errorf("failed to get network for cluster '%s'", cluster.Name)
|
||||
}
|
||||
|
||||
var imageVolume string
|
||||
|
@ -73,13 +73,11 @@ func FromViper(config *viper.Viper) (types.Config, error) {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to parse config '%s': %w'", config.ConfigFileUsed(), err)
|
||||
}
|
||||
|
||||
if err := config.Unmarshal(&cfg); err != nil {
|
||||
l.Log().Errorln("Failed to unmarshal File config")
|
||||
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to unmarshal config file '%s': %w", config.ConfigFileUsed(), err)
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
|
@ -73,7 +73,7 @@ func ValidateSchema(content map[string]interface{}, schemaJSON []byte) error {
|
||||
|
||||
result, err := gojsonschema.Validate(schemaLoader, configLoader)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to validate config: %w", err)
|
||||
}
|
||||
|
||||
l.Log().Debugf("JSON Schema Validation Result: %+v", result)
|
||||
|
@ -23,6 +23,8 @@ THE SOFTWARE.
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/imdario/mergo"
|
||||
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||
l "github.com/rancher/k3d/v4/pkg/logger"
|
||||
@ -33,9 +35,8 @@ func MergeSimple(dest, src conf.SimpleConfig) (*conf.SimpleConfig, error) {
|
||||
l.Log().Debugf("Merging %+v into %+v", src, dest)
|
||||
|
||||
if err := mergo.Merge(&dest, src); err != nil {
|
||||
l.Log().Errorln("Failed to merge config")
|
||||
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to merge configs: %w", err)
|
||||
}
|
||||
|
||||
return &dest, nil
|
||||
|
@ -167,7 +167,7 @@ func TransformSimpleToClusterConfig(ctx context.Context, runtime runtimes.Runtim
|
||||
for _, volumeWithNodeFilters := range simpleConfig.Volumes {
|
||||
nodes, err := util.FilterNodes(nodeList, volumeWithNodeFilters.NodeFilters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to filter nodes for volume mapping '%s': %w", volumeWithNodeFilters.Volume, err)
|
||||
}
|
||||
|
||||
for _, node := range nodes {
|
||||
@ -177,18 +177,18 @@ func TransformSimpleToClusterConfig(ctx context.Context, runtime runtimes.Runtim
|
||||
|
||||
// -> PORTS
|
||||
if err := client.TransformPorts(ctx, runtime, &newCluster, simpleConfig.Ports); err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to transform ports: %w", err)
|
||||
}
|
||||
|
||||
// -> K3S NODE LABELS
|
||||
for _, k3sNodeLabelWithNodeFilters := range simpleConfig.Options.K3sOptions.NodeLabels {
|
||||
if len(k3sNodeLabelWithNodeFilters.NodeFilters) == 0 && nodeCount > 1 {
|
||||
return nil, fmt.Errorf("K3sNodeLabelmapping '%s' lacks a node filter, but there's more than one node", k3sNodeLabelWithNodeFilters.Label)
|
||||
return nil, fmt.Errorf("k3s node label mapping '%s' lacks a node filter, but there's more than one node", k3sNodeLabelWithNodeFilters.Label)
|
||||
}
|
||||
|
||||
nodes, err := util.FilterNodes(nodeList, k3sNodeLabelWithNodeFilters.NodeFilters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to filter nodes for k3s node label mapping '%s': %w", k3sNodeLabelWithNodeFilters.Label, err)
|
||||
}
|
||||
|
||||
for _, node := range nodes {
|
||||
@ -209,7 +209,7 @@ func TransformSimpleToClusterConfig(ctx context.Context, runtime runtimes.Runtim
|
||||
|
||||
nodes, err := util.FilterNodes(nodeList, runtimeLabelWithNodeFilters.NodeFilters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to filter nodes for runtime label mapping '%s': %w", runtimeLabelWithNodeFilters.Label, err)
|
||||
}
|
||||
|
||||
for _, node := range nodes {
|
||||
@ -232,7 +232,7 @@ func TransformSimpleToClusterConfig(ctx context.Context, runtime runtimes.Runtim
|
||||
|
||||
nodes, err := util.FilterNodes(nodeList, envVarWithNodeFilters.NodeFilters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to filter nodes for environment variable config '%s': %w", envVarWithNodeFilters.EnvVar, err)
|
||||
}
|
||||
|
||||
for _, node := range nodes {
|
||||
@ -248,7 +248,7 @@ func TransformSimpleToClusterConfig(ctx context.Context, runtime runtimes.Runtim
|
||||
|
||||
nodes, err := util.FilterNodes(nodeList, argWithNodeFilters.NodeFilters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to filter nodes for k3s extra args config '%s': %w", argWithNodeFilters.Arg, err)
|
||||
}
|
||||
|
||||
for _, node := range nodes {
|
||||
@ -283,7 +283,7 @@ func TransformSimpleToClusterConfig(ctx context.Context, runtime runtimes.Runtim
|
||||
if simpleConfig.Registries.Create {
|
||||
regPort, err := cliutil.ParsePortExposureSpec("random", k3d.DefaultRegistryPort)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to get port for registry: %+v", err)
|
||||
return nil, fmt.Errorf("failed to get port for registry: %w", err)
|
||||
}
|
||||
clusterCreateOpts.Registries.Create = &k3d.Registry{
|
||||
ClusterRef: newCluster.Name,
|
||||
@ -296,7 +296,7 @@ func TransformSimpleToClusterConfig(ctx context.Context, runtime runtimes.Runtim
|
||||
for _, usereg := range simpleConfig.Registries.Use {
|
||||
reg, err := util.ParseRegistryRef(usereg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to parse use-registry string '%s': %+v", usereg, err)
|
||||
return nil, fmt.Errorf("failed to parse use-registry string '%s': %w", usereg, err)
|
||||
}
|
||||
l.Log().Tracef("Parsed registry reference: %+v", reg)
|
||||
clusterCreateOpts.Registries.Use = append(clusterCreateOpts.Registries.Use, reg)
|
||||
@ -308,20 +308,20 @@ func TransformSimpleToClusterConfig(ctx context.Context, runtime runtimes.Runtim
|
||||
if strings.Contains(simpleConfig.Registries.Config, "\n") { // CASE 1: embedded registries.yaml (multiline string)
|
||||
l.Log().Debugf("Found multiline registries config embedded in SimpleConfig:\n%s", simpleConfig.Registries.Config)
|
||||
if err := yaml.Unmarshal([]byte(simpleConfig.Registries.Config), &k3sRegistry); err != nil {
|
||||
return nil, fmt.Errorf("Failed to read embedded registries config: %+v", err)
|
||||
return nil, fmt.Errorf("failed to read embedded registries config: %w", err)
|
||||
}
|
||||
} else { // CASE 2: registries.yaml file referenced by path (single line)
|
||||
registryConfigFile, err := os.Open(simpleConfig.Registries.Config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to open registry config file at %s: %+v", simpleConfig.Registries.Config, err)
|
||||
return nil, fmt.Errorf("failed to open registry config file at %s: %w", simpleConfig.Registries.Config, err)
|
||||
}
|
||||
configBytes, err := ioutil.ReadAll(registryConfigFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to read registry config file at %s: %+v", registryConfigFile.Name(), err)
|
||||
return nil, fmt.Errorf("failed to read registry config file at %s: %w", registryConfigFile.Name(), err)
|
||||
}
|
||||
|
||||
if err := yaml.Unmarshal(configBytes, &k3sRegistry); err != nil {
|
||||
return nil, fmt.Errorf("Failed to read registry configuration: %+v", err)
|
||||
return nil, fmt.Errorf("failed to read registry configuration: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,63 +35,55 @@ import (
|
||||
"fmt"
|
||||
|
||||
dockerunits "github.com/docker/go-units"
|
||||
l "github.com/rancher/k3d/v4/pkg/logger"
|
||||
)
|
||||
|
||||
// ValidateClusterConfig checks a given cluster config for basic errors
|
||||
func ValidateClusterConfig(ctx context.Context, runtime runtimes.Runtime, config conf.ClusterConfig) error {
|
||||
// cluster name must be a valid host name
|
||||
if err := k3dc.CheckName(config.Cluster.Name); err != nil {
|
||||
l.Log().Errorf("Provided cluster name '%s' does not match requirements", config.Cluster.Name)
|
||||
|
||||
return err
|
||||
return fmt.Errorf("provided cluster name '%s' does not match requirements: %w", config.Cluster.Name, err)
|
||||
}
|
||||
|
||||
// network:: edge case: hostnetwork -> only if we have a single node (to avoid port collisions)
|
||||
if config.Cluster.Network.Name == "host" && len(config.Cluster.Nodes) > 1 {
|
||||
return fmt.Errorf("Can only use hostnetwork mode with a single node (port collisions, etc.)")
|
||||
return fmt.Errorf("can only use hostnetwork mode with a single node (port collisions, etc.)")
|
||||
}
|
||||
|
||||
// timeout can't be negative
|
||||
if config.ClusterCreateOpts.Timeout < 0*time.Second {
|
||||
return fmt.Errorf("Timeout may not be negative (is '%s')", config.ClusterCreateOpts.Timeout)
|
||||
return fmt.Errorf("timeout may not be negative (is '%s')", config.ClusterCreateOpts.Timeout)
|
||||
}
|
||||
|
||||
// API-Port cannot be changed when using network=host
|
||||
if config.Cluster.Network.Name == "host" && config.Cluster.KubeAPI.Port.Port() != k3d.DefaultAPIPort {
|
||||
// in hostNetwork mode, we're not going to map a hostport. Here it should always use 6443.
|
||||
// Note that hostNetwork mode is super inflexible and since we don't change the backend port (on the container), it will only be one hostmode cluster allowed.
|
||||
return fmt.Errorf("The API Port can not be changed when using 'host' network")
|
||||
return fmt.Errorf("the API Port can not be changed when using 'host' network")
|
||||
}
|
||||
|
||||
// memory limits must have proper format
|
||||
// if empty we don't care about errors in parsing
|
||||
if config.ClusterCreateOpts.ServersMemory != "" {
|
||||
if _, err := dockerunits.RAMInBytes(config.ClusterCreateOpts.ServersMemory); err != nil {
|
||||
return fmt.Errorf("Provided servers memory limit value is invalid")
|
||||
return fmt.Errorf("provided servers memory limit value is invalid: %w", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if config.ClusterCreateOpts.AgentsMemory != "" {
|
||||
if _, err := dockerunits.RAMInBytes(config.ClusterCreateOpts.AgentsMemory); err != nil {
|
||||
return fmt.Errorf("Provided agents memory limit value is invalid")
|
||||
return fmt.Errorf("provided agents memory limit value is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// validate nodes one by one
|
||||
for _, node := range config.Cluster.Nodes {
|
||||
|
||||
// node names have to be valid hostnames // TODO: validate hostnames once we generate them before this step
|
||||
/*if err := k3dc.CheckName(node.Name); err != nil {
|
||||
return err
|
||||
}*/
|
||||
|
||||
// volumes have to be either an existing path on the host or a named runtime volume
|
||||
for _, volume := range node.Volumes {
|
||||
|
||||
if err := runtimeutil.ValidateVolumeMount(runtime, volume); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to validate volume mount '%s': %w", volume, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,8 +46,7 @@ func createContainer(ctx context.Context, dockerNode *NodeInDocker, name string)
|
||||
// initialize docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return "", err
|
||||
return "", fmt.Errorf("failed to create docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
@ -58,13 +57,11 @@ func createContainer(ctx context.Context, dockerNode *NodeInDocker, name string)
|
||||
if err != nil {
|
||||
if client.IsErrNotFound(err) {
|
||||
if err := pullImage(ctx, docker, dockerNode.ContainerConfig.Image); err != nil {
|
||||
l.Log().Errorf("Failed to create container '%s'", name)
|
||||
return "", err
|
||||
return "", fmt.Errorf("docker failed to pull image '%s': %w", dockerNode.ContainerConfig.Image, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
l.Log().Errorf("Failed to create container '%s'", name)
|
||||
return "", err
|
||||
return "", fmt.Errorf("docker failed to create container '%s': %w", name, err)
|
||||
}
|
||||
l.Log().Debugf("Created container %s (ID: %s)", name, resp.ID)
|
||||
break
|
||||
@ -77,8 +74,7 @@ func startContainer(ctx context.Context, ID string) error {
|
||||
// initialize docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return err
|
||||
return fmt.Errorf("failed to get docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
@ -91,8 +87,7 @@ func removeContainer(ctx context.Context, ID string) error {
|
||||
// (0) create docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return err
|
||||
return fmt.Errorf("failed to get docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
@ -104,8 +99,7 @@ func removeContainer(ctx context.Context, ID string) error {
|
||||
|
||||
// (2) remove container
|
||||
if err := docker.ContainerRemove(ctx, ID, options); err != nil {
|
||||
l.Log().Errorf("Failed to delete container '%s'", ID)
|
||||
return err
|
||||
return fmt.Errorf("docker failed to remove the container '%s': %w", ID, err)
|
||||
}
|
||||
|
||||
l.Log().Infoln("Deleted", ID)
|
||||
@ -118,8 +112,7 @@ func pullImage(ctx context.Context, docker *client.Client, image string) error {
|
||||
|
||||
resp, err := docker.ImagePull(ctx, image, types.ImagePullOptions{})
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to pull image '%s'", image)
|
||||
return err
|
||||
return fmt.Errorf("docker failed to pull the image '%s': %w", image, err)
|
||||
}
|
||||
defer resp.Close()
|
||||
|
||||
@ -132,8 +125,7 @@ func pullImage(ctx context.Context, docker *client.Client, image string) error {
|
||||
}
|
||||
_, err = io.Copy(writer, resp)
|
||||
if err != nil {
|
||||
l.Log().Warningf("Couldn't get docker output")
|
||||
l.Log().Warningln(err)
|
||||
l.Log().Warnf("Couldn't get docker output: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -145,8 +137,7 @@ func getNodeContainer(ctx context.Context, node *k3d.Node) (*types.Container, er
|
||||
// (0) create docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to get docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
@ -187,8 +178,7 @@ func getNodeContainer(ctx context.Context, node *k3d.Node) (*types.Container, er
|
||||
func executeCheckInContainer(ctx context.Context, image string, cmd []string) (int64, error) {
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return -1, err
|
||||
return -1, fmt.Errorf("failed to create docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
@ -204,20 +194,17 @@ func executeCheckInContainer(ctx context.Context, image string, cmd []string) (i
|
||||
if err != nil {
|
||||
if client.IsErrNotFound(err) {
|
||||
if err := pullImage(ctx, docker, image); err != nil {
|
||||
l.Log().Errorf("Failed to create container from image %s with cmd %s", image, cmd)
|
||||
return -1, err
|
||||
return -1, fmt.Errorf("docker failed to pull image '%s': %w", image, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
l.Log().Errorf("Failed to create container from image %s with cmd %s", image, cmd)
|
||||
return -1, err
|
||||
return -1, fmt.Errorf("docker failed to create container from image '%s' with cmd '%s': %w", image, cmd, err)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if err = startContainer(ctx, resp.ID); err != nil {
|
||||
l.Log().Errorf("Failed to start container from image %s with cmd %s", image, cmd)
|
||||
return -1, err
|
||||
return -1, fmt.Errorf("docker failed to start container from image '%s' with cmd '%s': %w", image, cmd, err)
|
||||
}
|
||||
|
||||
exitCode := -1
|
||||
@ -225,15 +212,14 @@ func executeCheckInContainer(ctx context.Context, image string, cmd []string) (i
|
||||
select {
|
||||
case err := <-errCh:
|
||||
if err != nil {
|
||||
l.Log().Errorf("Error while waiting for container %s to exit", resp.ID)
|
||||
return -1, err
|
||||
return -1, fmt.Errorf("docker error while waiting for container '%s' to exit: %w", resp.ID, err)
|
||||
}
|
||||
case status := <-statusCh:
|
||||
exitCode = int(status.StatusCode)
|
||||
}
|
||||
|
||||
if err = removeContainer(ctx, resp.ID); err != nil {
|
||||
return -1, err
|
||||
return -1, fmt.Errorf("docker failed to remove container '%s': %w", resp.ID, err)
|
||||
}
|
||||
|
||||
return int64(exitCode), nil
|
||||
@ -246,6 +232,5 @@ func CheckIfDirectoryExists(ctx context.Context, image string, dir string) (bool
|
||||
cmd := []string{"sh", "-c", shellCmd}
|
||||
exitCode, err := executeCheckInContainer(ctx, image, cmd)
|
||||
l.Log().Tracef("check dir container returned %d exist code", exitCode)
|
||||
return exitCode == 0, err
|
||||
|
||||
return exitCode == 0, fmt.Errorf("error executing check command '%s' in container with image '%s': %w", cmd, image, err)
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ func (d Docker) GetHostIP(ctx context.Context, network string) (net.IP, error) {
|
||||
if runtime.GOOS == "linux" {
|
||||
ip, err := GetGatewayIP(ctx, network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to get gateway IP of docker network '%s': %w", network, err)
|
||||
}
|
||||
return ip, nil
|
||||
}
|
||||
|
@ -23,9 +23,9 @@ package docker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
l "github.com/rancher/k3d/v4/pkg/logger"
|
||||
)
|
||||
|
||||
// GetImages returns a list of images present in the runtime
|
||||
@ -33,15 +33,13 @@ func (d Docker) GetImages(ctx context.Context) ([]string, error) {
|
||||
// create docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to create docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
imageSummary, err := docker.ImageList(ctx, types.ImageListOptions{All: true})
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to list available docker images")
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("docker failed to list images: %w", err)
|
||||
}
|
||||
|
||||
var images []string
|
||||
|
@ -24,9 +24,9 @@ package docker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
l "github.com/rancher/k3d/v4/pkg/logger"
|
||||
runtimeTypes "github.com/rancher/k3d/v4/pkg/runtimes/types"
|
||||
)
|
||||
|
||||
@ -34,14 +34,13 @@ func (d Docker) Info() (*runtimeTypes.RuntimeInfo, error) {
|
||||
// create docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to create docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
info, err := docker.Info(context.Background())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("docker failed to provide info output: %w", err)
|
||||
}
|
||||
|
||||
runtimeInfo := runtimeTypes.RuntimeInfo{
|
||||
|
@ -24,6 +24,7 @@ package docker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
l "github.com/rancher/k3d/v4/pkg/logger"
|
||||
@ -34,22 +35,20 @@ import (
|
||||
func (d Docker) GetKubeconfig(ctx context.Context, node *k3d.Node) (io.ReadCloser, error) {
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to create docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
container, err := getNodeContainer(ctx, node)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("docker failed to get container for node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
l.Log().Tracef("Container Details: %+v", container)
|
||||
|
||||
reader, _, err := docker.CopyFromContainer(ctx, container.ID, "/output/kubeconfig.yaml")
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to copy from container '%s'", container.ID)
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("docker failed to copy path '/output/kubeconfig.yaml' from container '%s': %w", container.ID, err)
|
||||
}
|
||||
|
||||
return reader, nil
|
||||
|
@ -43,13 +43,12 @@ func (d Docker) GetNetwork(ctx context.Context, searchNet *k3d.ClusterNetwork) (
|
||||
// (0) create new docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to create docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
if searchNet.ID == "" && searchNet.Name == "" {
|
||||
return nil, fmt.Errorf("need one of name, id to get network")
|
||||
return nil, fmt.Errorf("failed to get network, because neither name nor ID was provided")
|
||||
}
|
||||
// configure list filters
|
||||
filter := filters.NewArgs()
|
||||
@ -65,8 +64,7 @@ func (d Docker) GetNetwork(ctx context.Context, searchNet *k3d.ClusterNetwork) (
|
||||
Filters: filter,
|
||||
})
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to list docker networks")
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("docker failed to list networks: %w", err)
|
||||
}
|
||||
|
||||
if len(networkList) == 0 {
|
||||
@ -75,7 +73,7 @@ func (d Docker) GetNetwork(ctx context.Context, searchNet *k3d.ClusterNetwork) (
|
||||
|
||||
targetNetwork, err := docker.NetworkInspect(ctx, networkList[0].ID, types.NetworkInspectOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to inspect network %s: %w", networkList[0].Name, err)
|
||||
return nil, fmt.Errorf("docker failed to inspect network %s: %w", networkList[0].Name, err)
|
||||
}
|
||||
l.Log().Debugf("Found network %+v", targetNetwork)
|
||||
|
||||
@ -88,7 +86,7 @@ func (d Docker) GetNetwork(ctx context.Context, searchNet *k3d.ClusterNetwork) (
|
||||
if len(targetNetwork.IPAM.Config) > 0 {
|
||||
network.IPAM, err = d.parseIPAM(targetNetwork.IPAM.Config[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to parse IPAM config: %w", err)
|
||||
}
|
||||
|
||||
for _, container := range targetNetwork.Containers {
|
||||
@ -138,8 +136,7 @@ func (d Docker) CreateNetworkIfNotPresent(ctx context.Context, inNet *k3d.Cluste
|
||||
// (0) create new docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return nil, false, err
|
||||
return nil, false, fmt.Errorf("failed to create docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
@ -147,8 +144,7 @@ func (d Docker) CreateNetworkIfNotPresent(ctx context.Context, inNet *k3d.Cluste
|
||||
if err != nil {
|
||||
if err != runtimeErr.ErrRuntimeNetworkNotExists {
|
||||
if existingNet == nil {
|
||||
l.Log().Errorln("Failed to check for duplicate networks")
|
||||
return nil, false, err
|
||||
return nil, false, fmt.Errorf("failed to check for duplicate docker networks: %w", err)
|
||||
} else if err == runtimeErr.ErrRuntimeNetworkMultiSameName {
|
||||
l.Log().Warnf("%+v, returning the first one: %s (%s)", err, existingNet.Name, existingNet.ID)
|
||||
return existingNet, true, nil
|
||||
@ -176,7 +172,7 @@ func (d Docker) CreateNetworkIfNotPresent(ctx context.Context, inNet *k3d.Cluste
|
||||
l.Log().Traceln("No subnet prefix given, but network should be managed: Trying to get a free subnet prefix...")
|
||||
freeSubnetPrefix, err := d.getFreeSubnetPrefix(ctx)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
return nil, false, fmt.Errorf("failed to get free subnet prefix: %w", err)
|
||||
}
|
||||
inNet.IPAM.IPPrefix = freeSubnetPrefix
|
||||
}
|
||||
@ -195,20 +191,18 @@ func (d Docker) CreateNetworkIfNotPresent(ctx context.Context, inNet *k3d.Cluste
|
||||
|
||||
newNet, err := docker.NetworkCreate(ctx, inNet.Name, netCreateOpts)
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create new network")
|
||||
return nil, false, err
|
||||
return nil, false, fmt.Errorf("docker failed to create new network '%s': %w", inNet.Name, err)
|
||||
}
|
||||
|
||||
networkDetails, err := docker.NetworkInspect(ctx, newNet.ID, types.NetworkInspectOptions{})
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to inspect newly created network")
|
||||
return nil, false, err
|
||||
return nil, false, fmt.Errorf("docker failed to inspect newly created network '%s': %w", newNet.ID, err)
|
||||
}
|
||||
|
||||
l.Log().Infof("Created network '%s' (%s)", inNet.Name, networkDetails.ID)
|
||||
prefix, err := netaddr.ParseIPPrefix(networkDetails.IPAM.Config[0].Subnet)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
return nil, false, fmt.Errorf("failed to parse IP Prefix of newly created network '%s': %w", newNet.ID, err)
|
||||
}
|
||||
|
||||
newClusterNet := &k3d.ClusterNetwork{Name: inNet.Name, ID: networkDetails.ID, IPAM: k3d.IPAM{IPPrefix: prefix}}
|
||||
@ -225,8 +219,7 @@ func (d Docker) DeleteNetwork(ctx context.Context, ID string) error {
|
||||
// (0) create new docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return err
|
||||
return fmt.Errorf("failed to get docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
@ -235,7 +228,7 @@ func (d Docker) DeleteNetwork(ctx context.Context, ID string) error {
|
||||
if strings.HasSuffix(err.Error(), "active endpoints") {
|
||||
return runtimeErr.ErrRuntimeNetworkNotEmpty
|
||||
}
|
||||
return err
|
||||
return fmt.Errorf("docker failed to remove network '%s': %w", ID, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -244,8 +237,7 @@ func (d Docker) DeleteNetwork(ctx context.Context, ID string) error {
|
||||
func GetNetwork(ctx context.Context, ID string) (types.NetworkResource, error) {
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return types.NetworkResource{}, err
|
||||
return types.NetworkResource{}, fmt.Errorf("failed to get docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
return docker.NetworkInspect(ctx, ID, types.NetworkInspectOptions{})
|
||||
@ -255,8 +247,7 @@ func GetNetwork(ctx context.Context, ID string) (types.NetworkResource, error) {
|
||||
func GetGatewayIP(ctx context.Context, network string) (net.IP, error) {
|
||||
bridgeNetwork, err := GetNetwork(ctx, network)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to get bridge network with name '%s'", network)
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to get bridge network with name '%s': %w", network, err)
|
||||
}
|
||||
|
||||
if len(bridgeNetwork.IPAM.Config) > 0 {
|
||||
@ -279,22 +270,20 @@ func (d Docker) ConnectNodeToNetwork(ctx context.Context, node *k3d.Node, networ
|
||||
// get container
|
||||
container, err := getNodeContainer(ctx, node)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to get container for node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
// get docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return err
|
||||
return fmt.Errorf("failed to get docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
// get network
|
||||
networkResource, err := GetNetwork(ctx, networkName)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to get network '%s'", networkName)
|
||||
return err
|
||||
return fmt.Errorf("failed to get network '%s': %w", networkName, err)
|
||||
}
|
||||
|
||||
// connect container to network
|
||||
@ -307,22 +296,20 @@ func (d Docker) DisconnectNodeFromNetwork(ctx context.Context, node *k3d.Node, n
|
||||
// get container
|
||||
container, err := getNodeContainer(ctx, node)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to get container for node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
// get docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return err
|
||||
return fmt.Errorf("failed to get docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
// get network
|
||||
networkResource, err := GetNetwork(ctx, networkName)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to get network '%s'", networkName)
|
||||
return err
|
||||
return fmt.Errorf("failed to get network '%s': %w", networkName, err)
|
||||
}
|
||||
|
||||
return docker.NetworkDisconnect(ctx, networkResource.ID, container.ID, true)
|
||||
|
@ -44,15 +44,13 @@ func (d Docker) CreateNode(ctx context.Context, node *k3d.Node) error {
|
||||
// translate node spec to docker container specs
|
||||
dockerNode, err := TranslateNodeToContainer(node)
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to translate k3d node specification to docker container specifications")
|
||||
return err
|
||||
return fmt.Errorf("failed to translate k3d node spec to docker container spec: %w", err)
|
||||
}
|
||||
|
||||
// create node
|
||||
_, err = createContainer(ctx, dockerNode, node.Name)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to create node '%s'", node.Name)
|
||||
return err
|
||||
return fmt.Errorf("failed to create container for node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -70,7 +68,7 @@ func (d Docker) GetNodesByLabel(ctx context.Context, labels map[string]string) (
|
||||
// (0) get containers
|
||||
containers, err := getContainersByLabel(ctx, labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("docker failed to get containers with labels '%v': %w", labels, err)
|
||||
}
|
||||
|
||||
// (1) convert them to node structs
|
||||
@ -84,12 +82,12 @@ func (d Docker) GetNodesByLabel(ctx context.Context, labels map[string]string) (
|
||||
l.Log().Warnf("Failed to get details for container %s", container.Names[0])
|
||||
node, err = TranslateContainerToNode(&container)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to translate container '%s' to k3d node spec: %w", container.Names[0], err)
|
||||
}
|
||||
} else {
|
||||
node, err = TranslateContainerDetailsToNode(containerDetails)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to translate container'%s' details to k3d node spec: %w", containerDetails.Name, err)
|
||||
}
|
||||
}
|
||||
nodes = append(nodes, node)
|
||||
@ -104,15 +102,14 @@ func (d Docker) StartNode(ctx context.Context, node *k3d.Node) error {
|
||||
// (0) create docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to create docker client. %+v", err)
|
||||
return fmt.Errorf("failed to create docker client. %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
// get container which represents the node
|
||||
nodeContainer, err := getNodeContainer(ctx, node)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to get container for node '%s'", node.Name)
|
||||
return err
|
||||
return fmt.Errorf("failed to get container for node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
// check if the container is actually managed by
|
||||
@ -123,7 +120,7 @@ func (d Docker) StartNode(ctx context.Context, node *k3d.Node) error {
|
||||
// actually start the container
|
||||
l.Log().Infof("Starting Node '%s'", node.Name)
|
||||
if err := docker.ContainerStart(ctx, nodeContainer.ID, types.ContainerStartOptions{}); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("docker failed to start container for node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
// get container which represents the node
|
||||
@ -151,8 +148,7 @@ func (d Docker) StopNode(ctx context.Context, node *k3d.Node) error {
|
||||
// get container which represents the node
|
||||
nodeContainer, err := getNodeContainer(ctx, node)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to get container for node '%s'", node.Name)
|
||||
return err
|
||||
return fmt.Errorf("failed to get container for node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
// check if the container is actually managed by
|
||||
@ -162,7 +158,7 @@ func (d Docker) StopNode(ctx context.Context, node *k3d.Node) error {
|
||||
|
||||
// actually stop the container
|
||||
if err := docker.ContainerStop(ctx, nodeContainer.ID, nil); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("docker failed to stop the container '%s': %w", nodeContainer.ID, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -201,14 +197,13 @@ func getContainerDetails(ctx context.Context, containerID string) (types.Contain
|
||||
// (0) create docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
return types.ContainerJSON{}, fmt.Errorf("Failed to create docker client. %+v", err)
|
||||
return types.ContainerJSON{}, fmt.Errorf("failed to create docker client. %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
containerDetails, err := docker.ContainerInspect(ctx, containerID)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to get details for container '%s'", containerID)
|
||||
return types.ContainerJSON{}, err
|
||||
return types.ContainerJSON{}, fmt.Errorf("failed to get details for container '%s': %w", containerID, err)
|
||||
}
|
||||
|
||||
return containerDetails, nil
|
||||
@ -219,18 +214,17 @@ func getContainerDetails(ctx context.Context, containerID string) (types.Contain
|
||||
func (d Docker) GetNode(ctx context.Context, node *k3d.Node) (*k3d.Node, error) {
|
||||
container, err := getNodeContainer(ctx, node)
|
||||
if err != nil {
|
||||
return node, err
|
||||
return node, fmt.Errorf("failed to get container for node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
containerDetails, err := getContainerDetails(ctx, container.ID)
|
||||
if err != nil {
|
||||
return node, err
|
||||
return node, fmt.Errorf("failed to get details for container '%s': %w", container.ID, err)
|
||||
}
|
||||
|
||||
node, err = TranslateContainerDetailsToNode(containerDetails)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to translate container '%s' to node object", containerDetails.Name)
|
||||
return node, err
|
||||
return node, fmt.Errorf("failed to translate container '%s' details to node spec: %w", containerDetails.Name, err)
|
||||
}
|
||||
|
||||
return node, nil
|
||||
@ -246,20 +240,19 @@ func (d Docker) GetNodeStatus(ctx context.Context, node *k3d.Node) (bool, string
|
||||
// get the container for the given node
|
||||
container, err := getNodeContainer(ctx, node)
|
||||
if err != nil {
|
||||
return running, stateString, err
|
||||
return running, stateString, fmt.Errorf("failed to get container for node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
// create docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return running, stateString, err
|
||||
return running, stateString, fmt.Errorf("failed to get docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
containerInspectResponse, err := docker.ContainerInspect(ctx, container.ID)
|
||||
if err != nil {
|
||||
return running, stateString, err
|
||||
return running, stateString, fmt.Errorf("docker failed to inspect container '%s': %w", container.ID, err)
|
||||
}
|
||||
|
||||
running = containerInspectResponse.ContainerJSONBase.State.Running
|
||||
@ -272,7 +265,7 @@ func (d Docker) GetNodeStatus(ctx context.Context, node *k3d.Node) (bool, string
|
||||
func (d Docker) NodeIsRunning(ctx context.Context, node *k3d.Node) (bool, error) {
|
||||
isRunning, _, err := d.GetNodeStatus(ctx, node)
|
||||
if err != nil {
|
||||
return false, err
|
||||
return false, fmt.Errorf("failed to get status for node '%s': %w", node.Name, err)
|
||||
}
|
||||
return isRunning, nil
|
||||
}
|
||||
@ -282,25 +275,23 @@ func (d Docker) GetNodeLogs(ctx context.Context, node *k3d.Node, since time.Time
|
||||
// get the container for the given node
|
||||
container, err := getNodeContainer(ctx, node)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to get container for node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
// create docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to get docker client; %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
containerInspectResponse, err := docker.ContainerInspect(ctx, container.ID)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to inspect node '%s'(ID %s)", node.Name, container.ID)
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed ton inspect container '%s': %w", container.ID, err)
|
||||
}
|
||||
|
||||
if !containerInspectResponse.ContainerJSONBase.State.Running {
|
||||
return nil, fmt.Errorf("Node '%s' (container '%s') not running", node.Name, containerInspectResponse.ID)
|
||||
return nil, fmt.Errorf("node '%s' (container '%s') not running", node.Name, containerInspectResponse.ID)
|
||||
}
|
||||
|
||||
sinceStr := ""
|
||||
@ -309,8 +300,7 @@ func (d Docker) GetNodeLogs(ctx context.Context, node *k3d.Node, since time.Time
|
||||
}
|
||||
logreader, err := docker.ContainerLogs(ctx, container.ID, types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true, Since: sinceStr})
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to get logs from node '%s' (container '%s')", node.Name, container.ID)
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("docker failed to get logs from node '%s' (container '%s'): %w", node.Name, container.ID, err)
|
||||
}
|
||||
|
||||
return logreader, nil
|
||||
@ -335,8 +325,7 @@ func (d Docker) ExecInNode(ctx context.Context, node *k3d.Node, cmd []string) er
|
||||
if execConnection != nil && execConnection.Reader != nil {
|
||||
logs, err := ioutil.ReadAll(execConnection.Reader)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to get logs from errored exec process in node '%s'", node.Name)
|
||||
return err
|
||||
return fmt.Errorf("failed to get logs from errored exec process in node '%s': %w", node.Name, err)
|
||||
}
|
||||
err = fmt.Errorf("%w: Logs from failed access process:\n%s", err, string(logs))
|
||||
}
|
||||
@ -351,14 +340,13 @@ func executeInNode(ctx context.Context, node *k3d.Node, cmd []string) (*types.Hi
|
||||
// get the container for the given node
|
||||
container, err := getNodeContainer(ctx, node)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to get container for node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
// create docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to get docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
@ -371,28 +359,25 @@ func executeInNode(ctx context.Context, node *k3d.Node, cmd []string) (*types.Hi
|
||||
Cmd: cmd,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to create exec config for node '%s': %+v", node.Name, err)
|
||||
return nil, fmt.Errorf("docker failed to create exec config for node '%s': %+v", node.Name, err)
|
||||
}
|
||||
|
||||
execConnection, err := docker.ContainerExecAttach(ctx, exec.ID, types.ExecStartCheck{
|
||||
Tty: true,
|
||||
})
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to connect to exec process in node '%s'", node.Name)
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("docker failed to attach to exec process in node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
if err := docker.ContainerExecStart(ctx, exec.ID, types.ExecStartCheck{Tty: true}); err != nil {
|
||||
l.Log().Errorf("Failed to start exec process in node '%s'", node.Name)
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("docker failed to start exec process in node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
for {
|
||||
// get info about exec process inside container
|
||||
execInfo, err := docker.ContainerExecInspect(ctx, exec.ID)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to inspect exec process in node '%s'", node.Name)
|
||||
return &execConnection, err
|
||||
return &execConnection, fmt.Errorf("docker failed to inspect exec process in node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
// if still running, continue loop
|
||||
@ -416,14 +401,13 @@ func (d Docker) GetNodesInNetwork(ctx context.Context, network string) ([]*k3d.N
|
||||
// create docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to create docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
net, err := GetNetwork(ctx, network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to get network '%s': %w", network, err)
|
||||
}
|
||||
|
||||
connectedNodes := []*k3d.Node{}
|
||||
@ -432,7 +416,7 @@ func (d Docker) GetNodesInNetwork(ctx context.Context, network string) ([]*k3d.N
|
||||
for cID := range net.Containers {
|
||||
containerDetails, err := getContainerDetails(ctx, cID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("docker failed to get details of container '%s': %w", cID, err)
|
||||
}
|
||||
node, err := TranslateContainerDetailsToNode(containerDetails)
|
||||
if err != nil {
|
||||
@ -440,7 +424,7 @@ func (d Docker) GetNodesInNetwork(ctx context.Context, network string) ([]*k3d.N
|
||||
l.Log().Tracef("GetNodesInNetwork: inspected non-k3d-managed container %s", containerDetails.Name)
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to translate container '%s' details to node spec: %w", containerDetails.Name, err)
|
||||
}
|
||||
connectedNodes = append(connectedNodes, node)
|
||||
}
|
||||
@ -452,14 +436,13 @@ func (d Docker) RenameNode(ctx context.Context, node *k3d.Node, newName string)
|
||||
// get the container for the given node
|
||||
container, err := getNodeContainer(ctx, node)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to get container for node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
// create docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return err
|
||||
return fmt.Errorf("failed to get docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
|
@ -57,28 +57,24 @@ func (d Docker) CopyToNode(ctx context.Context, src string, dest string, node *k
|
||||
// create docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return err
|
||||
return fmt.Errorf("failed to get docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
container, err := getNodeContainer(ctx, node)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to find container for target node '%s'", node.Name)
|
||||
return err
|
||||
return fmt.Errorf("failed to find container for target node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
// source: docker/cli/cli/command/container/cp
|
||||
srcInfo, err := archive.CopyInfoSourcePath(src, false)
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to copy info source path")
|
||||
return err
|
||||
return fmt.Errorf("failed to copy info source path: %w", err)
|
||||
}
|
||||
|
||||
srcArchive, err := archive.TarResource(srcInfo)
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create tar resource")
|
||||
return err
|
||||
return fmt.Errorf("failed to create tar resource: %w", err)
|
||||
}
|
||||
defer srcArchive.Close()
|
||||
|
||||
@ -90,8 +86,7 @@ func (d Docker) CopyToNode(ctx context.Context, src string, dest string, node *k
|
||||
|
||||
destDir, preparedArchive, err := archive.PrepareArchiveCopy(srcArchive, srcInfo, destInfo)
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to prepare archive")
|
||||
return err
|
||||
return fmt.Errorf("failed to prepare archive: %w", err)
|
||||
}
|
||||
defer preparedArchive.Close()
|
||||
|
||||
@ -109,8 +104,7 @@ func (d Docker) WriteToNode(ctx context.Context, content []byte, dest string, mo
|
||||
// create docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return err
|
||||
return fmt.Errorf("failed to get docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
@ -148,12 +142,12 @@ func (d Docker) ReadFromNode(ctx context.Context, path string, node *k3d.Node) (
|
||||
l.Log().Tracef("Reading path %s from node %s...", path, node.Name)
|
||||
nodeContainer, err := getNodeContainer(ctx, node)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to find container for node '%s': %+v", node.Name, err)
|
||||
return nil, fmt.Errorf("failed to find container for node '%s': %w", node.Name, err)
|
||||
}
|
||||
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to get docker client: %w", err)
|
||||
}
|
||||
|
||||
reader, _, err := docker.CopyFromContainer(ctx, nodeContainer.ID, path)
|
||||
@ -161,7 +155,7 @@ func (d Docker) ReadFromNode(ctx context.Context, path string, node *k3d.Node) (
|
||||
if client.IsErrNotFound(err) {
|
||||
return nil, errors.Wrap(runtimeErrors.ErrRuntimeFileNotFound, err.Error())
|
||||
}
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to copy path '%s' from container '%s': %w", path, nodeContainer.ID, err)
|
||||
}
|
||||
|
||||
return reader, err
|
||||
@ -171,7 +165,7 @@ func (d Docker) ReadFromNode(ctx context.Context, path string, node *k3d.Node) (
|
||||
func GetDockerClient() (*client.Client, error) {
|
||||
dockerCli, err := command.NewDockerCli(command.WithStandardStreams())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to create new docker CLI with standard streams: %w", err)
|
||||
}
|
||||
|
||||
newClientOpts := flags.NewClientOptions()
|
||||
@ -179,7 +173,7 @@ func GetDockerClient() (*client.Client, error) {
|
||||
|
||||
err = dockerCli.Initialize(newClientOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to initialize docker CLI: %w", err)
|
||||
}
|
||||
|
||||
// check for TLS Files used for protected connections
|
||||
@ -187,7 +181,7 @@ func GetDockerClient() (*client.Client, error) {
|
||||
storageInfo := dockerCli.ContextStore().GetStorageInfo(currentContext)
|
||||
tlsFilesMap, err := dockerCli.ContextStore().ListTLSFiles(currentContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("docker CLI failed to list TLS files for context '%s': %w", currentContext, err)
|
||||
}
|
||||
endpointDriver := "docker"
|
||||
tlsFiles := tlsFilesMap[endpointDriver]
|
||||
@ -198,7 +192,7 @@ func GetDockerClient() (*client.Client, error) {
|
||||
if ep.Host != "" {
|
||||
clientopts, err := ep.ClientOpts()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to get client opts for docker endpoint: %w", err)
|
||||
}
|
||||
headers := make(map[string]string, 1)
|
||||
headers["User-Agent"] = command.UserAgent()
|
||||
|
@ -36,8 +36,7 @@ func (d Docker) CreateVolume(ctx context.Context, name string, labels map[string
|
||||
// (0) create new docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return err
|
||||
return fmt.Errorf("failed to get docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
@ -58,8 +57,7 @@ func (d Docker) CreateVolume(ctx context.Context, name string, labels map[string
|
||||
|
||||
vol, err := docker.VolumeCreate(ctx, volumeCreateOptions)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to create volume '%s'", name)
|
||||
return err
|
||||
return fmt.Errorf("failed to create volume '%s': %w", name, err)
|
||||
}
|
||||
l.Log().Infof("Created volume '%s'", vol.Name)
|
||||
return nil
|
||||
@ -70,30 +68,26 @@ func (d Docker) DeleteVolume(ctx context.Context, name string) error {
|
||||
// (0) create new docker client
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return err
|
||||
return fmt.Errorf("failed to get docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
// get volume and delete it
|
||||
vol, err := docker.VolumeInspect(ctx, name)
|
||||
if err != nil {
|
||||
l.Log().Errorf("Failed to find volume '%s'", name)
|
||||
return err
|
||||
return fmt.Errorf("failed to find volume '%s': %w", name, err)
|
||||
}
|
||||
|
||||
// check if volume is still in use
|
||||
if vol.UsageData != nil {
|
||||
if vol.UsageData.RefCount > 0 {
|
||||
l.Log().Errorf("Failed to delete volume '%s'", vol.Name)
|
||||
return fmt.Errorf("Volume '%s' is still referenced by %d containers", name, vol.UsageData.RefCount)
|
||||
return fmt.Errorf("failed to delete volume '%s' as it is still referenced by %d containers", name, vol.UsageData.RefCount)
|
||||
}
|
||||
}
|
||||
|
||||
// remove volume
|
||||
if err := docker.VolumeRemove(ctx, name, true); err != nil {
|
||||
l.Log().Errorf("Failed to delete volume '%s'", name)
|
||||
return err
|
||||
return fmt.Errorf("docker failed to delete volume '%s': %w", name, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -105,8 +99,7 @@ func (d Docker) GetVolume(name string) (string, error) {
|
||||
ctx := context.Background()
|
||||
docker, err := GetDockerClient()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create docker client")
|
||||
return "", err
|
||||
return "", fmt.Errorf("failed to get docker client: %w", err)
|
||||
}
|
||||
defer docker.Close()
|
||||
|
||||
@ -114,10 +107,10 @@ func (d Docker) GetVolume(name string) (string, error) {
|
||||
filters.Add("name", fmt.Sprintf("^%s$", name))
|
||||
volumeList, err := docker.VolumeList(ctx, filters)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", fmt.Errorf("docker failed to list volumes: %w", err)
|
||||
}
|
||||
if len(volumeList.Volumes) < 1 {
|
||||
return "", fmt.Errorf("Failed to find named volume '%s'", name)
|
||||
return "", fmt.Errorf("failed to find named volume '%s'", name)
|
||||
}
|
||||
|
||||
return volumeList.Volumes[0].Name, nil
|
||||
|
@ -93,12 +93,12 @@ func ValidateVolumeMount(runtime runtimes.Runtime, volumeMount string) error {
|
||||
|
||||
// verifyNamedVolume checks whether a named volume exists in the runtime
|
||||
func verifyNamedVolume(runtime runtimes.Runtime, volumeName string) error {
|
||||
volumeName, err := runtime.GetVolume(volumeName)
|
||||
foundVolName, err := runtime.GetVolume(volumeName)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("runtime failed to get volume '%s': %w", volumeName, err)
|
||||
}
|
||||
if volumeName == "" {
|
||||
return fmt.Errorf("Failed to find named volume '%s'", volumeName)
|
||||
if foundVolName == "" {
|
||||
return fmt.Errorf("failed to find named volume '%s'", volumeName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -22,11 +22,11 @@ THE SOFTWARE.
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
homedir "github.com/mitchellh/go-homedir"
|
||||
l "github.com/rancher/k3d/v4/pkg/logger"
|
||||
)
|
||||
|
||||
// GetConfigDirOrCreate will return the base path of the k3d config directory or create it if it doesn't exist yet
|
||||
@ -36,15 +36,13 @@ func GetConfigDirOrCreate() (string, error) {
|
||||
// build the path
|
||||
homeDir, err := homedir.Dir()
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to get user's home directory")
|
||||
return "", err
|
||||
return "", fmt.Errorf("failed to get user's home directory: %w", err)
|
||||
}
|
||||
configDir := path.Join(homeDir, ".k3d")
|
||||
|
||||
// create directories if necessary
|
||||
if err := createDirIfNotExists(configDir); err != nil {
|
||||
l.Log().Errorf("Failed to create config path '%s'", configDir)
|
||||
return "", err
|
||||
return "", fmt.Errorf("failed to create config directory '%s': %w", configDir, err)
|
||||
}
|
||||
|
||||
return configDir, nil
|
||||
|
@ -83,7 +83,7 @@ func FilterNodesWithSuffix(nodes []*k3d.Node, nodefilters []string) (map[string]
|
||||
|
||||
filteredNodes, err := FilterNodes(nodes, []string{nf})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to filder nodes by filter '%s': %w", nf, err)
|
||||
}
|
||||
|
||||
l.Log().Tracef("Filtered %d nodes for suffix '%s' (filter: %s)", len(filteredNodes), suffix, nf)
|
||||
|
@ -28,7 +28,6 @@ import (
|
||||
"strings"
|
||||
|
||||
dockerunits "github.com/docker/go-units"
|
||||
l "github.com/rancher/k3d/v4/pkg/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -58,14 +57,13 @@ func GetNodeFakerDirOrCreate(name string) (string, error) {
|
||||
// this folder needs to be kept across reboots, keep it in ~/.k3d
|
||||
configdir, err := GetConfigDirOrCreate()
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", fmt.Errorf("failed to get config directory: %w", err)
|
||||
}
|
||||
fakeDir := path.Join(configdir, fmt.Sprintf(".%s", name))
|
||||
|
||||
// create directories if necessary
|
||||
if err := createDirIfNotExists(fakeDir); err != nil {
|
||||
l.Log().Errorf("Failed to create fake files path '%s'", fakeDir)
|
||||
return "", err
|
||||
return "", fmt.Errorf("failed to create fake files path '%s': %w", fakeDir, err)
|
||||
}
|
||||
|
||||
return fakeDir, nil
|
||||
@ -83,12 +81,12 @@ func GetFakeMeminfoPathForName(nodeName string) (string, error) {
|
||||
func MakeFakeMeminfo(memoryBytes int64, nodeName string) (string, error) {
|
||||
fakeMeminfoPath, err := GetFakeMeminfoPathForName(nodeName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", fmt.Errorf("failed to get fake meminfo path for node '%s': %w", nodeName, err)
|
||||
}
|
||||
fakememinfo, err := os.Create(fakeMeminfoPath)
|
||||
defer fakememinfo.Close()
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", fmt.Errorf("failed to create fake meminfo path '%s': %w", fakeMeminfoPath, err)
|
||||
}
|
||||
|
||||
// write content, must be kB
|
||||
@ -96,7 +94,7 @@ func MakeFakeMeminfo(memoryBytes int64, nodeName string) (string, error) {
|
||||
content := meminfoContent(memoryKb)
|
||||
_, err = fakememinfo.WriteString(content)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", fmt.Errorf("failed to write fake meminfo file: %w", err)
|
||||
}
|
||||
|
||||
return fakememinfo.Name(), nil
|
||||
@ -107,13 +105,12 @@ func MakeFakeMeminfo(memoryBytes int64, nodeName string) (string, error) {
|
||||
func MakeFakeEdac(nodeName string) (string, error) {
|
||||
dir, err := GetNodeFakerDirOrCreate(nodeName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", fmt.Errorf("failed to get or create fake files dir for node '%s': %w", nodeName, err)
|
||||
}
|
||||
edacPath := path.Join(dir, "edac")
|
||||
// create directories if necessary
|
||||
if err := createDirIfNotExists(edacPath); err != nil {
|
||||
l.Log().Errorf("Failed to create fake edac path '%s'", edacPath)
|
||||
return "", err
|
||||
return "", fmt.Errorf("failed to create fake edac path '%s': %w", edacPath, err)
|
||||
}
|
||||
|
||||
return edacPath, nil
|
||||
@ -124,7 +121,7 @@ func fakeInfoPathForName(infoType string, nodeName string) (string, error) {
|
||||
// this file needs to be kept across reboots, keep it in ~/.k3d
|
||||
dir, err := GetNodeFakerDirOrCreate(nodeName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", fmt.Errorf("failed to get or create fake files dir for node '%s': %w", nodeName, err)
|
||||
}
|
||||
return path.Join(dir, infoType), nil
|
||||
}
|
||||
|
@ -23,24 +23,22 @@ THE SOFTWARE.
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/docker/go-connections/nat"
|
||||
l "github.com/rancher/k3d/v4/pkg/logger"
|
||||
)
|
||||
|
||||
// GetFreePort tries to fetch an open port from the OS-Kernel
|
||||
func GetFreePort() (int, error) {
|
||||
tcpAddress, err := net.ResolveTCPAddr("tcp", "localhost:0")
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to resolve address")
|
||||
return 0, err
|
||||
return 0, fmt.Errorf("failed to resolve address 'localhost:0': %w", err)
|
||||
}
|
||||
|
||||
tcpListener, err := net.ListenTCP("tcp", tcpAddress)
|
||||
if err != nil {
|
||||
l.Log().Errorln("Failed to create TCP Listener")
|
||||
return 0, err
|
||||
return 0, fmt.Errorf("failed to create tcp listener: %w", err)
|
||||
}
|
||||
defer tcpListener.Close()
|
||||
|
||||
|
@ -22,6 +22,7 @@ THE SOFTWARE.
|
||||
package version
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
@ -85,12 +86,12 @@ func fetchLatestK3sVersion() (string, error) {
|
||||
|
||||
hub, err := registry.New(url, username, password)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", fmt.Errorf("failed to create new registry instance from URL '%s': %w", url, err)
|
||||
}
|
||||
|
||||
tags, err := hub.Tags(repository)
|
||||
if err != nil || len(tags) == 0 {
|
||||
return "", err
|
||||
return "", fmt.Errorf("failed to list tags from repository with URL '%s': %w", url, err)
|
||||
}
|
||||
|
||||
l.Log().Debugln("Fetched the following tags for rancher/k3s from DockerHub:")
|
||||
|
Loading…
Reference in New Issue
Block a user