[Enhancement] Refactoring: normalize label flags (k3s node & runtime) (#598, @ejose19)

pull/656/head
ejose19 3 years ago committed by iwilltry42
parent 99fe3c75c4
commit 1deb0aa64d
No known key found for this signature in database
GPG Key ID: 7BA57AD1CFF16110
  1. 57
      cmd/cluster/clusterCreate.go
  2. 37
      cmd/node/nodeCreate.go
  3. 2
      cmd/node/nodeList.go
  4. 4
      cmd/registry/registryList.go
  5. 35
      cmd/util/runtimeLabels.go
  6. 40
      pkg/client/cluster.go
  7. 8
      pkg/client/kubeconfig.go
  8. 40
      pkg/client/node.go
  9. 10
      pkg/client/registry.go
  10. 20
      pkg/config/config_test.go
  11. 16
      pkg/config/test_assets/config_test_simple.yaml
  12. 18
      pkg/config/test_assets/config_test_simple_invalid_servers.yaml
  13. 44
      pkg/config/transform.go
  14. 9
      pkg/config/v1alpha3/migrations.go
  15. 52
      pkg/config/v1alpha3/schema.json
  16. 11
      pkg/config/v1alpha3/types.go
  17. 2
      pkg/runtimes/docker/container.go
  18. 2
      pkg/runtimes/docker/network.go
  19. 2
      pkg/runtimes/docker/node.go
  20. 44
      pkg/runtimes/docker/translate.go
  21. 6
      pkg/runtimes/docker/translate_test.go
  22. 2
      pkg/runtimes/docker/util.go
  23. 4
      pkg/runtimes/docker/volume.go
  24. 24
      pkg/tools/tools.go
  25. 10
      pkg/types/types.go
  26. 18
      tests/assets/config_test_simple.yaml
  27. 13
      tests/assets/config_test_simple_migration_v1alpha3.yaml
  28. 6
      tests/common.sh
  29. 6
      tests/test_config_file.sh
  30. 4
      tests/test_config_with_overrides.sh

@ -283,8 +283,11 @@ func NewCmdClusterCreate() *cobra.Command {
cmd.Flags().StringArrayP("port", "p", nil, "Map ports from the node containers to the host (Format: `[HOST:][HOSTPORT:]CONTAINERPORT[/PROTOCOL][@NODEFILTER]`)\n - Example: `k3d cluster create --agents 2 -p 8080:80@agent[0] -p 8081@agent[1]`") cmd.Flags().StringArrayP("port", "p", nil, "Map ports from the node containers to the host (Format: `[HOST:][HOSTPORT:]CONTAINERPORT[/PROTOCOL][@NODEFILTER]`)\n - Example: `k3d cluster create --agents 2 -p 8080:80@agent[0] -p 8081@agent[1]`")
_ = ppViper.BindPFlag("cli.ports", cmd.Flags().Lookup("port")) _ = ppViper.BindPFlag("cli.ports", cmd.Flags().Lookup("port"))
cmd.Flags().StringArrayP("label", "l", nil, "Add label to node container (Format: `KEY[=VALUE][@NODEFILTER[;NODEFILTER...]]`\n - Example: `k3d cluster create --agents 2 -l \"my.label@agent[0,1]\" -l \"other.label=somevalue@server[0]\"`") cmd.Flags().StringArrayP("k3s-node-label", "", nil, "Add label to k3s node (Format: `KEY[=VALUE][@NODEFILTER[;NODEFILTER...]]`\n - Example: `k3d cluster create --agents 2 --k3s-node-label \"my.label@agent[0,1]\" --k3s-node-label \"other.label=somevalue@server[0]\"`")
_ = ppViper.BindPFlag("cli.labels", cmd.Flags().Lookup("label")) _ = ppViper.BindPFlag("cli.k3s-node-labels", cmd.Flags().Lookup("k3s-node-label"))
cmd.Flags().StringArrayP("runtime-label", "", nil, "Add label to container runtime (Format: `KEY[=VALUE][@NODEFILTER[;NODEFILTER...]]`\n - Example: `k3d cluster create --agents 2 --runtime-label \"my.label@agent[0,1]\" --runtime-label \"other.label=somevalue@server[0]\"`")
_ = ppViper.BindPFlag("cli.runtime-labels", cmd.Flags().Lookup("runtime-label"))
/* k3s */ /* k3s */
cmd.Flags().StringArray("k3s-arg", nil, "Additional args passed to k3s command (Format: `ARG@NODEFILTER[;@NODEFILTER]`)\n - Example: `k3d cluster create --k3s-arg \"--disable=traefik@server[0]\"") cmd.Flags().StringArray("k3s-arg", nil, "Additional args passed to k3s command (Format: `ARG@NODEFILTER[;@NODEFILTER]`)\n - Example: `k3d cluster create --k3s-arg \"--disable=traefik@server[0]\"")
@ -481,10 +484,38 @@ func applyCLIOverrides(cfg conf.SimpleConfig) (conf.SimpleConfig, error) {
log.Tracef("PortFilterMap: %+v", portFilterMap) log.Tracef("PortFilterMap: %+v", portFilterMap)
// --label // --k3s-node-label
// labelFilterMap will add container label to applied node filters // k3sNodeLabelFilterMap will add k3s node label to applied node filters
labelFilterMap := make(map[string][]string, 1) k3sNodeLabelFilterMap := make(map[string][]string, 1)
for _, labelFlag := range ppViper.GetStringSlice("cli.labels") { for _, labelFlag := range ppViper.GetStringSlice("cli.k3s-node-labels") {
// split node filter from the specified label
label, nodeFilters, err := cliutil.SplitFiltersFromFlag(labelFlag)
if err != nil {
log.Fatalln(err)
}
// create new entry or append filter to existing entry
if _, exists := k3sNodeLabelFilterMap[label]; exists {
k3sNodeLabelFilterMap[label] = append(k3sNodeLabelFilterMap[label], nodeFilters...)
} else {
k3sNodeLabelFilterMap[label] = nodeFilters
}
}
for label, nodeFilters := range k3sNodeLabelFilterMap {
cfg.Options.K3sOptions.NodeLabels = append(cfg.Options.K3sOptions.NodeLabels, conf.LabelWithNodeFilters{
Label: label,
NodeFilters: nodeFilters,
})
}
log.Tracef("K3sNodeLabelFilterMap: %+v", k3sNodeLabelFilterMap)
// --runtime-label
// runtimeLabelFilterMap will add container runtime label to applied node filters
runtimeLabelFilterMap := make(map[string][]string, 1)
for _, labelFlag := range ppViper.GetStringSlice("cli.runtime-labels") {
// split node filter from the specified label // split node filter from the specified label
label, nodeFilters, err := cliutil.SplitFiltersFromFlag(labelFlag) label, nodeFilters, err := cliutil.SplitFiltersFromFlag(labelFlag)
@ -492,22 +523,24 @@ func applyCLIOverrides(cfg conf.SimpleConfig) (conf.SimpleConfig, error) {
log.Fatalln(err) log.Fatalln(err)
} }
cliutil.ValidateRuntimeLabelKey(strings.Split(label, "=")[0])
// create new entry or append filter to existing entry // create new entry or append filter to existing entry
if _, exists := labelFilterMap[label]; exists { if _, exists := runtimeLabelFilterMap[label]; exists {
labelFilterMap[label] = append(labelFilterMap[label], nodeFilters...) runtimeLabelFilterMap[label] = append(runtimeLabelFilterMap[label], nodeFilters...)
} else { } else {
labelFilterMap[label] = nodeFilters runtimeLabelFilterMap[label] = nodeFilters
} }
} }
for label, nodeFilters := range labelFilterMap { for label, nodeFilters := range runtimeLabelFilterMap {
cfg.Labels = append(cfg.Labels, conf.LabelWithNodeFilters{ cfg.Options.Runtime.Labels = append(cfg.Options.Runtime.Labels, conf.LabelWithNodeFilters{
Label: label, Label: label,
NodeFilters: nodeFilters, NodeFilters: nodeFilters,
}) })
} }
log.Tracef("LabelFilterMap: %+v", labelFilterMap) log.Tracef("RuntimeLabelFilterMap: %+v", runtimeLabelFilterMap)
// --env // --env
// envFilterMap will add container env vars to applied node filters // envFilterMap will add container env vars to applied node filters

@ -30,6 +30,7 @@ import (
dockerunits "github.com/docker/go-units" dockerunits "github.com/docker/go-units"
"github.com/rancher/k3d/v4/cmd/util" "github.com/rancher/k3d/v4/cmd/util"
cliutil "github.com/rancher/k3d/v4/cmd/util"
k3dc "github.com/rancher/k3d/v4/pkg/client" k3dc "github.com/rancher/k3d/v4/pkg/client"
"github.com/rancher/k3d/v4/pkg/runtimes" "github.com/rancher/k3d/v4/pkg/runtimes"
k3d "github.com/rancher/k3d/v4/pkg/types" k3d "github.com/rancher/k3d/v4/pkg/types"
@ -74,6 +75,7 @@ func NewCmdNodeCreate() *cobra.Command {
cmd.Flags().BoolVar(&createNodeOpts.Wait, "wait", false, "Wait for the node(s) to be ready before returning.") cmd.Flags().BoolVar(&createNodeOpts.Wait, "wait", false, "Wait for the node(s) to be ready before returning.")
cmd.Flags().DurationVar(&createNodeOpts.Timeout, "timeout", 0*time.Second, "Maximum waiting time for '--wait' before canceling/returning.") cmd.Flags().DurationVar(&createNodeOpts.Timeout, "timeout", 0*time.Second, "Maximum waiting time for '--wait' before canceling/returning.")
cmd.Flags().StringSliceP("runtime-label", "", []string{}, "Specify container runtime labels in format \"foo=bar\"")
cmd.Flags().StringSliceP("k3s-node-label", "", []string{}, "Specify k3s node labels in format \"foo=bar\"") cmd.Flags().StringSliceP("k3s-node-label", "", []string{}, "Specify k3s node labels in format \"foo=bar\"")
// done // done
@ -127,9 +129,30 @@ func parseCreateNodeCmd(cmd *cobra.Command, args []string) ([]*k3d.Node, *k3d.Cl
log.Errorf("Provided memory limit value is invalid") log.Errorf("Provided memory limit value is invalid")
} }
// --runtime-label
runtimeLabelsFlag, err := cmd.Flags().GetStringSlice("runtime-label")
if err != nil {
log.Errorln("No runtime-label specified")
log.Fatalln(err)
}
runtimeLabels := make(map[string]string, len(runtimeLabelsFlag)+1)
for _, label := range runtimeLabelsFlag {
labelSplitted := strings.Split(label, "=")
if len(labelSplitted) != 2 {
log.Fatalf("unknown runtime-label format format: %s, use format \"foo=bar\"", label)
}
cliutil.ValidateRuntimeLabelKey(labelSplitted[0])
runtimeLabels[labelSplitted[0]] = labelSplitted[1]
}
// Internal k3d runtime labels take precedence over user-defined labels
runtimeLabels[k3d.LabelRole] = roleStr
// --k3s-node-label
k3sNodeLabelsFlag, err := cmd.Flags().GetStringSlice("k3s-node-label") k3sNodeLabelsFlag, err := cmd.Flags().GetStringSlice("k3s-node-label")
if err != nil { if err != nil {
log.Errorln("No node-label specified") log.Errorln("No k3s-node-label specified")
log.Fatalln(err) log.Fatalln(err)
} }
@ -137,7 +160,7 @@ func parseCreateNodeCmd(cmd *cobra.Command, args []string) ([]*k3d.Node, *k3d.Cl
for _, label := range k3sNodeLabelsFlag { for _, label := range k3sNodeLabelsFlag {
labelSplitted := strings.Split(label, "=") labelSplitted := strings.Split(label, "=")
if len(labelSplitted) != 2 { if len(labelSplitted) != 2 {
log.Fatalf("unknown label format format: %s, use format \"foo=bar\"", label) log.Fatalf("unknown k3s-node-label format format: %s, use format \"foo=bar\"", label)
} }
k3sNodeLabels[labelSplitted[0]] = labelSplitted[1] k3sNodeLabels[labelSplitted[0]] = labelSplitted[1]
} }
@ -146,13 +169,11 @@ func parseCreateNodeCmd(cmd *cobra.Command, args []string) ([]*k3d.Node, *k3d.Cl
nodes := []*k3d.Node{} nodes := []*k3d.Node{}
for i := 0; i < replicas; i++ { for i := 0; i < replicas; i++ {
node := &k3d.Node{ node := &k3d.Node{
Name: fmt.Sprintf("%s-%s-%d", k3d.DefaultObjectNamePrefix, args[0], i), Name: fmt.Sprintf("%s-%s-%d", k3d.DefaultObjectNamePrefix, args[0], i),
Role: role, Role: role,
Image: image, Image: image,
Labels: map[string]string{
k3d.LabelRole: roleStr,
},
K3sNodeLabels: k3sNodeLabels, K3sNodeLabels: k3sNodeLabels,
RuntimeLabels: runtimeLabels,
Restart: true, Restart: true,
Memory: memory, Memory: memory,
} }

@ -88,7 +88,7 @@ func NewCmdNodeList() *cobra.Command {
fmt.Fprintf(tabwriter, "%s\t%s\t%s\t%s\n", fmt.Fprintf(tabwriter, "%s\t%s\t%s\t%s\n",
strings.TrimPrefix(node.Name, "/"), strings.TrimPrefix(node.Name, "/"),
string(node.Role), string(node.Role),
node.Labels[k3d.LabelClusterName], node.RuntimeLabels[k3d.LabelClusterName],
node.State.Status) node.State.Status)
})) }))
}, },

