[Enhancement] clusterDelete: proper node and network handling (#437)
This comes with several fixes/improvements - only consider containers that have the default object label (app=k3d) - handle network deletion - check if there are other k3d containers connected - if there are only registries, disconnect them - if there are non-registry nodes, leave everything as it is - if there are any containers connected, that are not automatically disconnected, log a warning and continue
This commit is contained in:
parent
ec20a1e549
commit
185ffcd34f
@ -100,6 +100,7 @@ func parseDeleteClusterCmd(cmd *cobra.Command, args []string) []*k3d.Cluster {
|
|||||||
if all, err := cmd.Flags().GetBool("all"); err != nil {
|
if all, err := cmd.Flags().GetBool("all"); err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
} else if all {
|
} else if all {
|
||||||
|
log.Infoln("Deleting all clusters...")
|
||||||
clusters, err = client.ClusterList(cmd.Context(), runtimes.SelectedRuntime)
|
clusters, err = client.ClusterList(cmd.Context(), runtimes.SelectedRuntime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
|
@ -67,7 +67,7 @@ Finally, we can create the cluster, mounting the CA file in the path we specifie
|
|||||||
|
|
||||||
### Using k3d-managed registries
|
### Using k3d-managed registries
|
||||||
|
|
||||||
!!! info "Not ported yet"
|
!!! info "Just ported!"
|
||||||
The k3d-managed registry is available again as of k3d v4.0.0 (January 2021)
|
The k3d-managed registry is available again as of k3d v4.0.0 (January 2021)
|
||||||
|
|
||||||
#### Create a dedicated registry together with your cluster
|
#### Create a dedicated registry together with your cluster
|
||||||
|
@ -39,6 +39,7 @@ import (
|
|||||||
config "github.com/rancher/k3d/v4/pkg/config/v1alpha1"
|
config "github.com/rancher/k3d/v4/pkg/config/v1alpha1"
|
||||||
k3drt "github.com/rancher/k3d/v4/pkg/runtimes"
|
k3drt "github.com/rancher/k3d/v4/pkg/runtimes"
|
||||||
"github.com/rancher/k3d/v4/pkg/runtimes/docker"
|
"github.com/rancher/k3d/v4/pkg/runtimes/docker"
|
||||||
|
runtimeErr "github.com/rancher/k3d/v4/pkg/runtimes/errors"
|
||||||
"github.com/rancher/k3d/v4/pkg/types"
|
"github.com/rancher/k3d/v4/pkg/types"
|
||||||
k3d "github.com/rancher/k3d/v4/pkg/types"
|
k3d "github.com/rancher/k3d/v4/pkg/types"
|
||||||
"github.com/rancher/k3d/v4/pkg/util"
|
"github.com/rancher/k3d/v4/pkg/util"
|
||||||
@ -100,7 +101,6 @@ func ClusterRun(ctx context.Context, runtime k3drt.Runtime, clusterConfig *confi
|
|||||||
|
|
||||||
// ClusterPrep takes care of the steps required before creating/starting the cluster containers
|
// ClusterPrep takes care of the steps required before creating/starting the cluster containers
|
||||||
func ClusterPrep(ctx context.Context, runtime k3drt.Runtime, clusterConfig *config.ClusterConfig) error {
|
func ClusterPrep(ctx context.Context, runtime k3drt.Runtime, clusterConfig *config.ClusterConfig) error {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up contexts
|
* Set up contexts
|
||||||
* Used for (early) termination (across API boundaries)
|
* Used for (early) termination (across API boundaries)
|
||||||
@ -139,6 +139,7 @@ func ClusterPrep(ctx context.Context, runtime k3drt.Runtime, clusterConfig *conf
|
|||||||
|
|
||||||
// Ensure referenced registries
|
// Ensure referenced registries
|
||||||
for _, reg := range clusterConfig.ClusterCreateOpts.Registries.Use {
|
for _, reg := range clusterConfig.ClusterCreateOpts.Registries.Use {
|
||||||
|
log.Debugf("Trying to find registry %s", reg.Host)
|
||||||
regNode, err := runtime.GetNode(ctx, &k3d.Node{Name: reg.Host})
|
regNode, err := runtime.GetNode(ctx, &k3d.Node{Name: reg.Host})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to find registry node '%s': %+v", reg.Host, err)
|
return fmt.Errorf("Failed to find registry node '%s': %+v", reg.Host, err)
|
||||||
@ -243,7 +244,6 @@ func ClusterPrepImageVolume(ctx context.Context, runtime k3drt.Runtime, cluster
|
|||||||
* Cluster-Wide volumes
|
* Cluster-Wide volumes
|
||||||
* - image volume (for importing images)
|
* - image volume (for importing images)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
imageVolumeName := fmt.Sprintf("%s-%s-images", k3d.DefaultObjectNamePrefix, cluster.Name)
|
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 {
|
if err := runtime.CreateVolume(ctx, imageVolumeName, map[string]string{k3d.LabelClusterName: cluster.Name}); err != nil {
|
||||||
log.Errorf("Failed to create image volume '%s' for cluster '%s'", imageVolumeName, cluster.Name)
|
log.Errorf("Failed to create image volume '%s' for cluster '%s'", imageVolumeName, cluster.Name)
|
||||||
@ -468,7 +468,7 @@ ClusterCreatOpts:
|
|||||||
fmt.Sprintf("WORKER_PROCESSES=%d", len(strings.Split(ports, ","))),
|
fmt.Sprintf("WORKER_PROCESSES=%d", len(strings.Split(ports, ","))),
|
||||||
},
|
},
|
||||||
Role: k3d.LoadBalancerRole,
|
Role: k3d.LoadBalancerRole,
|
||||||
Labels: k3d.DefaultObjectLabels, // TODO: createLoadBalancer: add more expressive labels
|
Labels: clusterCreateOpts.GlobalLabels, // TODO: createLoadBalancer: add more expressive labels
|
||||||
Network: cluster.Network.Name,
|
Network: cluster.Network.Name,
|
||||||
Restart: true,
|
Restart: true,
|
||||||
}
|
}
|
||||||
@ -491,6 +491,10 @@ ClusterCreatOpts:
|
|||||||
func ClusterDelete(ctx context.Context, runtime k3drt.Runtime, cluster *k3d.Cluster) error {
|
func ClusterDelete(ctx context.Context, runtime k3drt.Runtime, cluster *k3d.Cluster) error {
|
||||||
|
|
||||||
log.Infof("Deleting cluster '%s'", cluster.Name)
|
log.Infof("Deleting cluster '%s'", cluster.Name)
|
||||||
|
cluster, err := ClusterGet(ctx, runtime, cluster)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
log.Debugf("Cluster Details: %+v", cluster)
|
log.Debugf("Cluster Details: %+v", cluster)
|
||||||
|
|
||||||
failed := 0
|
failed := 0
|
||||||
@ -507,8 +511,32 @@ func ClusterDelete(ctx context.Context, runtime k3drt.Runtime, cluster *k3d.Clus
|
|||||||
if !cluster.Network.External {
|
if !cluster.Network.External {
|
||||||
log.Infof("Deleting cluster network '%s'", cluster.Network.Name)
|
log.Infof("Deleting cluster network '%s'", cluster.Network.Name)
|
||||||
if err := runtime.DeleteNetwork(ctx, cluster.Network.Name); err != nil {
|
if err := runtime.DeleteNetwork(ctx, cluster.Network.Name); err != nil {
|
||||||
if strings.HasSuffix(err.Error(), "active endpoints") {
|
if errors.Is(err, runtimeErr.ErrRuntimeNetworkNotEmpty) { // there are still containers connected to that network
|
||||||
log.Warningf("Failed to delete cluster network '%s' because it's still in use: is there another cluster using it?", cluster.Network.Name)
|
|
||||||
|
connectedNodes, err := runtime.GetNodesInNetwork(ctx, cluster.Network.Name) // check, if there are any k3d nodes connected to the cluster
|
||||||
|
if err != nil {
|
||||||
|
log.Warningf("Failed to check cluster network for connected nodes: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(connectedNodes) > 0 { // there are still k3d-managed containers (aka nodes) connected to the network
|
||||||
|
connectedRegistryNodes := util.FilterNodesByRole(connectedNodes, k3d.RegistryRole)
|
||||||
|
if len(connectedRegistryNodes) == len(connectedNodes) { // only registry node(s) left in the network
|
||||||
|
for _, node := range connectedRegistryNodes {
|
||||||
|
log.Debugf("Disconnecting registry node %s from the network...", node.Name)
|
||||||
|
if err := runtime.DisconnectNodeFromNetwork(ctx, node, cluster.Network.Name); err != nil {
|
||||||
|
log.Warnf("Failed to disconnect registry %s from network %s", node.Name, cluster.Network.Name)
|
||||||
|
} else {
|
||||||
|
if err := runtime.DeleteNetwork(ctx, cluster.Network.Name); err != nil {
|
||||||
|
log.Warningf("Failed to delete cluster network, even after disconnecting registry node(s): %+v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // besides the registry node(s), there are still other nodes... maybe they still need a registry
|
||||||
|
log.Debugf("There are some non-registry nodes left in the network")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Warningf("Failed to delete cluster network '%s' because it's still in use: is there another cluster using it?", cluster.Network.Name)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Warningf("Failed to delete cluster network '%s': '%+v'", cluster.Network.Name, err)
|
log.Warningf("Failed to delete cluster network '%s': '%+v'", cluster.Network.Name, err)
|
||||||
}
|
}
|
||||||
@ -535,14 +563,29 @@ func ClusterDelete(ctx context.Context, runtime k3drt.Runtime, cluster *k3d.Clus
|
|||||||
|
|
||||||
// ClusterList returns a list of all existing clusters
|
// ClusterList returns a list of all existing clusters
|
||||||
func ClusterList(ctx context.Context, runtime k3drt.Runtime) ([]*k3d.Cluster, error) {
|
func ClusterList(ctx context.Context, runtime k3drt.Runtime) ([]*k3d.Cluster, error) {
|
||||||
|
log.Traceln("Listing Clusters...")
|
||||||
nodes, err := runtime.GetNodesByLabel(ctx, k3d.DefaultObjectLabels)
|
nodes, err := runtime.GetNodesByLabel(ctx, k3d.DefaultObjectLabels)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorln("Failed to get clusters")
|
log.Errorln("Failed to get clusters")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Debugf("Found %d nodes", len(nodes))
|
||||||
|
if log.GetLevel() == log.TraceLevel {
|
||||||
|
for _, node := range nodes {
|
||||||
|
log.Tracef("Found node %s of role %s", node.Name, node.Role)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nodes = NodeFilterByRoles(nodes, k3d.ClusterInternalNodeRoles, k3d.ClusterExternalNodeRoles)
|
nodes = NodeFilterByRoles(nodes, k3d.ClusterInternalNodeRoles, k3d.ClusterExternalNodeRoles)
|
||||||
|
|
||||||
|
log.Tracef("Found %d cluster-internal nodes", len(nodes))
|
||||||
|
if log.GetLevel() == log.TraceLevel {
|
||||||
|
for _, node := range nodes {
|
||||||
|
log.Tracef("Found cluster-internal node %s of role %s belonging to cluster %s", node.Name, node.Role, node.Labels[k3d.LabelClusterName])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
clusters := []*k3d.Cluster{}
|
clusters := []*k3d.Cluster{}
|
||||||
// for each node, check, if we can add it to a cluster or add the cluster if it doesn't exist yet
|
// for each node, check, if we can add it to a cluster or add the cluster if it doesn't exist yet
|
||||||
for _, node := range nodes {
|
for _, node := range nodes {
|
||||||
@ -570,6 +613,7 @@ func ClusterList(ctx context.Context, runtime k3drt.Runtime) ([]*k3d.Cluster, er
|
|||||||
log.Warnln(err)
|
log.Warnln(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.Debugf("Found %d clusters", len(clusters))
|
||||||
return clusters, nil
|
return clusters, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,6 +222,11 @@ func TransformSimpleToClusterConfig(ctx context.Context, runtime runtimes.Runtim
|
|||||||
GlobalEnv: []string{}, // empty init
|
GlobalEnv: []string{}, // empty init
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure, that we have the default object labels
|
||||||
|
for k, v := range k3d.DefaultObjectLabels {
|
||||||
|
clusterCreateOpts.GlobalLabels[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Registries
|
* Registries
|
||||||
*/
|
*/
|
||||||
|
@ -41,3 +41,8 @@ func (d Containerd) DeleteNetwork(ctx context.Context, ID string) error {
|
|||||||
func (d Containerd) ConnectNodeToNetwork(ctx context.Context, node *k3d.Node, network string) error {
|
func (d Containerd) ConnectNodeToNetwork(ctx context.Context, node *k3d.Node, network string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DisconnectNodeFromNetwork disconnects a node from a network (u don't say :O)
|
||||||
|
func (d Containerd) DisconnectNodeFromNetwork(ctx context.Context, node *k3d.Node, network string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -137,3 +137,8 @@ func (d Containerd) ExecInNode(ctx context.Context, node *k3d.Node, cmd []string
|
|||||||
func (d Containerd) ExecInNodeGetLogs(ctx context.Context, node *k3d.Node, cmd []string) (*bufio.Reader, error) {
|
func (d Containerd) ExecInNodeGetLogs(ctx context.Context, node *k3d.Node, cmd []string) (*bufio.Reader, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNodesInNetwork returns all the nodes connected to a given network
|
||||||
|
func (d Containerd) GetNodesInNetwork(ctx context.Context, network string) ([]*k3d.Node, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
@ -25,12 +25,14 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
|
|
||||||
|
runtimeErr "github.com/rancher/k3d/v4/pkg/runtimes/errors"
|
||||||
k3d "github.com/rancher/k3d/v4/pkg/types"
|
k3d "github.com/rancher/k3d/v4/pkg/types"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
@ -94,7 +96,13 @@ func (d Docker) DeleteNetwork(ctx context.Context, ID string) error {
|
|||||||
defer docker.Close()
|
defer docker.Close()
|
||||||
|
|
||||||
// (3) delete network
|
// (3) delete network
|
||||||
return docker.NetworkRemove(ctx, ID)
|
if err := docker.NetworkRemove(ctx, ID); err != nil {
|
||||||
|
if strings.HasSuffix(err.Error(), "active endpoints") {
|
||||||
|
return runtimeErr.ErrRuntimeNetworkNotEmpty
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNetwork gets information about a network by its ID
|
// GetNetwork gets information about a network by its ID
|
||||||
@ -147,3 +155,29 @@ func (d Docker) ConnectNodeToNetwork(ctx context.Context, node *k3d.Node, networ
|
|||||||
// connect container to network
|
// connect container to network
|
||||||
return docker.NetworkConnect(ctx, networkResource.ID, container.ID, &network.EndpointSettings{})
|
return docker.NetworkConnect(ctx, networkResource.ID, container.ID, &network.EndpointSettings{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DisconnectNodeFromNetwork disconnects a node from a network (u don't say :O)
|
||||||
|
func (d Docker) DisconnectNodeFromNetwork(ctx context.Context, node *k3d.Node, networkName string) error {
|
||||||
|
// get container
|
||||||
|
container, err := getNodeContainer(ctx, node)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// get docker client
|
||||||
|
docker, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||||
|
if err != nil {
|
||||||
|
log.Errorln("Failed to create docker client")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer docker.Close()
|
||||||
|
|
||||||
|
// get network
|
||||||
|
networkResource, err := GetNetwork(ctx, networkName)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to get network '%s'", networkName)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return docker.NetworkDisconnect(ctx, networkResource.ID, container.ID, true)
|
||||||
|
}
|
||||||
|
@ -25,6 +25,7 @@ package docker
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -33,6 +34,7 @@ import (
|
|||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
|
runtimeErr "github.com/rancher/k3d/v4/pkg/runtimes/errors"
|
||||||
k3d "github.com/rancher/k3d/v4/pkg/types"
|
k3d "github.com/rancher/k3d/v4/pkg/types"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
@ -59,6 +61,7 @@ func (d Docker) CreateNode(ctx context.Context, node *k3d.Node) error {
|
|||||||
|
|
||||||
// DeleteNode deletes a node
|
// DeleteNode deletes a node
|
||||||
func (d Docker) DeleteNode(ctx context.Context, nodeSpec *k3d.Node) error {
|
func (d Docker) DeleteNode(ctx context.Context, nodeSpec *k3d.Node) error {
|
||||||
|
log.Debugf("Deleting node %s ...", nodeSpec.Name)
|
||||||
return removeContainer(ctx, nodeSpec.Name)
|
return removeContainer(ctx, nodeSpec.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,7 +221,7 @@ func (d Docker) GetNode(ctx context.Context, node *k3d.Node) (*k3d.Node, error)
|
|||||||
|
|
||||||
node, err = TranslateContainerDetailsToNode(containerDetails)
|
node, err = TranslateContainerDetailsToNode(containerDetails)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to translate container details for node '%s' to node object", node.Name)
|
log.Errorf("Failed to translate container '%s' to node object", containerDetails.Name)
|
||||||
return node, err
|
return node, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,10 +399,44 @@ func executeInNode(ctx context.Context, node *k3d.Node, cmd []string) (*types.Hi
|
|||||||
if execInfo.ExitCode == 0 { // success
|
if execInfo.ExitCode == 0 { // success
|
||||||
log.Debugf("Exec process in node '%s' exited with '0'", node.Name)
|
log.Debugf("Exec process in node '%s' exited with '0'", node.Name)
|
||||||
return &execConnection, nil
|
return &execConnection, nil
|
||||||
} else { // failed
|
|
||||||
return &execConnection, fmt.Errorf("Exec process in node '%s' failed with exit code '%d'", node.Name, execInfo.ExitCode)
|
|
||||||
}
|
}
|
||||||
|
return &execConnection, fmt.Errorf("Exec process in node '%s' failed with exit code '%d'", node.Name, execInfo.ExitCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNodesInNetwork returns all the nodes connected to a given network
|
||||||
|
func (d Docker) GetNodesInNetwork(ctx context.Context, network string) ([]*k3d.Node, error) {
|
||||||
|
// create docker client
|
||||||
|
docker, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||||
|
if err != nil {
|
||||||
|
log.Errorln("Failed to create docker client")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer docker.Close()
|
||||||
|
|
||||||
|
net, err := GetNetwork(ctx, network)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connectedNodes := []*k3d.Node{}
|
||||||
|
|
||||||
|
// loop over list of containers connected to this cluster and transform them into nodes internally
|
||||||
|
for cID := range net.Containers {
|
||||||
|
containerDetails, err := getContainerDetails(ctx, cID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
node, err := TranslateContainerDetailsToNode(containerDetails)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, runtimeErr.ErrRuntimeContainerUnknown) {
|
||||||
|
log.Tracef("GetNodesInNetwork: inspected non-k3d-managed container %s", containerDetails.Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
connectedNodes = append(connectedNodes, node)
|
||||||
|
}
|
||||||
|
|
||||||
|
return connectedNodes, nil
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ import (
|
|||||||
docker "github.com/docker/docker/api/types/container"
|
docker "github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
|
runtimeErr "github.com/rancher/k3d/v4/pkg/runtimes/errors"
|
||||||
k3d "github.com/rancher/k3d/v4/pkg/types"
|
k3d "github.com/rancher/k3d/v4/pkg/types"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
@ -135,6 +136,22 @@ func TranslateContainerToNode(cont *types.Container) (*k3d.Node, error) {
|
|||||||
// TranslateContainerDetailsToNode translates a docker containerJSON object into a k3d node representation
|
// TranslateContainerDetailsToNode translates a docker containerJSON object into a k3d node representation
|
||||||
func TranslateContainerDetailsToNode(containerDetails types.ContainerJSON) (*k3d.Node, error) {
|
func TranslateContainerDetailsToNode(containerDetails types.ContainerJSON) (*k3d.Node, error) {
|
||||||
|
|
||||||
|
// first, make sure, that it's actually a k3d managed container by checking if it has all the default labels
|
||||||
|
for k, v := range k3d.DefaultObjectLabels {
|
||||||
|
log.Tracef("TranslateContainerDetailsToNode: Checking for default object label %s=%s", k, v)
|
||||||
|
found := false
|
||||||
|
for lk, lv := range containerDetails.Config.Labels {
|
||||||
|
if lk == k && lv == v {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
log.Debugf("Container %s is missing default label %s=%s in label set %+v", containerDetails.Name, k, v, containerDetails.Config.Labels)
|
||||||
|
return nil, runtimeErr.ErrRuntimeContainerUnknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// restart -> we only set 'unless-stopped' upon cluster creation
|
// restart -> we only set 'unless-stopped' upon cluster creation
|
||||||
restart := false
|
restart := false
|
||||||
if containerDetails.HostConfig.RestartPolicy.IsAlways() || containerDetails.HostConfig.RestartPolicy.IsUnlessStopped() {
|
if containerDetails.HostConfig.RestartPolicy.IsAlways() || containerDetails.HostConfig.RestartPolicy.IsUnlessStopped() {
|
||||||
|
@ -45,11 +45,12 @@ func (d Docker) CreateVolume(ctx context.Context, name string, labels map[string
|
|||||||
// (1) create volume
|
// (1) create volume
|
||||||
volumeCreateOptions := volume.VolumeCreateBody{
|
volumeCreateOptions := volume.VolumeCreateBody{
|
||||||
Name: name,
|
Name: name,
|
||||||
Labels: k3d.DefaultObjectLabels,
|
Labels: labels,
|
||||||
Driver: "local", // TODO: allow setting driver + opts
|
Driver: "local", // TODO: allow setting driver + opts
|
||||||
DriverOpts: map[string]string{},
|
DriverOpts: map[string]string{},
|
||||||
}
|
}
|
||||||
for k, v := range labels {
|
|
||||||
|
for k, v := range k3d.DefaultObjectLabels {
|
||||||
volumeCreateOptions.Labels[k] = v
|
volumeCreateOptions.Labels[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
30
pkg/runtimes/errors/errors.go
Normal file
30
pkg/runtimes/errors/errors.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
Copyright © 2020 The k3d Author(s)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package runtimes
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
// ErrRuntimeNetworkNotEmpty describes an error that occurs because a network still has containers connected to it (e.g. cannot be deleted)
|
||||||
|
var ErrRuntimeNetworkNotEmpty = errors.New("network not empty")
|
||||||
|
|
||||||
|
// ErrRuntimeContainerUnknown describes the situation, where we're inspecting a container that's not obviously managed by k3d
|
||||||
|
var ErrRuntimeContainerUnknown = errors.New("container not managed by k3d: missing default label(s)")
|
@ -56,6 +56,7 @@ type Runtime interface {
|
|||||||
GetNodesByLabel(context.Context, map[string]string) ([]*k3d.Node, error)
|
GetNodesByLabel(context.Context, map[string]string) ([]*k3d.Node, error)
|
||||||
GetNode(context.Context, *k3d.Node) (*k3d.Node, error)
|
GetNode(context.Context, *k3d.Node) (*k3d.Node, error)
|
||||||
GetNodeStatus(context.Context, *k3d.Node) (bool, string, error)
|
GetNodeStatus(context.Context, *k3d.Node) (bool, string, error)
|
||||||
|
GetNodesInNetwork(context.Context, string) ([]*k3d.Node, error)
|
||||||
CreateNetworkIfNotPresent(context.Context, string) (string, bool, error) // @return NETWORK_NAME, EXISTS, ERROR
|
CreateNetworkIfNotPresent(context.Context, string) (string, bool, error) // @return NETWORK_NAME, EXISTS, ERROR
|
||||||
GetKubeconfig(context.Context, *k3d.Node) (io.ReadCloser, error)
|
GetKubeconfig(context.Context, *k3d.Node) (io.ReadCloser, error)
|
||||||
DeleteNetwork(context.Context, string) error
|
DeleteNetwork(context.Context, string) error
|
||||||
@ -72,7 +73,8 @@ type Runtime interface {
|
|||||||
CopyToNode(context.Context, string, string, *k3d.Node) error // @param context, source, destination, node
|
CopyToNode(context.Context, string, string, *k3d.Node) error // @param context, source, destination, node
|
||||||
WriteToNode(context.Context, []byte, string, *k3d.Node) error // @param context, content, destination, node
|
WriteToNode(context.Context, []byte, string, *k3d.Node) error // @param context, content, destination, node
|
||||||
GetHostIP(context.Context, string) (net.IP, error)
|
GetHostIP(context.Context, string) (net.IP, error)
|
||||||
ConnectNodeToNetwork(context.Context, *k3d.Node, string) error // @param context, node, network name
|
ConnectNodeToNetwork(context.Context, *k3d.Node, string) error // @param context, node, network name
|
||||||
|
DisconnectNodeFromNetwork(context.Context, *k3d.Node, string) error // @param context, node, network name
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRuntime checks, if a given name is represented by an implemented k3d runtime and returns it
|
// GetRuntime checks, if a given name is represented by an implemented k3d runtime and returns it
|
||||||
|
@ -174,3 +174,14 @@ func FilterNodes(nodes []*k3d.Node, filters []string) ([]*k3d.Node, error) {
|
|||||||
|
|
||||||
return filteredNodes, nil
|
return filteredNodes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FilterNodesByRole returns a stripped list of nodes which do match the given role
|
||||||
|
func FilterNodesByRole(nodes []*k3d.Node, role k3d.Role) []*k3d.Node {
|
||||||
|
filteredNodes := []*k3d.Node{}
|
||||||
|
for _, node := range nodes {
|
||||||
|
if node.Role == role {
|
||||||
|
filteredNodes = append(filteredNodes, node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filteredNodes
|
||||||
|
}
|
||||||
|
@ -35,7 +35,7 @@ var Version string
|
|||||||
var HelperVersionOverride string
|
var HelperVersionOverride string
|
||||||
|
|
||||||
// K3sVersion should contain the latest version tag of k3s (hardcoded at build time)
|
// K3sVersion should contain the latest version tag of k3s (hardcoded at build time)
|
||||||
var K3sVersion = "rancher/k3s:v1.20.0-k3s2"
|
var K3sVersion = "v1.20.0-k3s2"
|
||||||
|
|
||||||
// GetVersion returns the version for cli, it gets it from "git describe --tags" or returns "dev" when doing simple go build
|
// GetVersion returns the version for cli, it gets it from "git describe --tags" or returns "dev" when doing simple go build
|
||||||
func GetVersion() string {
|
func GetVersion() string {
|
||||||
|
Loading…
Reference in New Issue
Block a user