diff --git a/cmd/cluster/clusterCreate.go b/cmd/cluster/clusterCreate.go index d4c3a6cc..5ea8c9dd 100644 --- a/cmd/cluster/clusterCreate.go +++ b/cmd/cluster/clusterCreate.go @@ -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) } } diff --git a/cmd/util/ports.go b/cmd/util/ports.go index 3b8037bf..f9759dbf 100644 --- a/cmd/util/ports.go +++ b/cmd/util/ports.go @@ -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() diff --git a/cmd/util/volumes.go b/cmd/util/volumes.go index 80668d2a..3282ee58 100644 --- a/cmd/util/volumes.go +++ b/cmd/util/volumes.go @@ -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) diff --git a/pkg/client/cluster.go b/pkg/client/cluster.go index 1da4988a..7fb5dd74 100644 --- a/pkg/client/cluster.go +++ b/pkg/client/cluster.go @@ -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, diff --git a/pkg/client/environment.go b/pkg/client/environment.go index 39e48513..1e0fe44e 100644 --- a/pkg/client/environment.go +++ b/pkg/client/environment.go @@ -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 diff --git a/pkg/client/host.go b/pkg/client/host.go index e02df7ac..8269b9fb 100644 --- a/pkg/client/host.go +++ b/pkg/client/host.go @@ -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 } diff --git a/pkg/client/ipam.go b/pkg/client/ipam.go index 2151d50f..ff1c3ac9 100644 --- a/pkg/client/ipam.go +++ b/pkg/client/ipam.go @@ -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 diff --git a/pkg/client/kubeconfig.go b/pkg/client/kubeconfig.go index abed7a70..3185b5b4 100644 --- a/pkg/client/kubeconfig.go +++ b/pkg/client/kubeconfig.go @@ -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) diff --git a/pkg/client/loadbalancer.go b/pkg/client/loadbalancer.go index cf19b85a..d7882a87 100644 --- a/pkg/client/loadbalancer.go +++ b/pkg/client/loadbalancer.go @@ -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) } diff --git a/pkg/client/node.go b/pkg/client/node.go index f1ea6d7e..7b5f6b24 100644 --- a/pkg/client/node.go +++ b/pkg/client/node.go @@ -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 } diff --git a/pkg/client/ports.go b/pkg/client/ports.go index bf412912..068cd84e 100644 --- a/pkg/client/ports.go +++ b/pkg/client/ports.go @@ -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" { diff --git a/pkg/client/registry.go b/pkg/client/registry.go index 1320ab15..e5d8695e 100644 --- a/pkg/client/registry.go +++ b/pkg/client/registry.go @@ -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 } diff --git a/pkg/client/tools.go b/pkg/client/tools.go index df1f7885..e07b2faf 100644 --- a/pkg/client/tools.go +++ b/pkg/client/tools.go @@ -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 diff --git a/pkg/config/config.go b/pkg/config/config.go index 853c69f1..34399d6d 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -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 diff --git a/pkg/config/jsonschema.go b/pkg/config/jsonschema.go index f0bd2ed3..c1c3cecd 100644 --- a/pkg/config/jsonschema.go +++ b/pkg/config/jsonschema.go @@ -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) diff --git a/pkg/config/merge.go b/pkg/config/merge.go index d69fb4c3..0a36f7c3 100644 --- a/pkg/config/merge.go +++ b/pkg/config/merge.go @@ -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 diff --git a/pkg/config/transform.go b/pkg/config/transform.go index 949448f7..acca7bb1 100644 --- a/pkg/config/transform.go +++ b/pkg/config/transform.go @@ -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) } } diff --git a/pkg/config/validate.go b/pkg/config/validate.go index a00fdc5f..bed7fad7 100644 --- a/pkg/config/validate.go +++ b/pkg/config/validate.go @@ -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) } } } diff --git a/pkg/runtimes/docker/container.go b/pkg/runtimes/docker/container.go index 956af92f..9e367c5e 100644 --- a/pkg/runtimes/docker/container.go +++ b/pkg/runtimes/docker/container.go @@ -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) } diff --git a/pkg/runtimes/docker/host.go b/pkg/runtimes/docker/host.go index 4c1d991b..dd67f77c 100644 --- a/pkg/runtimes/docker/host.go +++ b/pkg/runtimes/docker/host.go @@ -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 } diff --git a/pkg/runtimes/docker/image.go b/pkg/runtimes/docker/image.go index bf49950b..c2c0f44e 100644 --- a/pkg/runtimes/docker/image.go +++ b/pkg/runtimes/docker/image.go @@ -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 diff --git a/pkg/runtimes/docker/info.go b/pkg/runtimes/docker/info.go index 0666e645..e793a5f3 100644 --- a/pkg/runtimes/docker/info.go +++ b/pkg/runtimes/docker/info.go @@ -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{ diff --git a/pkg/runtimes/docker/kubeconfig.go b/pkg/runtimes/docker/kubeconfig.go index 85988edb..dc67ea31 100644 --- a/pkg/runtimes/docker/kubeconfig.go +++ b/pkg/runtimes/docker/kubeconfig.go @@ -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 diff --git a/pkg/runtimes/docker/network.go b/pkg/runtimes/docker/network.go index 92522c6b..0a912295 100644 --- a/pkg/runtimes/docker/network.go +++ b/pkg/runtimes/docker/network.go @@ -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) diff --git a/pkg/runtimes/docker/node.go b/pkg/runtimes/docker/node.go index 1cc859ab..e839b24b 100644 --- a/pkg/runtimes/docker/node.go +++ b/pkg/runtimes/docker/node.go @@ -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() diff --git a/pkg/runtimes/docker/util.go b/pkg/runtimes/docker/util.go index 042260e2..d5b41cfa 100644 --- a/pkg/runtimes/docker/util.go +++ b/pkg/runtimes/docker/util.go @@ -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() diff --git a/pkg/runtimes/docker/volume.go b/pkg/runtimes/docker/volume.go index adbd5b84..6166bf28 100644 --- a/pkg/runtimes/docker/volume.go +++ b/pkg/runtimes/docker/volume.go @@ -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 diff --git a/pkg/runtimes/util/volumes.go b/pkg/runtimes/util/volumes.go index cfa32bcf..36544920 100644 --- a/pkg/runtimes/util/volumes.go +++ b/pkg/runtimes/util/volumes.go @@ -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 } diff --git a/pkg/util/files.go b/pkg/util/files.go index 9e9d59e2..3d030916 100644 --- a/pkg/util/files.go +++ b/pkg/util/files.go @@ -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 diff --git a/pkg/util/filter.go b/pkg/util/filter.go index 6976a98e..689b0a4a 100644 --- a/pkg/util/filter.go +++ b/pkg/util/filter.go @@ -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) diff --git a/pkg/util/infofaker.go b/pkg/util/infofaker.go index b9255059..0804b8fa 100644 --- a/pkg/util/infofaker.go +++ b/pkg/util/infofaker.go @@ -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 } diff --git a/pkg/util/ports.go b/pkg/util/ports.go index 5fe92220..d060250f 100644 --- a/pkg/util/ports.go +++ b/pkg/util/ports.go @@ -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() diff --git a/version/version.go b/version/version.go index 19e62ec2..53f13d8b 100644 --- a/version/version.go +++ b/version/version.go @@ -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:")