@ -88,8 +88,8 @@ func NewCmdRegistryList() *cobra.Command {
util.PrintNodes(existingNodes, registryListFlags.output, util.PrintNodes(existingNodes, registryListFlags.output,
headers, util.NodePrinterFunc(func(tabwriter *tabwriter.Writer, node *k3d.Node) { headers, util.NodePrinterFunc(func(tabwriter *tabwriter.Writer, node *k3d.Node) {
cluster := "*" cluster := "*"
if _, ok := node.Labels[k3d.LabelClusterName]; ok { if _, ok := node.RuntimeLabels[k3d.LabelClusterName]; ok {
cluster = node.Labels[k3d.LabelClusterName] cluster = node.RuntimeLabels[k3d.LabelClusterName]
} }
fmt.Fprintf(tabwriter, "%s\t%s\t%s\t%s\n", fmt.Fprintf(tabwriter, "%s\t%s\t%s\t%s\n",
strings.TrimPrefix(node.Name, "/"), strings.TrimPrefix(node.Name, "/"),

@ -0,0 +1,35 @@
/*
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 util
import (
"strings"
log "github.com/sirupsen/logrus"
)
// validateRuntimeLabelKey validates a given label key is not reserved for internal k3d usage
func ValidateRuntimeLabelKey(labelKey string) {
if strings.HasPrefix(labelKey, "k3s.") || strings.HasPrefix(labelKey, "k3d.") || labelKey == "app" {
log.Fatalf("runtime label \"%s\" is reserved for internal usage", labelKey)
}
}

@ -381,13 +381,13 @@ ClusterCreatOpts:
nodeSetup := func(node *k3d.Node, suffix int) error { nodeSetup := func(node *k3d.Node, suffix int) error {
// cluster specific settings // cluster specific settings
if node.Labels == nil { if node.RuntimeLabels == nil {
node.Labels = make(map[string]string) // TODO: maybe create an init function? node.RuntimeLabels = make(map[string]string) // TODO: maybe create an init function?
} }
// ensure global labels // ensure global labels
for k, v := range clusterCreateOpts.GlobalLabels { for k, v := range clusterCreateOpts.GlobalLabels {
node.Labels[k] = v node.RuntimeLabels[k] = v
} }
// ensure global env // ensure global env
@ -404,7 +404,7 @@ ClusterCreatOpts:
cluster.Network.IPAM.IPsUsed = append(cluster.Network.IPAM.IPsUsed, ip) // make sure that we're not reusing the same IP next time 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 node.IP.Static = true
node.IP.IP = ip node.IP.IP = ip
node.Labels[k3d.LabelNodeStaticIP] = ip.String() node.RuntimeLabels[k3d.LabelNodeStaticIP] = ip.String()
} }
node.ServerOpts.KubeAPI = cluster.KubeAPI node.ServerOpts.KubeAPI = cluster.KubeAPI
@ -412,7 +412,7 @@ ClusterCreatOpts:
// the cluster has an init server node, but its not this one, so connect it to the init node // the cluster has an init server node, but its not this one, so connect it to the init node
if cluster.InitNode != nil && !node.ServerOpts.IsInit { if cluster.InitNode != nil && !node.ServerOpts.IsInit {
node.Env = append(node.Env, fmt.Sprintf("K3S_URL=%s", connectionURL)) node.Env = append(node.Env, fmt.Sprintf("K3S_URL=%s", connectionURL))
node.Labels[k3d.LabelServerIsInit] = "false" // set label, that this server node is not the init server node.RuntimeLabels[k3d.LabelServerIsInit] = "false" // set label, that this server node is not the init server
} }
} else if node.Role == k3d.AgentRole { } else if node.Role == k3d.AgentRole {
@ -446,10 +446,10 @@ ClusterCreatOpts:
if cluster.InitNode != nil { if cluster.InitNode != nil {
log.Infoln("Creating initializing server node") log.Infoln("Creating initializing server node")
cluster.InitNode.Args = append(cluster.InitNode.Args, "--cluster-init") cluster.InitNode.Args = append(cluster.InitNode.Args, "--cluster-init")
if cluster.InitNode.Labels == nil { if cluster.InitNode.RuntimeLabels == nil {
cluster.InitNode.Labels = map[string]string{} cluster.InitNode.RuntimeLabels = map[string]string{}
} }
cluster.InitNode.Labels[k3d.LabelServerIsInit] = "true" // set label, that this server node is the init server cluster.InitNode.RuntimeLabels[k3d.LabelServerIsInit] = "true" // set label, that this server node is the init server
// in case the LoadBalancer was disabled, expose the API Port on the initializing server node // in case the LoadBalancer was disabled, expose the API Port on the initializing server node
if clusterCreateOpts.DisableLoadBalancer { if clusterCreateOpts.DisableLoadBalancer {
@ -547,10 +547,10 @@ ClusterCreatOpts:
fmt.Sprintf("PORTS=%s", strings.Join(ports, ",")), fmt.Sprintf("PORTS=%s", strings.Join(ports, ",")),
fmt.Sprintf("WORKER_PROCESSES=%d", len(ports)), fmt.Sprintf("WORKER_PROCESSES=%d", len(ports)),
}, },
Role: k3d.LoadBalancerRole, Role: k3d.LoadBalancerRole,
Labels: clusterCreateOpts.GlobalLabels, // TODO: createLoadBalancer: add more expressive labels RuntimeLabels: clusterCreateOpts.GlobalLabels, // TODO: createLoadBalancer: add more expressive labels
Networks: []string{cluster.Network.Name}, Networks: []string{cluster.Network.Name},
Restart: true, Restart: true,
} }
if len(udp_ports) > 0 { if len(udp_ports) > 0 {
lbNode.Env = append(lbNode.Env, fmt.Sprintf("UDP_PORTS=%s", strings.Join(udp_ports, ","))) lbNode.Env = append(lbNode.Env, fmt.Sprintf("UDP_PORTS=%s", strings.Join(udp_ports, ",")))
@ -673,7 +673,7 @@ 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...") log.Traceln("Listing Clusters...")
nodes, err := runtime.GetNodesByLabel(ctx, k3d.DefaultObjectLabels) nodes, err := runtime.GetNodesByLabel(ctx, k3d.DefaultRuntimeLabels)
if err != nil { if err != nil {
log.Errorln("Failed to get clusters") log.Errorln("Failed to get clusters")
return nil, err return nil, err
@ -691,7 +691,7 @@ func ClusterList(ctx context.Context, runtime k3drt.Runtime) ([]*k3d.Cluster, er
log.Tracef("Found %d cluster-internal nodes", len(nodes)) log.Tracef("Found %d cluster-internal nodes", len(nodes))
if log.GetLevel() == log.TraceLevel { if log.GetLevel() == log.TraceLevel {
for _, node := range nodes { 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]) log.Tracef("Found cluster-internal node %s of role %s belonging to cluster %s", node.Name, node.Role, node.RuntimeLabels[k3d.LabelClusterName])
} }
} }
@ -700,7 +700,7 @@ func ClusterList(ctx context.Context, runtime k3drt.Runtime) ([]*k3d.Cluster, er
for _, node := range nodes { for _, node := range nodes {
clusterExists := false clusterExists := false
for _, cluster := range clusters { for _, cluster := range clusters {
if node.Labels[k3d.LabelClusterName] == cluster.Name { // TODO: handle case, where this label doesn't exist if node.RuntimeLabels[k3d.LabelClusterName] == cluster.Name { // TODO: handle case, where this label doesn't exist
cluster.Nodes = append(cluster.Nodes, node) cluster.Nodes = append(cluster.Nodes, node)
clusterExists = true clusterExists = true
break break
@ -709,7 +709,7 @@ func ClusterList(ctx context.Context, runtime k3drt.Runtime) ([]*k3d.Cluster, er
// cluster is not in the list yet, so we add it with the current node as its first member // cluster is not in the list yet, so we add it with the current node as its first member
if !clusterExists { if !clusterExists {
clusters = append(clusters, &k3d.Cluster{ clusters = append(clusters, &k3d.Cluster{
Name: node.Labels[k3d.LabelClusterName], Name: node.RuntimeLabels[k3d.LabelClusterName],
Nodes: []*k3d.Node{node}, Nodes: []*k3d.Node{node},
}) })
} }
@ -734,7 +734,7 @@ func populateClusterFieldsFromLabels(cluster *k3d.Cluster) error {
// get the name of the cluster network // get the name of the cluster network
if cluster.Network.Name == "" { if cluster.Network.Name == "" {
if networkName, ok := node.Labels[k3d.LabelNetwork]; ok { if networkName, ok := node.RuntimeLabels[k3d.LabelNetwork]; ok {
cluster.Network.Name = networkName cluster.Network.Name = networkName
} }
} }
@ -742,7 +742,7 @@ func populateClusterFieldsFromLabels(cluster *k3d.Cluster) error {
// check if the network is external // check if the network is external
// since the struct value is a bool, initialized as false, we cannot check if it's unset // since the struct value is a bool, initialized as false, we cannot check if it's unset
if !cluster.Network.External && !networkExternalSet { if !cluster.Network.External && !networkExternalSet {
if networkExternalString, ok := node.Labels[k3d.LabelNetworkExternal]; ok { if networkExternalString, ok := node.RuntimeLabels[k3d.LabelNetworkExternal]; ok {
if networkExternal, err := strconv.ParseBool(networkExternalString); err == nil { if networkExternal, err := strconv.ParseBool(networkExternalString); err == nil {
cluster.Network.External = networkExternal cluster.Network.External = networkExternal
networkExternalSet = true networkExternalSet = true
@ -752,14 +752,14 @@ func populateClusterFieldsFromLabels(cluster *k3d.Cluster) error {
// get image volume // TODO: enable external image volumes the same way we do it with networks // get image volume // TODO: enable external image volumes the same way we do it with networks
if cluster.ImageVolume == "" { if cluster.ImageVolume == "" {
if imageVolumeName, ok := node.Labels[k3d.LabelImageVolume]; ok { if imageVolumeName, ok := node.RuntimeLabels[k3d.LabelImageVolume]; ok {
cluster.ImageVolume = imageVolumeName cluster.ImageVolume = imageVolumeName
} }
} }
// get k3s cluster's token // get k3s cluster's token
if cluster.Token == "" { if cluster.Token == "" {
if token, ok := node.Labels[k3d.LabelClusterToken]; ok { if token, ok := node.RuntimeLabels[k3d.LabelClusterToken]; ok {
cluster.Token = token cluster.Token = token
} }
} }

@ -131,11 +131,11 @@ func KubeconfigGet(ctx context.Context, runtime runtimes.Runtime, cluster *k3d.C
APIHost := k3d.DefaultAPIHost APIHost := k3d.DefaultAPIHost
for _, server := range serverNodes { for _, server := range serverNodes {
if _, ok := server.Labels[k3d.LabelServerAPIPort]; ok { if _, ok := server.RuntimeLabels[k3d.LabelServerAPIPort]; ok {
chosenServer = server chosenServer = server
APIPort = server.Labels[k3d.LabelServerAPIPort] APIPort = server.RuntimeLabels[k3d.LabelServerAPIPort]
if _, ok := server.Labels[k3d.LabelServerAPIHost]; ok { if _, ok := server.RuntimeLabels[k3d.LabelServerAPIHost]; ok {
APIHost = server.Labels[k3d.LabelServerAPIHost] APIHost = server.RuntimeLabels[k3d.LabelServerAPIHost]
} }
break break
} }

@ -59,8 +59,8 @@ func NodeAddToCluster(ctx context.Context, runtime runtimes.Runtime, node *k3d.N
node.Networks = []string{cluster.Network.Name} node.Networks = []string{cluster.Network.Name}
// skeleton // skeleton
if node.Labels == nil { if node.RuntimeLabels == nil {
node.Labels = map[string]string{ node.RuntimeLabels = map[string]string{
k3d.LabelRole: string(node.Role), k3d.LabelRole: string(node.Role),
} }
} }
@ -141,7 +141,7 @@ func NodeAddToCluster(ctx context.Context, runtime runtimes.Runtime, node *k3d.N
} }
} }
if !k3sURLFound { if !k3sURLFound {
if url, ok := node.Labels[k3d.LabelClusterURL]; ok { if url, ok := node.RuntimeLabels[k3d.LabelClusterURL]; ok {
node.Env = append(node.Env, fmt.Sprintf("K3S_URL=%s", url)) node.Env = append(node.Env, fmt.Sprintf("K3S_URL=%s", url))
} else { } else {
log.Warnln("Failed to find K3S_URL value!") log.Warnln("Failed to find K3S_URL value!")
@ -381,18 +381,22 @@ func NodeCreate(ctx context.Context, runtime runtimes.Runtime, node *k3d.Node, c
// ### Labels ### // ### Labels ###
labels := make(map[string]string) labels := make(map[string]string)
for k, v := range k3d.DefaultObjectLabels { for k, v := range k3d.DefaultRuntimeLabels {
labels[k] = v labels[k] = v
} }
for k, v := range k3d.DefaultObjectLabelsVar { for k, v := range k3d.DefaultRuntimeLabelsVar {
labels[k] = v labels[k] = v
} }
for k, v := range node.Labels { for k, v := range node.RuntimeLabels {
labels[k] = v labels[k] = v
} }
node.Labels = labels node.RuntimeLabels = labels
// second most important: the node role label // second most important: the node role label
node.Labels[k3d.LabelRole] = string(node.Role) node.RuntimeLabels[k3d.LabelRole] = string(node.Role)
for k, v := range node.K3sNodeLabels {
node.Args = append(node.Args, "--node-label", fmt.Sprintf("%s=%s", k, v))
}
// ### Environment ### // ### Environment ###
node.Env = append(node.Env, k3d.DefaultNodeEnv...) // append default node env vars node.Env = append(node.Env, k3d.DefaultNodeEnv...) // append default node env vars
@ -469,7 +473,7 @@ func NodeDelete(ctx context.Context, runtime runtimes.Runtime, node *k3d.Node, o
// update the server loadbalancer // update the server loadbalancer
if !opts.SkipLBUpdate && (node.Role == k3d.ServerRole || node.Role == k3d.AgentRole) { if !opts.SkipLBUpdate && (node.Role == k3d.ServerRole || node.Role == k3d.AgentRole) {
cluster, err := ClusterGet(ctx, runtime, &k3d.Cluster{Name: node.Labels[k3d.LabelClusterName]}) cluster, err := ClusterGet(ctx, runtime, &k3d.Cluster{Name: node.RuntimeLabels[k3d.LabelClusterName]})
if err != nil { if err != nil {
log.Errorf("Failed to find cluster for node '%s'", node.Name) log.Errorf("Failed to find cluster for node '%s'", node.Name)
return err return err
@ -493,10 +497,6 @@ func patchAgentSpec(node *k3d.Node) error {
node.Cmd = []string{"agent"} node.Cmd = []string{"agent"}
} }
for k, v := range node.K3sNodeLabels {
node.Args = append(node.Args, "--node-label", fmt.Sprintf("%s=%s", k, v))
}
return nil return nil
} }
@ -509,9 +509,9 @@ func patchServerSpec(node *k3d.Node, runtime runtimes.Runtime) error {
// Add labels and TLS SAN for the exposed API // Add labels and TLS SAN for the exposed API
// FIXME: For now, the labels concerning the API on the server nodes are only being used for configuring the kubeconfig // FIXME: For now, the labels concerning the API on the server nodes are only being used for configuring the kubeconfig
node.Labels[k3d.LabelServerAPIHostIP] = node.ServerOpts.KubeAPI.Binding.HostIP // TODO: maybe get docker machine IP here node.RuntimeLabels[k3d.LabelServerAPIHostIP] = node.ServerOpts.KubeAPI.Binding.HostIP // TODO: maybe get docker machine IP here
node.Labels[k3d.LabelServerAPIHost] = node.ServerOpts.KubeAPI.Host node.RuntimeLabels[k3d.LabelServerAPIHost] = node.ServerOpts.KubeAPI.Host
node.Labels[k3d.LabelServerAPIPort] = node.ServerOpts.KubeAPI.Binding.HostPort node.RuntimeLabels[k3d.LabelServerAPIPort] = node.ServerOpts.KubeAPI.Binding.HostPort
// If the runtime is docker, attempt to use the docker host // If the runtime is docker, attempt to use the docker host
if runtime == runtimes.Docker { if runtime == runtimes.Docker {
@ -519,19 +519,19 @@ func patchServerSpec(node *k3d.Node, runtime runtimes.Runtime) error {
if dockerHost != "" { if dockerHost != "" {
dockerHost = strings.Split(dockerHost, ":")[0] // remove the port dockerHost = strings.Split(dockerHost, ":")[0] // remove the port
log.Tracef("Using docker host %s", dockerHost) log.Tracef("Using docker host %s", dockerHost)
node.Labels[k3d.LabelServerAPIHostIP] = dockerHost node.RuntimeLabels[k3d.LabelServerAPIHostIP] = dockerHost
node.Labels[k3d.LabelServerAPIHost] = dockerHost node.RuntimeLabels[k3d.LabelServerAPIHost] = dockerHost
} }
} }
node.Args = append(node.Args, "--tls-san", node.Labels[k3d.LabelServerAPIHost]) // add TLS SAN for non default host name node.Args = append(node.Args, "--tls-san", node.RuntimeLabels[k3d.LabelServerAPIHost]) // add TLS SAN for non default host name
return nil return nil
} }
// NodeList returns a list of all existing clusters // NodeList returns a list of all existing clusters
func NodeList(ctx context.Context, runtime runtimes.Runtime) ([]*k3d.Node, error) { func NodeList(ctx context.Context, runtime runtimes.Runtime) ([]*k3d.Node, error) {
nodes, err := runtime.GetNodesByLabel(ctx, k3d.DefaultObjectLabels) nodes, err := runtime.GetNodesByLabel(ctx, k3d.DefaultRuntimeLabels)
if err != nil { if err != nil {
log.Errorln("Failed to get nodes") log.Errorln("Failed to get nodes")
return nil, err return nil, err

@ -77,7 +77,7 @@ func RegistryCreate(ctx context.Context, runtime runtimes.Runtime, reg *k3d.Regi
} }
// setup the node labels // setup the node labels
registryNode.Labels = map[string]string{ registryNode.RuntimeLabels = map[string]string{
k3d.LabelClusterName: reg.ClusterRef, k3d.LabelClusterName: reg.ClusterRef,
k3d.LabelRole: string(k3d.RegistryRole), k3d.LabelRole: string(k3d.RegistryRole),
k3d.LabelRegistryHost: reg.ExposureOpts.Host, // TODO: docker machine host? k3d.LabelRegistryHost: reg.ExposureOpts.Host, // TODO: docker machine host?
@ -85,11 +85,11 @@ func RegistryCreate(ctx context.Context, runtime runtimes.Runtime, reg *k3d.Regi
k3d.LabelRegistryPortExternal: reg.ExposureOpts.Binding.HostPort, k3d.LabelRegistryPortExternal: reg.ExposureOpts.Binding.HostPort,
k3d.LabelRegistryPortInternal: reg.ExposureOpts.Port.Port(), k3d.LabelRegistryPortInternal: reg.ExposureOpts.Port.Port(),
} }
for k, v := range k3d.DefaultObjectLabels { for k, v := range k3d.DefaultRuntimeLabels {
registryNode.Labels[k] = v registryNode.RuntimeLabels[k] = v
} }
for k, v := range k3d.DefaultObjectLabelsVar { for k, v := range k3d.DefaultRuntimeLabelsVar {
registryNode.Labels[k] = v registryNode.RuntimeLabels[k] = v
} }
// port // port

@ -64,12 +64,6 @@ func TestReadSimpleConfig(t *testing.T) {
NodeFilters: []string{"loadbalancer"}, NodeFilters: []string{"loadbalancer"},
}, },
}, },
Labels: []conf.LabelWithNodeFilters{
{
Label: "foo=bar",
NodeFilters: []string{"server[0]", "loadbalancer"},
},
},
Env: []conf.EnvVarWithNodeFilters{ Env: []conf.EnvVarWithNodeFilters{
{ {
EnvVar: "bar=baz", EnvVar: "bar=baz",
@ -90,11 +84,25 @@ func TestReadSimpleConfig(t *testing.T) {
NodeFilters: []string{"server[*]"}, NodeFilters: []string{"server[*]"},
}, },
}, },
NodeLabels: []conf.LabelWithNodeFilters{
{
Label: "foo=bar",
NodeFilters: []string{"server[0]", "loadbalancer"},
},
},
}, },
KubeconfigOptions: conf.SimpleConfigOptionsKubeconfig{ KubeconfigOptions: conf.SimpleConfigOptionsKubeconfig{
UpdateDefaultKubeconfig: true, UpdateDefaultKubeconfig: true,
SwitchCurrentContext: true, SwitchCurrentContext: true,
}, },
Runtime: conf.SimpleConfigOptionsRuntime{
Labels: []conf.LabelWithNodeFilters{
{
Label: "foo=bar",
NodeFilters: []string{"server[0]", "loadbalancer"},
},
},
},
}, },
} }

@ -22,11 +22,6 @@ env:
- envVar: bar=baz - envVar: bar=baz
nodeFilters: nodeFilters:
- all - all
labels:
- label: foo=bar
nodeFilters:
- "server[0]"
- loadbalancer
options: options:
k3d: k3d:
@ -39,6 +34,17 @@ options:
- arg: --tls-san=127.0.0.1 - arg: --tls-san=127.0.0.1
nodeFilters: nodeFilters:
- "server[*]" - "server[*]"
nodeLabels:
- label: foo=bar
nodeFilters:
- server[0]
- loadbalancer
kubeconfig: kubeconfig:
updateDefaultKubeconfig: true updateDefaultKubeconfig: true
switchCurrentContext: true switchCurrentContext: true
runtime:
labels:
- label: foo=bar
nodeFilters:
- server[0]
- loadbalancer

@ -22,11 +22,6 @@ env:
- envVar: bar=baz - envVar: bar=baz
nodeFilters: nodeFilters:
- all - all
labels:
- label: foo=bar
nodeFilters:
- server[0]
- loadbalancer
options: options:
k3d: k3d:
@ -39,6 +34,17 @@ options:
- arg: --tls-san=127.0.0.1 - arg: --tls-san=127.0.0.1
nodeFilters: nodeFilters:
- "server[*]" - "server[*]"
nodeLabels:
- label: foo=bar
nodeFilters:
- server[0]
- loadbalancer
kubeconfig: kubeconfig:
updateDefaultKubeconfig: true updateDefaultKubeconfig: true
switchCurrentContext: true switchCurrentContext: true
runtime:
labels:
- label: foo=bar
nodeFilters:
- server[0]
- loadbalancer

@ -190,23 +190,47 @@ func TransformSimpleToClusterConfig(ctx context.Context, runtime runtimes.Runtim
} }
} }
// -> LABELS // -> K3S NODE LABELS
for _, labelWithNodeFilters := range simpleConfig.Labels { for _, k3sNodeLabelWithNodeFilters := range simpleConfig.Options.K3sOptions.NodeLabels {
if len(labelWithNodeFilters.NodeFilters) == 0 && nodeCount > 1 { if len(k3sNodeLabelWithNodeFilters.NodeFilters) == 0 && nodeCount > 1 {
return nil, fmt.Errorf("Labelmapping '%s' lacks a node filter, but there's more than one node", labelWithNodeFilters.Label) return nil, fmt.Errorf("K3sNodeLabelmapping '%s' lacks a node filter, but there's more than one node", k3sNodeLabelWithNodeFilters.Label)
} }
nodes, err := util.FilterNodes(nodeList, labelWithNodeFilters.NodeFilters) nodes, err := util.FilterNodes(nodeList, k3sNodeLabelWithNodeFilters.NodeFilters)
if err != nil { if err != nil {
return nil, err return nil, err
} }
for _, node := range nodes { for _, node := range nodes {
if node.Labels == nil { if node.K3sNodeLabels == nil {
node.Labels = make(map[string]string) // ensure that the map is initialized node.K3sNodeLabels = make(map[string]string) // ensure that the map is initialized
} }
k, v := util.SplitLabelKeyValue(labelWithNodeFilters.Label) k, v := util.SplitLabelKeyValue(k3sNodeLabelWithNodeFilters.Label)
node.Labels[k] = v node.K3sNodeLabels[k] = v
}
}
// -> RUNTIME LABELS
for _, runtimeLabelWithNodeFilters := range simpleConfig.Options.Runtime.Labels {
if len(runtimeLabelWithNodeFilters.NodeFilters) == 0 && nodeCount > 1 {
return nil, fmt.Errorf("RuntimeLabelmapping '%s' lacks a node filter, but there's more than one node", runtimeLabelWithNodeFilters.Label)
}
nodes, err := util.FilterNodes(nodeList, runtimeLabelWithNodeFilters.NodeFilters)
if err != nil {
return nil, err
}
for _, node := range nodes {
if node.RuntimeLabels == nil {
node.RuntimeLabels = make(map[string]string) // ensure that the map is initialized
}
k, v := util.SplitLabelKeyValue(runtimeLabelWithNodeFilters.Label)
cliutil.ValidateRuntimeLabelKey(k)
node.RuntimeLabels[k] = v
} }
} }
@ -260,7 +284,7 @@ func TransformSimpleToClusterConfig(ctx context.Context, runtime runtimes.Runtim
} }
// ensure, that we have the default object labels // ensure, that we have the default object labels
for k, v := range k3d.DefaultObjectLabels { for k, v := range k3d.DefaultRuntimeLabels {
clusterCreateOpts.GlobalLabels[k] = v clusterCreateOpts.GlobalLabels[k] = v
} }

@ -49,6 +49,15 @@ func MigrateV1Alpha2(input configtypes.Config) (configtypes.Config, error) {
return nil, err return nil, err
} }
cfg.Options.Runtime.Labels = []LabelWithNodeFilters{}
for _, label := range input.(v1alpha2.SimpleConfig).Labels {
cfg.Options.Runtime.Labels = append(cfg.Options.Runtime.Labels, LabelWithNodeFilters{
Label: label.Label,
NodeFilters: label.NodeFilters,
})
}
cfg.Options.K3sOptions.ExtraArgs = []K3sArgWithNodeFilters{} cfg.Options.K3sOptions.ExtraArgs = []K3sArgWithNodeFilters{}
for _, arg := range input.(v1alpha2.SimpleConfig).Options.K3sOptions.ExtraServerArgs { for _, arg := range input.(v1alpha2.SimpleConfig).Options.K3sOptions.ExtraServerArgs {

@ -108,21 +108,6 @@
"additionalProperties": false "additionalProperties": false
} }
}, },
"labels": {
"type": "array",
"items": {
"type": "object",
"properties": {
"label": {
"type": "string"
},
"nodeFilters": {
"$ref": "#/definitions/nodeFilters"
}
},
"additionalProperties": false
}
},
"options": { "options": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -170,12 +155,24 @@
"properties": { "properties": {
"arg": { "arg": {
"type": "string", "type": "string",
"examples": [ "examples": ["--tls-san=127.0.0.1", "--disable=traefik"]
"--tls-san=127.0.0.1",
"--disable=traefik"
]
}, },
"nodeFilters": { "nodeFilters": {
"$ref": "#/definitions/nodeFilters"
}
},
"additionalProperties": false
}
},
"nodeLabels": {
"type": "array",
"items": {
"type": "object",
"properties": {
"label": {
"type": "string"
},
"nodeFilters": {
"$ref": "#/definitions/nodeFilters" "$ref": "#/definitions/nodeFilters"
} }
}, },
@ -210,6 +207,21 @@
}, },
"agentsMemory": { "agentsMemory": {
"type": "string" "type": "string"
},
"labels": {
"type": "array",
"items": {
"type": "object",
"properties": {
"label": {
"type": "string"
},
"nodeFilters": {
"$ref": "#/definitions/nodeFilters"
}
},
"additionalProperties": false
}
} }
} }
} }

@ -95,9 +95,10 @@ type SimpleConfigOptions struct {
} }
type SimpleConfigOptionsRuntime struct { type SimpleConfigOptionsRuntime struct {
GPURequest string `mapstructure:"gpuRequest" yaml:"gpuRequest"` GPURequest string `mapstructure:"gpuRequest" yaml:"gpuRequest"`
ServersMemory string `mapstructure:"serversMemory" yaml:"serversMemory"` ServersMemory string `mapstructure:"serversMemory" yaml:"serversMemory"`
AgentsMemory string `mapstructure:"agentsMemory" yaml:"agentsMemory"` AgentsMemory string `mapstructure:"agentsMemory" yaml:"agentsMemory"`
Labels []LabelWithNodeFilters `mapstructure:"labels" yaml:"labels"`
} }
type SimpleConfigOptionsK3d struct { type SimpleConfigOptionsK3d struct {
@ -111,7 +112,8 @@ type SimpleConfigOptionsK3d struct {
} }
type SimpleConfigOptionsK3s struct { type SimpleConfigOptionsK3s struct {
ExtraArgs []K3sArgWithNodeFilters `mapstructure:"extraArgs" yaml:"extraArgs"` ExtraArgs []K3sArgWithNodeFilters `mapstructure:"extraArgs" yaml:"extraArgs"`
NodeLabels []LabelWithNodeFilters `mapstructure:"nodeLabels" yaml:"nodeLabels"`
} }
// SimpleConfig describes the toplevel k3d configuration file. // SimpleConfig describes the toplevel k3d configuration file.
@ -127,7 +129,6 @@ type SimpleConfig struct {
ClusterToken string `mapstructure:"token" yaml:"clusterToken" json:"clusterToken,omitempty"` // default: auto-generated ClusterToken string `mapstructure:"token" yaml:"clusterToken" json:"clusterToken,omitempty"` // default: auto-generated
Volumes []VolumeWithNodeFilters `mapstructure:"volumes" yaml:"volumes" json:"volumes,omitempty"` Volumes []VolumeWithNodeFilters `mapstructure:"volumes" yaml:"volumes" json:"volumes,omitempty"`
Ports []PortWithNodeFilters `mapstructure:"ports" yaml:"ports" json:"ports,omitempty"` Ports []PortWithNodeFilters `mapstructure:"ports" yaml:"ports" json:"ports,omitempty"`
Labels []LabelWithNodeFilters `mapstructure:"labels" yaml:"labels" json:"labels,omitempty"`
Options SimpleConfigOptions `mapstructure:"options" yaml:"options" json:"options,omitempty"` Options SimpleConfigOptions `mapstructure:"options" yaml:"options" json:"options,omitempty"`
Env []EnvVarWithNodeFilters `mapstructure:"env" yaml:"env" json:"env,omitempty"` Env []EnvVarWithNodeFilters `mapstructure:"env" yaml:"env" json:"env,omitempty"`
Registries struct { Registries struct {

@ -151,7 +151,7 @@ func getNodeContainer(ctx context.Context, node *k3d.Node) (*types.Container, er
// (1) list containers which have the default k3d labels attached // (1) list containers which have the default k3d labels attached
filters := filters.NewArgs() filters := filters.NewArgs()
for k, v := range node.Labels { for k, v := range node.RuntimeLabels {
filters.Add("label", fmt.Sprintf("%s=%s", k, v)) filters.Add("label", fmt.Sprintf("%s=%s", k, v))
} }

@ -147,7 +147,7 @@ func (d Docker) CreateNetworkIfNotPresent(ctx context.Context, inNet *k3d.Cluste
// (3) Create a new network // (3) Create a new network
netCreateOpts := types.NetworkCreate{ netCreateOpts := types.NetworkCreate{
CheckDuplicate: true, CheckDuplicate: true,
Labels: k3d.DefaultObjectLabels, Labels: k3d.DefaultRuntimeLabels,
} }
// we want a managed (user-defined) network, but user didn't specify a subnet, so we try to auto-generate one // we want a managed (user-defined) network, but user didn't specify a subnet, so we try to auto-generate one

@ -178,7 +178,7 @@ func getContainersByLabel(ctx context.Context, labels map[string]string) ([]type
// (1) list containers which have the default k3d labels attached // (1) list containers which have the default k3d labels attached
filters := filters.NewArgs() filters := filters.NewArgs()
for k, v := range k3d.DefaultObjectLabels { for k, v := range k3d.DefaultRuntimeLabels {
filters.Add("label", fmt.Sprintf("%s=%s", k, v)) filters.Add("label", fmt.Sprintf("%s=%s", k, v))
} }
for k, v := range labels { for k, v := range labels {

@ -73,7 +73,7 @@ func TranslateNodeToContainer(node *k3d.Node) (*NodeInDocker, error) {
containerConfig.Env = node.Env containerConfig.Env = node.Env
/* Labels */ /* Labels */
containerConfig.Labels = node.Labels // has to include the role containerConfig.Labels = node.RuntimeLabels // has to include the role
/* Auto-Restart */ /* Auto-Restart */
if node.Restart { if node.Restart {
@ -162,10 +162,10 @@ func TranslateNodeToContainer(node *k3d.Node) (*NodeInDocker, error) {
// TranslateContainerToNode translates a docker container object into a k3d node representation // TranslateContainerToNode translates a docker container object into a k3d node representation
func TranslateContainerToNode(cont *types.Container) (*k3d.Node, error) { func TranslateContainerToNode(cont *types.Container) (*k3d.Node, error) {
node := &k3d.Node{ node := &k3d.Node{
Name: strings.TrimPrefix(cont.Names[0], "/"), // container name with leading '/' cut off Name: strings.TrimPrefix(cont.Names[0], "/"), // container name with leading '/' cut off
Image: cont.Image, Image: cont.Image,
Labels: cont.Labels, RuntimeLabels: cont.Labels,
Role: k3d.NodeRoles[cont.Labels[k3d.LabelRole]], Role: k3d.NodeRoles[cont.Labels[k3d.LabelRole]],
// TODO: all the rest // TODO: all the rest
} }
return node, nil return node, nil
@ -175,7 +175,7 @@ func TranslateContainerToNode(cont *types.Container) (*k3d.Node, error) {
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 // 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 { for k, v := range k3d.DefaultRuntimeLabels {
log.Tracef("TranslateContainerDetailsToNode: Checking for default object label %s=%s on container %s", k, v, containerDetails.Name) log.Tracef("TranslateContainerDetailsToNode: Checking for default object label %s=%s on container %s", k, v, containerDetails.Name)
found := false found := false
for lk, lv := range containerDetails.Config.Labels { for lk, lv := range containerDetails.Config.Labels {
@ -273,22 +273,22 @@ func TranslateContainerDetailsToNode(containerDetails types.ContainerJSON) (*k3d
} }
node := &k3d.Node{ node := &k3d.Node{
Name: strings.TrimPrefix(containerDetails.Name, "/"), // container name with leading '/' cut off Name: strings.TrimPrefix(containerDetails.Name, "/"), // container name with leading '/' cut off
Role: k3d.NodeRoles[containerDetails.Config.Labels[k3d.LabelRole]], Role: k3d.NodeRoles[containerDetails.Config.Labels[k3d.LabelRole]],
Image: containerDetails.Image, Image: containerDetails.Image,
Volumes: containerDetails.HostConfig.Binds, Volumes: containerDetails.HostConfig.Binds,
Env: env, Env: env,
Cmd: containerDetails.Config.Cmd, Cmd: containerDetails.Config.Cmd,
Args: []string{}, // empty, since Cmd already contains flags Args: []string{}, // empty, since Cmd already contains flags
Ports: containerDetails.HostConfig.PortBindings, Ports: containerDetails.HostConfig.PortBindings,
Restart: restart, Restart: restart,
Created: containerDetails.Created, Created: containerDetails.Created,
Labels: labels, RuntimeLabels: labels,
Networks: orderedNetworks, Networks: orderedNetworks,
ServerOpts: serverOpts, ServerOpts: serverOpts,
AgentOpts: k3d.AgentOpts{}, AgentOpts: k3d.AgentOpts{},
State: nodeState, State: nodeState,
Memory: memoryStr, Memory: memoryStr,
} }
return node, nil return node, nil
} }

@ -52,9 +52,9 @@ func TestTranslateNodeToContainer(t *testing.T) {
}, },
}, },
}, },
Restart: true, Restart: true,
Labels: map[string]string{k3d.LabelRole: string(k3d.ServerRole), "test_key_1": "test_val_1"}, RuntimeLabels: map[string]string{k3d.LabelRole: string(k3d.ServerRole), "test_key_1": "test_val_1"},
Networks: []string{"mynet"}, Networks: []string{"mynet"},
} }
init := true init := true

@ -44,7 +44,7 @@ import (
// GetDefaultObjectLabelsFilter returns docker type filters created from k3d labels // GetDefaultObjectLabelsFilter returns docker type filters created from k3d labels
func GetDefaultObjectLabelsFilter(clusterName string) filters.Args { func GetDefaultObjectLabelsFilter(clusterName string) filters.Args {
filters := filters.NewArgs() filters := filters.NewArgs()
for key, value := range k3d.DefaultObjectLabels { for key, value := range k3d.DefaultRuntimeLabels {
filters.Add("label", fmt.Sprintf("%s=%s", key, value)) filters.Add("label", fmt.Sprintf("%s=%s", key, value))
} }
filters.Add("label", fmt.Sprintf("%s=%s", k3d.LabelClusterName, clusterName)) filters.Add("label", fmt.Sprintf("%s=%s", k3d.LabelClusterName, clusterName))

@ -49,10 +49,10 @@ func (d Docker) CreateVolume(ctx context.Context, name string, labels map[string
DriverOpts: map[string]string{}, DriverOpts: map[string]string{},
} }
for k, v := range k3d.DefaultObjectLabels { for k, v := range k3d.DefaultRuntimeLabels {
volumeCreateOptions.Labels[k] = v volumeCreateOptions.Labels[k] = v
} }
for k, v := range k3d.DefaultObjectLabelsVar { for k, v := range k3d.DefaultRuntimeLabelsVar {
volumeCreateOptions.Labels[k] = v volumeCreateOptions.Labels[k] = v
} }

@ -65,7 +65,7 @@ func ImageImportIntoClusterMulti(ctx context.Context, runtime runtimes.Runtime,
var ok bool var ok bool
for _, node := range cluster.Nodes { for _, node := range cluster.Nodes {
if node.Role == k3d.ServerRole || node.Role == k3d.AgentRole { if node.Role == k3d.ServerRole || node.Role == k3d.AgentRole {
if imageVolume, ok = node.Labels[k3d.LabelImageVolume]; ok { if imageVolume, ok = node.RuntimeLabels[k3d.LabelImageVolume]; ok {
break break
} }
} }
@ -269,23 +269,23 @@ func containsVersionPart(imageTag string) bool {
// startToolsNode will start a new k3d tools container and connect it to the network of the chosen cluster // startToolsNode will start a new k3d tools container and connect it to the network of the chosen cluster
func startToolsNode(ctx context.Context, runtime runtimes.Runtime, cluster *k3d.Cluster, network string, volumes []string) (*k3d.Node, error) { func startToolsNode(ctx context.Context, runtime runtimes.Runtime, cluster *k3d.Cluster, network string, volumes []string) (*k3d.Node, error) {
labels := map[string]string{} labels := map[string]string{}
for k, v := range k3d.DefaultObjectLabels { for k, v := range k3d.DefaultRuntimeLabels {
labels[k] = v labels[k] = v
} }
for k, v := range k3d.DefaultObjectLabelsVar { for k, v := range k3d.DefaultRuntimeLabelsVar {
labels[k] = v labels[k] = v
} }
node := &k3d.Node{ node := &k3d.Node{
Name: fmt.Sprintf("%s-%s-tools", k3d.DefaultObjectNamePrefix, cluster.Name), Name: fmt.Sprintf("%s-%s-tools", k3d.DefaultObjectNamePrefix, cluster.Name),
Image: fmt.Sprintf("%s:%s", k3d.DefaultToolsImageRepo, version.GetHelperImageVersion()), Image: fmt.Sprintf("%s:%s", k3d.DefaultToolsImageRepo, version.GetHelperImageVersion()),
Role: k3d.NoRole, Role: k3d.NoRole,
Volumes: volumes, Volumes: volumes,
Networks: []string{network}, Networks: []string{network},
Cmd: []string{}, Cmd: []string{},
Args: []string{"noop"}, Args: []string{"noop"},
Labels: k3d.DefaultObjectLabels, RuntimeLabels: k3d.DefaultRuntimeLabels,
} }
node.Labels[k3d.LabelClusterName] = cluster.Name node.RuntimeLabels[k3d.LabelClusterName] = cluster.Name
if err := k3dc.NodeRun(ctx, runtime, node, k3d.NodeCreateOpts{}); err != nil { if err := k3dc.NodeRun(ctx, runtime, node, k3d.NodeCreateOpts{}); err != nil {
log.Errorf("Failed to create tools container for cluster '%s'", cluster.Name) log.Errorf("Failed to create tools container for cluster '%s'", cluster.Name)
return node, err return node, err

@ -105,13 +105,13 @@ var ClusterExternalNodeRoles = []Role{
RegistryRole, RegistryRole,
} }
// DefaultObjectLabels specifies a set of labels that will be attached to k3d objects by default // DefaultRuntimeLabels specifies a set of labels that will be attached to k3d runtime objects by default
var DefaultObjectLabels = map[string]string{ var DefaultRuntimeLabels = map[string]string{
"app": "k3d", "app": "k3d",
} }
// DefaultObjectLabelsVar specifies a set of labels that will be attached to k3d objects by default but are not static (e.g. across k3d versions) // DefaultRuntimeLabelsVar specifies a set of labels that will be attached to k3d runtime objects by default but are not static (e.g. across k3d versions)
var DefaultObjectLabelsVar = map[string]string{ var DefaultRuntimeLabelsVar = map[string]string{
"k3d.version": version.GetVersion(), "k3d.version": version.GetVersion(),
} }
@ -338,7 +338,7 @@ type Node struct {
Ports nat.PortMap `yaml:"portMappings" json:"portMappings,omitempty"` Ports nat.PortMap `yaml:"portMappings" json:"portMappings,omitempty"`
Restart bool `yaml:"restart" json:"restart,omitempty"` Restart bool `yaml:"restart" json:"restart,omitempty"`
Created string `yaml:"created" json:"created,omitempty"` Created string `yaml:"created" json:"created,omitempty"`
Labels map[string]string // filled automatically RuntimeLabels map[string]string `yaml:"runtimeLabels" json:"runtimeLabels,omitempty"`
K3sNodeLabels map[string]string `yaml:"k3sNodeLabels" json:"k3sNodeLabels,omitempty"` K3sNodeLabels map[string]string `yaml:"k3sNodeLabels" json:"k3sNodeLabels,omitempty"`
Networks []string // filled automatically Networks []string // filled automatically
ExtraHosts []string // filled automatically ExtraHosts []string // filled automatically

@ -22,11 +22,6 @@ env:
- envVar: bar=baz,bob - envVar: bar=baz,bob
nodeFilters: nodeFilters:
- all - all
labels:
- label: foo=bar
nodeFilters:
- server[0]
- loadbalancer
registries: registries:
create: true create: true
use: [] use: []
@ -47,6 +42,17 @@ options:
- arg: --tls-san=127.0.0.1 - arg: --tls-san=127.0.0.1
nodeFilters: nodeFilters:
- server[*] - server[*]
nodeLabels:
- label: foo=bar
nodeFilters:
- server[0]
- loadbalancer
kubeconfig: kubeconfig:
updateDefaultKubeconfig: true updateDefaultKubeconfig: true
switchCurrentContext: true switchCurrentContext: true
runtime:
labels:
- label: foo=bar
nodeFilters:
- server[0]
- loadbalancer

@ -22,11 +22,6 @@ env:
- envVar: bar=baz,bob - envVar: bar=baz,bob
nodeFilters: nodeFilters:
- all - all
labels:
- label: foo=bar
nodeFilters:
- server[0]
- loadbalancer
registries: registries:
create: true create: true
use: [] use: []
@ -49,4 +44,10 @@ options:
- server[*] - server[*]
kubeconfig: kubeconfig:
updateDefaultKubeconfig: true updateDefaultKubeconfig: true
switchCurrentContext: true switchCurrentContext: true
runtime:
labels:
- label: foo=bar
nodeFilters:
- server[0]
- loadbalancer

@ -175,4 +175,10 @@ docker_assert_container_label() {
# $1 = container/node name # $1 = container/node name
# $2 = label to assert # $2 = label to assert
docker inspect --format '{{ range $k, $v := .Config.Labels }}{{ printf "%s=%s\n" $k $v }}{{ end }}' "$1" | grep -E "^$2$" docker inspect --format '{{ range $k, $v := .Config.Labels }}{{ printf "%s=%s\n" $k $v }}{{ end }}' "$1" | grep -E "^$2$"
}
k3s_assert_node_label() {
# $1 = node name
# $2 = label to assert
kubectl get node "$1" --output go-template='{{ range $k, $v := .metadata.labels }}{{ printf "%s=%s\n" $k $v }}{{ end }}' | grep -E "^$2$"
} }

@ -18,7 +18,7 @@ fi
export CURRENT_STAGE="Test | config-file | $K3S_IMAGE_TAG" export CURRENT_STAGE="Test | config-file | $K3S_IMAGE_TAG"
clustername="ConfigTest" clustername="configtest"
highlight "[START] ConfigTest $EXTRA_TITLE" highlight "[START] ConfigTest $EXTRA_TITLE"
@ -45,6 +45,10 @@ exec_in_node "k3d-$clustername-server-0" "env" | grep "bar=baz,bob" || failed "E
info "Ensuring that container labels have been set as stated in the config" info "Ensuring that container labels have been set as stated in the config"
docker_assert_container_label "k3d-$clustername-server-0" "foo=bar" || failed "Expected label 'foo=bar' not present on container/node k3d-$clustername-server-0" docker_assert_container_label "k3d-$clustername-server-0" "foo=bar" || failed "Expected label 'foo=bar' not present on container/node k3d-$clustername-server-0"
## K3s Node Labels
info "Ensuring that k3s node labels have been set as stated in the config"
k3s_assert_node_label "k3d-$clustername-server-0" "foo=bar" || failed "Expected label 'foo=bar' not present on node k3d-$clustername-server-0"
## Registry Node ## Registry Node
info "Ensuring, that we have a registry node present" info "Ensuring, that we have a registry node present"
$EXE node list "k3d-$clustername-registry" || failed "Expected k3d-$clustername-registry to be present" $EXE node list "k3d-$clustername-registry" || failed "Expected k3d-$clustername-registry to be present"

@ -44,6 +44,10 @@ exec_in_node "k3d-$clustername-agent-1" "env" | grep "x=y" || failed "Expected e
info "Ensuring that container labels have been set as stated in the config" info "Ensuring that container labels have been set as stated in the config"
docker_assert_container_label "k3d-$clustername-server-0" "foo=bar" || failed "Expected label 'foo=bar' not present on container/node k3d-$clustername-server-0" docker_assert_container_label "k3d-$clustername-server-0" "foo=bar" || failed "Expected label 'foo=bar' not present on container/node k3d-$clustername-server-0"
## K3s Node Labels
info "Ensuring that k3s node labels have been set as stated in the config"
k3s_assert_node_label "k3d-$clustername-server-0" "foo=bar" || failed "Expected label 'foo=bar' not present on node k3d-$clustername-server-0"
## Registry Node ## Registry Node
info "Ensuring, that we DO NOT have a registry node present" info "Ensuring, that we DO NOT have a registry node present"
$EXE node list "k3d-$clustername-registry" && failed "Expected k3d-$clustername-registry to NOT be present" $EXE node list "k3d-$clustername-registry" && failed "Expected k3d-$clustername-registry to NOT be present"

Loading…
Cancel
Save