[BREAKING] Config File Enhancements: v1alpha3, migrations, generic k3s-args (#605)
Excerpt: - new version v1alpha3 with k3s extraArgs using node filters - reflected in CLI via --k3s-arg - new migration option to migrate (internally and via cli) from v1alpha2 to v1alpha3 - enhancements to how config files are being read - e2e tests for config file migration
This commit is contained in:
parent
296f24c9b7
commit
261ac0faf4
@ -38,7 +38,7 @@ import (
|
|||||||
cliutil "github.com/rancher/k3d/v4/cmd/util"
|
cliutil "github.com/rancher/k3d/v4/cmd/util"
|
||||||
k3dCluster "github.com/rancher/k3d/v4/pkg/client"
|
k3dCluster "github.com/rancher/k3d/v4/pkg/client"
|
||||||
"github.com/rancher/k3d/v4/pkg/config"
|
"github.com/rancher/k3d/v4/pkg/config"
|
||||||
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha2"
|
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||||
"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"
|
||||||
"github.com/rancher/k3d/v4/version"
|
"github.com/rancher/k3d/v4/version"
|
||||||
@ -77,11 +77,6 @@ func initConfig() {
|
|||||||
if _, err := os.Stat(configFile); err != nil {
|
if _, err := os.Stat(configFile); err != nil {
|
||||||
log.Fatalf("Failed to stat config file %s: %+v", configFile, err)
|
log.Fatalf("Failed to stat config file %s: %+v", configFile, err)
|
||||||
}
|
}
|
||||||
log.Tracef("Schema: %+v", conf.JSONSchema)
|
|
||||||
|
|
||||||
if err := config.ValidateSchemaFile(configFile, []byte(conf.JSONSchema)); err != nil {
|
|
||||||
log.Fatalf("Schema Validation failed for config file %s: %+v", configFile, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to read config into memory (viper map structure)
|
// try to read config into memory (viper map structure)
|
||||||
if err := cfgViper.ReadInConfig(); err != nil {
|
if err := cfgViper.ReadInConfig(); err != nil {
|
||||||
@ -92,7 +87,16 @@ func initConfig() {
|
|||||||
log.Fatalf("Failed to read config file %s: %+v", configFile, err)
|
log.Fatalf("Failed to read config file %s: %+v", configFile, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Using config file %s", cfgViper.ConfigFileUsed())
|
schema, err := config.GetSchemaByVersion(cfgViper.GetString("apiVersion"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Cannot validate config file %s: %+v", configFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := config.ValidateSchemaFile(configFile, schema); err != nil {
|
||||||
|
log.Fatalf("Schema Validation failed for config file %s: %+v", configFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("Using config file %s (%s#%s)", cfgViper.ConfigFileUsed(), strings.ToLower(cfgViper.GetString("apiVersion")), strings.ToLower(cfgViper.GetString("kind")))
|
||||||
}
|
}
|
||||||
if log.GetLevel() >= log.DebugLevel {
|
if log.GetLevel() >= log.DebugLevel {
|
||||||
c, _ := yaml.Marshal(cfgViper.AllSettings())
|
c, _ := yaml.Marshal(cfgViper.AllSettings())
|
||||||
@ -121,19 +125,35 @@ func NewCmdClusterCreate() *cobra.Command {
|
|||||||
/*************************
|
/*************************
|
||||||
* Compute Configuration *
|
* Compute Configuration *
|
||||||
*************************/
|
*************************/
|
||||||
cfg, err := config.FromViperSimple(cfgViper)
|
if cfgViper.GetString("apiversion") == "" {
|
||||||
|
cfgViper.Set("apiversion", config.DefaultConfigApiVersion)
|
||||||
|
}
|
||||||
|
if cfgViper.GetString("kind") == "" {
|
||||||
|
cfgViper.Set("kind", "Simple")
|
||||||
|
}
|
||||||
|
cfg, err := config.FromViper(cfgViper)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("========== Simple Config ==========\n%+v\n==========================\n", cfg)
|
if cfg.GetAPIVersion() != config.DefaultConfigApiVersion {
|
||||||
|
log.Warnf("Default config apiVersion is '%s', but you're using '%s': consider migrating.", config.DefaultConfigApiVersion, cfg.GetAPIVersion())
|
||||||
|
cfg, err = config.Migrate(cfg, config.DefaultConfigApiVersion)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cfg, err = applyCLIOverrides(cfg)
|
simpleCfg := cfg.(conf.SimpleConfig)
|
||||||
|
|
||||||
|
log.Debugf("========== Simple Config ==========\n%+v\n==========================\n", simpleCfg)
|
||||||
|
|
||||||
|
simpleCfg, err = applyCLIOverrides(simpleCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Failed to apply CLI overrides: %+v", err)
|
log.Fatalf("Failed to apply CLI overrides: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("========== Merged Simple Config ==========\n%+v\n==========================\n", cfg)
|
log.Debugf("========== Merged Simple Config ==========\n%+v\n==========================\n", simpleCfg)
|
||||||
|
|
||||||
/**************************************
|
/**************************************
|
||||||
* Transform, Process & Validate Configuration *
|
* Transform, Process & Validate Configuration *
|
||||||
@ -141,10 +161,10 @@ func NewCmdClusterCreate() *cobra.Command {
|
|||||||
|
|
||||||
// Set the name
|
// Set the name
|
||||||
if len(args) != 0 {
|
if len(args) != 0 {
|
||||||
cfg.Name = args[0]
|
simpleCfg.Name = args[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
clusterConfig, err := config.TransformSimpleToClusterConfig(cmd.Context(), runtimes.SelectedRuntime, cfg)
|
clusterConfig, err := config.TransformSimpleToClusterConfig(cmd.Context(), runtimes.SelectedRuntime, simpleCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
@ -178,7 +198,7 @@ func NewCmdClusterCreate() *cobra.Command {
|
|||||||
if err := k3dCluster.ClusterRun(cmd.Context(), runtimes.SelectedRuntime, clusterConfig); err != nil {
|
if err := k3dCluster.ClusterRun(cmd.Context(), runtimes.SelectedRuntime, clusterConfig); err != nil {
|
||||||
// rollback if creation failed
|
// rollback if creation failed
|
||||||
log.Errorln(err)
|
log.Errorln(err)
|
||||||
if cfg.Options.K3dOptions.NoRollback { // TODO: move rollback mechanics to pkg/
|
if simpleCfg.Options.K3dOptions.NoRollback { // TODO: move rollback mechanics to pkg/
|
||||||
log.Fatalln("Cluster creation FAILED, rollback deactivated.")
|
log.Fatalln("Cluster creation FAILED, rollback deactivated.")
|
||||||
}
|
}
|
||||||
// rollback if creation failed
|
// rollback if creation failed
|
||||||
@ -202,7 +222,7 @@ func NewCmdClusterCreate() *cobra.Command {
|
|||||||
|
|
||||||
if clusterConfig.KubeconfigOpts.UpdateDefaultKubeconfig {
|
if clusterConfig.KubeconfigOpts.UpdateDefaultKubeconfig {
|
||||||
log.Debugf("Updating default kubeconfig with a new context for cluster %s", clusterConfig.Cluster.Name)
|
log.Debugf("Updating default kubeconfig with a new context for cluster %s", clusterConfig.Cluster.Name)
|
||||||
if _, err := k3dCluster.KubeconfigGetWrite(cmd.Context(), runtimes.SelectedRuntime, &clusterConfig.Cluster, "", &k3dCluster.WriteKubeConfigOptions{UpdateExisting: true, OverwriteExisting: false, UpdateCurrentContext: cfg.Options.KubeconfigOptions.SwitchCurrentContext}); err != nil {
|
if _, err := k3dCluster.KubeconfigGetWrite(cmd.Context(), runtimes.SelectedRuntime, &clusterConfig.Cluster, "", &k3dCluster.WriteKubeConfigOptions{UpdateExisting: true, OverwriteExisting: false, UpdateCurrentContext: simpleCfg.Options.KubeconfigOptions.SwitchCurrentContext}); err != nil {
|
||||||
log.Warningln(err)
|
log.Warningln(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -266,6 +286,10 @@ func NewCmdClusterCreate() *cobra.Command {
|
|||||||
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("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]\"`")
|
||||||
_ = ppViper.BindPFlag("cli.labels", cmd.Flags().Lookup("label"))
|
_ = ppViper.BindPFlag("cli.labels", cmd.Flags().Lookup("label"))
|
||||||
|
|
||||||
|
/* 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]\"")
|
||||||
|
_ = cfgViper.BindPFlag("cli.k3sargs", cmd.Flags().Lookup("k3s-arg"))
|
||||||
|
|
||||||
/******************
|
/******************
|
||||||
* "Normal" Flags *
|
* "Normal" Flags *
|
||||||
******************
|
******************
|
||||||
@ -340,13 +364,6 @@ func NewCmdClusterCreate() *cobra.Command {
|
|||||||
cmd.Flags().String("registry-config", "", "Specify path to an extra registries.yaml file")
|
cmd.Flags().String("registry-config", "", "Specify path to an extra registries.yaml file")
|
||||||
_ = cfgViper.BindPFlag("registries.config", cmd.Flags().Lookup("registry-config"))
|
_ = cfgViper.BindPFlag("registries.config", cmd.Flags().Lookup("registry-config"))
|
||||||
|
|
||||||
/* k3s */
|
|
||||||
cmd.Flags().StringArray("k3s-server-arg", nil, "Additional args passed to the `k3s server` command on server nodes (new flag per arg)")
|
|
||||||
_ = cfgViper.BindPFlag("options.k3s.extraserverargs", cmd.Flags().Lookup("k3s-server-arg"))
|
|
||||||
|
|
||||||
cmd.Flags().StringArray("k3s-agent-arg", nil, "Additional args passed to the `k3s agent` command on agent nodes (new flag per arg)")
|
|
||||||
_ = cfgViper.BindPFlag("options.k3s.extraagentargs", cmd.Flags().Lookup("k3s-agent-arg"))
|
|
||||||
|
|
||||||
/* Subcommands */
|
/* Subcommands */
|
||||||
|
|
||||||
// done
|
// done
|
||||||
@ -520,5 +537,30 @@ func applyCLIOverrides(cfg conf.SimpleConfig) (conf.SimpleConfig, error) {
|
|||||||
|
|
||||||
log.Tracef("EnvFilterMap: %+v", envFilterMap)
|
log.Tracef("EnvFilterMap: %+v", envFilterMap)
|
||||||
|
|
||||||
|
// --k3s-arg
|
||||||
|
argFilterMap := make(map[string][]string, 1)
|
||||||
|
for _, argFlag := range ppViper.GetStringSlice("cli.k3sargs") {
|
||||||
|
|
||||||
|
// split node filter from the specified arg
|
||||||
|
arg, filters, err := cliutil.SplitFiltersFromFlag(argFlag)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create new entry or append filter to existing entry
|
||||||
|
if _, exists := argFilterMap[arg]; exists {
|
||||||
|
argFilterMap[arg] = append(argFilterMap[arg], filters...)
|
||||||
|
} else {
|
||||||
|
argFilterMap[arg] = filters
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for arg, nodeFilters := range argFilterMap {
|
||||||
|
cfg.Options.K3sOptions.ExtraArgs = append(cfg.Options.K3sOptions.ExtraArgs, conf.K3sArgWithNodeFilters{
|
||||||
|
Arg: arg,
|
||||||
|
NodeFilters: nodeFilters,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ func NewCmdConfig() *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmd.AddCommand(NewCmdConfigInit())
|
cmd.AddCommand(NewCmdConfigInit())
|
||||||
|
cmd.AddCommand(NewCmdConfigMigrate())
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
config "github.com/rancher/k3d/v4/pkg/config/v1alpha2"
|
config "github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
111
cmd/config/configMigrate.go
Normal file
111
cmd/config/configMigrate.go
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
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 config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/rancher/k3d/v4/pkg/config"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewCmdConfigMigrate returns a new cobra command
|
||||||
|
func NewCmdConfigMigrate() *cobra.Command {
|
||||||
|
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "migrate INPUT OUTPUT",
|
||||||
|
Args: cobra.RangeArgs(1, 2),
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
|
configFile := args[0]
|
||||||
|
|
||||||
|
if _, err := os.Stat(configFile); err != nil {
|
||||||
|
log.Fatalf("Failed to stat config file %s: %+v", configFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfgViper := viper.New()
|
||||||
|
cfgViper.SetConfigType("yaml")
|
||||||
|
|
||||||
|
cfgViper.SetConfigFile(configFile)
|
||||||
|
|
||||||
|
// try to read config into memory (viper map structure)
|
||||||
|
if err := cfgViper.ReadInConfig(); err != nil {
|
||||||
|
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
|
||||||
|
log.Fatalf("Config file %s not found: %+v", configFile, err)
|
||||||
|
}
|
||||||
|
// config file found but some other error happened
|
||||||
|
log.Fatalf("Failed to read config file %s: %+v", configFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
schema, err := config.GetSchemaByVersion(cfgViper.GetString("apiVersion"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Cannot validate config file %s: %+v", configFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := config.ValidateSchemaFile(configFile, schema); err != nil {
|
||||||
|
log.Fatalf("Schema Validation failed for config file %s: %+v", configFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("Using config file %s (%s#%s)", cfgViper.ConfigFileUsed(), strings.ToLower(cfgViper.GetString("apiVersion")), strings.ToLower(cfgViper.GetString("kind")))
|
||||||
|
|
||||||
|
cfg, err := config.FromViper(cfgViper)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.GetAPIVersion() != config.DefaultConfigApiVersion {
|
||||||
|
cfg, err = config.Migrate(cfg, config.DefaultConfigApiVersion)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yamlout, err := yaml.Marshal(cfg)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
output := "-"
|
||||||
|
|
||||||
|
if len(args) > 1 {
|
||||||
|
output = args[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if output == "-" {
|
||||||
|
if _, err := os.Stdout.Write(yamlout); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := os.WriteFile(output, yamlout, os.ModeAppend); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
@ -6,6 +6,8 @@ The code will output files in [`../docs/usage/commands/`](../docs/usage/commands
|
|||||||
|
|
||||||
## Run
|
## Run
|
||||||
|
|
||||||
|
- may required a `replace github.com/rancher/k3d/v4 => PATH/TO/LOCAL/REPO` in the `go.mod`
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# ensure that you're in the docgen dir, as the relative path to the docs/ dir is hardcoded
|
# ensure that you're in the docgen dir, as the relative path to the docs/ dir is hardcoded
|
||||||
cd docgen
|
cd docgen
|
||||||
|
@ -29,8 +29,8 @@ k3d cluster create NAME [flags]
|
|||||||
--gpus string GPU devices to add to the cluster node containers ('all' to pass all GPUs) [From docker]
|
--gpus string GPU devices to add to the cluster node containers ('all' to pass all GPUs) [From docker]
|
||||||
-h, --help help for create
|
-h, --help help for create
|
||||||
-i, --image string Specify k3s image that you want to use for the nodes
|
-i, --image string Specify k3s image that you want to use for the nodes
|
||||||
--k3s-agent-arg k3s agent Additional args passed to the k3s agent command on agent nodes (new flag per arg)
|
--k3s-arg ARG@NODEFILTER[;@NODEFILTER] Additional args passed to k3s command (Format: ARG@NODEFILTER[;@NODEFILTER])
|
||||||
--k3s-server-arg k3s server Additional args passed to the k3s server command on server nodes (new flag per arg)
|
- Example: `k3d cluster create --k3s-arg "--disable=traefik@server[0]"
|
||||||
--kubeconfig-switch-context Directly switch the default kubeconfig's current-context to the new cluster's context (requires --kubeconfig-update-default) (default true)
|
--kubeconfig-switch-context Directly switch the default kubeconfig's current-context to the new cluster's context (requires --kubeconfig-update-default) (default true)
|
||||||
--kubeconfig-update-default Directly update the default kubeconfig with the new cluster's context (default true)
|
--kubeconfig-update-default Directly update the default kubeconfig with the new cluster's context (default true)
|
||||||
-l, --label KEY[=VALUE][@NODEFILTER[;NODEFILTER...]] Add label to node container (Format: KEY[=VALUE][@NODEFILTER[;NODEFILTER...]]
|
-l, --label KEY[=VALUE][@NODEFILTER[;NODEFILTER...]] Add label to node container (Format: KEY[=VALUE][@NODEFILTER[;NODEFILTER...]]
|
||||||
|
@ -28,4 +28,5 @@ k3d config [flags]
|
|||||||
|
|
||||||
* [k3d](k3d.md) - https://k3d.io/ -> Run k3s in Docker!
|
* [k3d](k3d.md) - https://k3d.io/ -> Run k3s in Docker!
|
||||||
* [k3d config init](k3d_config_init.md) -
|
* [k3d config init](k3d_config_init.md) -
|
||||||
|
* [k3d config migrate](k3d_config_migrate.md) -
|
||||||
|
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
## k3d docgen
|
## k3d config migrate
|
||||||
|
|
||||||
|
|
||||||
Generate command docs
|
|
||||||
|
|
||||||
```
|
```
|
||||||
k3d docgen [flags]
|
k3d config migrate INPUT OUTPUT [flags]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Options
|
### Options
|
||||||
|
|
||||||
```
|
```
|
||||||
-h, --help help for docgen
|
-h, --help help for migrate
|
||||||
```
|
```
|
||||||
|
|
||||||
### Options inherited from parent commands
|
### Options inherited from parent commands
|
||||||
@ -22,5 +22,5 @@ k3d docgen [flags]
|
|||||||
|
|
||||||
### SEE ALSO
|
### SEE ALSO
|
||||||
|
|
||||||
* [k3d](k3d.md) - https://k3d.io/ -> Run k3s in Docker!
|
* [k3d config](k3d_config.md) - Work with config file(s)
|
||||||
|
|
@ -13,14 +13,15 @@ k3d node create NAME [flags]
|
|||||||
### Options
|
### Options
|
||||||
|
|
||||||
```
|
```
|
||||||
-c, --cluster string Select the cluster that the node shall connect to. (default "k3s-default")
|
-c, --cluster string Select the cluster that the node shall connect to. (default "k3s-default")
|
||||||
-h, --help help for create
|
-h, --help help for create
|
||||||
-i, --image string Specify k3s image used for the node(s) (default "docker.io/rancher/k3s:v1.20.0-k3s2")
|
-i, --image string Specify k3s image used for the node(s) (default "docker.io/rancher/k3s:v1.20.0-k3s2")
|
||||||
--memory string Memory limit imposed on the node [From docker]
|
--k3s-node-label strings Specify k3s node labels in format "foo=bar"
|
||||||
--replicas int Number of replicas of this node specification. (default 1)
|
--memory string Memory limit imposed on the node [From docker]
|
||||||
--role string Specify node role [server, agent] (default "agent")
|
--replicas int Number of replicas of this node specification. (default 1)
|
||||||
--timeout duration Maximum waiting time for '--wait' before canceling/returning.
|
--role string Specify node role [server, agent] (default "agent")
|
||||||
--wait Wait for the node(s) to be ready before returning.
|
--timeout duration Maximum waiting time for '--wait' before canceling/returning.
|
||||||
|
--wait Wait for the node(s) to be ready before returning.
|
||||||
```
|
```
|
||||||
|
|
||||||
### Options inherited from parent commands
|
### Options inherited from parent commands
|
||||||
|
@ -25,13 +25,13 @@ Using a config file is as easy as putting it in a well-known place in your file
|
|||||||
|
|
||||||
As of the time of writing this documentation, the config file only **requires** you to define two fields:
|
As of the time of writing this documentation, the config file only **requires** you to define two fields:
|
||||||
|
|
||||||
- `apiVersion` to match the version of the config file that you want to use (at this time it would be `apiVersion: k3d.io/v1alpha2`)
|
- `apiVersion` to match the version of the config file that you want to use (at this time it would be `apiVersion: k3d.io/v1alpha3`)
|
||||||
- `kind` to define the kind of config file that you want to use (currently we only have the `Simple` config)
|
- `kind` to define the kind of config file that you want to use (currently we only have the `Simple` config)
|
||||||
|
|
||||||
So this would be the minimal config file, which configures absolutely nothing:
|
So this would be the minimal config file, which configures absolutely nothing:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: k3d.io/v1alpha2
|
apiVersion: k3d.io/v1alpha3
|
||||||
kind: Simple
|
kind: Simple
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ Currently, the config file is still in an Alpha-State, meaning, that it is subje
|
|||||||
!!! info "Validation via JSON-Schema"
|
!!! info "Validation via JSON-Schema"
|
||||||
k3d uses a [JSON-Schema](https://json-schema.org/) to describe the expected format and fields of the configuration file.
|
k3d uses a [JSON-Schema](https://json-schema.org/) to describe the expected format and fields of the configuration file.
|
||||||
This schema is also used to [validate](https://github.com/xeipuuv/gojsonschema#validation) a user-given config file.
|
This schema is also used to [validate](https://github.com/xeipuuv/gojsonschema#validation) a user-given config file.
|
||||||
This JSON-Schema can be found in the specific config version sub-directory in the repository (e.g. [here for `v1alpha2`](https://github.com/rancher/k3d/blob/main/pkg/config/v1alpha2/schema.json)) and could be used to lookup supported fields or by linters to validate the config file, e.g. in your code editor.
|
This JSON-Schema can be found in the specific config version sub-directory in the repository (e.g. [here for `v1alpha3`](https://github.com/rancher/k3d/blob/main/pkg/config/v1alpha3/schema.json)) and could be used to lookup supported fields or by linters to validate the config file, e.g. in your code editor.
|
||||||
|
|
||||||
### All Options: Example
|
### All Options: Example
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ Since the config options and the config file are changing quite a bit, it's hard
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# k3d configuration file, saved as e.g. /home/me/myk3dcluster.yaml
|
# k3d configuration file, saved as e.g. /home/me/myk3dcluster.yaml
|
||||||
apiVersion: k3d.io/v1alpha2 # this will change in the future as we make everything more stable
|
apiVersion: k3d.io/v1alpha3 # this will change in the future as we make everything more stable
|
||||||
kind: Simple # internally, we also have a Cluster config, which is not yet available externally
|
kind: Simple # internally, we also have a Cluster config, which is not yet available externally
|
||||||
name: mycluster # name that you want to give to your cluster (will still be prefixed with `k3d-`)
|
name: mycluster # name that you want to give to your cluster (will still be prefixed with `k3d-`)
|
||||||
servers: 1 # same as `--servers 1`
|
servers: 1 # same as `--servers 1`
|
||||||
@ -98,9 +98,10 @@ options:
|
|||||||
disableRollback: false # same as `--no-Rollback`
|
disableRollback: false # same as `--no-Rollback`
|
||||||
disableHostIPInjection: false # same as `--no-hostip`
|
disableHostIPInjection: false # same as `--no-hostip`
|
||||||
k3s: # options passed on to K3s itself
|
k3s: # options passed on to K3s itself
|
||||||
extraServerArgs: # additional arguments passed to the `k3s server` command; same as `--k3s-server-arg`
|
extraArgs: # additional arguments passed to the `k3s server|agent` command; same as `--k3s-arg`
|
||||||
- --tls-san=my.host.domain
|
- arg: --tls-san=my.host.domain
|
||||||
extraAgentArgs: [] # addditional arguments passed to the `k3s agent` command; same as `--k3s-agent-arg`
|
nodeFilters:
|
||||||
|
- server[*]
|
||||||
kubeconfig:
|
kubeconfig:
|
||||||
updateDefaultKubeconfig: true # add new cluster to your default Kubeconfig; same as `--kubeconfig-update-default` (default: true)
|
updateDefaultKubeconfig: true # add new cluster to your default Kubeconfig; same as `--kubeconfig-update-default` (default: true)
|
||||||
switchCurrentContext: true # also set current-context to the new cluster's context; same as `--kubeconfig-switch-context` (default: true)
|
switchCurrentContext: true # also set current-context to the new cluster's context; same as `--kubeconfig-switch-context` (default: true)
|
||||||
|
@ -29,7 +29,7 @@ This file can also be used for providing additional information necessary for ac
|
|||||||
If you're using a `SimpleConfig` file to configure your k3d cluster, you may as well embed the registries.yaml in there directly:
|
If you're using a `SimpleConfig` file to configure your k3d cluster, you may as well embed the registries.yaml in there directly:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: k3d.io/v1alpha2
|
apiVersion: k3d.io/v1alpha3
|
||||||
kind: Simple
|
kind: Simple
|
||||||
name: test
|
name: test
|
||||||
servers: 1
|
servers: 1
|
||||||
|
@ -36,7 +36,7 @@ import (
|
|||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
"github.com/imdario/mergo"
|
"github.com/imdario/mergo"
|
||||||
"github.com/rancher/k3d/v4/pkg/actions"
|
"github.com/rancher/k3d/v4/pkg/actions"
|
||||||
config "github.com/rancher/k3d/v4/pkg/config/v1alpha2"
|
config "github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||||
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"
|
runtimeErr "github.com/rancher/k3d/v4/pkg/runtimes/errors"
|
||||||
|
@ -29,43 +29,51 @@ import (
|
|||||||
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha2"
|
"github.com/rancher/k3d/v4/pkg/config/v1alpha2"
|
||||||
|
"github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||||
|
defaultConfig "github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||||
|
|
||||||
|
types "github.com/rancher/k3d/v4/pkg/config/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func FromViperSimple(config *viper.Viper) (conf.SimpleConfig, error) {
|
const DefaultConfigApiVersion = defaultConfig.ApiVersion
|
||||||
|
|
||||||
var cfg conf.SimpleConfig
|
var Schemas = map[string]string{
|
||||||
|
v1alpha2.ApiVersion: v1alpha2.JSONSchema,
|
||||||
// determine config kind
|
v1alpha3.ApiVersion: v1alpha3.JSONSchema,
|
||||||
if config.GetString("kind") != "" && strings.ToLower(config.GetString("kind")) != "simple" {
|
|
||||||
return cfg, fmt.Errorf("Wrong `kind` '%s' != 'simple' in config file", config.GetString("kind"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := config.Unmarshal(&cfg); err != nil {
|
|
||||||
log.Errorln("Failed to unmarshal File config")
|
|
||||||
|
|
||||||
return cfg, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return cfg, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromViper(config *viper.Viper) (conf.Config, error) {
|
func GetSchemaByVersion(apiVersion string) ([]byte, error) {
|
||||||
|
schema, ok := Schemas[strings.ToLower(apiVersion)]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unsupported apiVersion '%s'", apiVersion)
|
||||||
|
}
|
||||||
|
return []byte(schema), nil
|
||||||
|
}
|
||||||
|
|
||||||
var cfg conf.Config
|
func FromViper(config *viper.Viper) (types.Config, error) {
|
||||||
|
|
||||||
// determine config kind
|
var cfg types.Config
|
||||||
switch strings.ToLower(config.GetString("kind")) {
|
var err error
|
||||||
case "simple":
|
|
||||||
cfg = conf.SimpleConfig{}
|
apiVersion := strings.ToLower(config.GetString("apiversion"))
|
||||||
case "cluster":
|
kind := strings.ToLower(config.GetString("kind"))
|
||||||
cfg = conf.ClusterConfig{}
|
|
||||||
case "clusterlist":
|
log.Tracef("Trying to read config apiVersion='%s', kind='%s'", apiVersion, kind)
|
||||||
cfg = conf.ClusterListConfig{}
|
|
||||||
|
switch apiVersion {
|
||||||
|
case "k3d.io/v1alpha2":
|
||||||
|
cfg, err = v1alpha2.GetConfigByKind(kind)
|
||||||
|
case "k3d.io/v1alpha3":
|
||||||
|
cfg, err = v1alpha3.GetConfigByKind(kind)
|
||||||
case "":
|
case "":
|
||||||
return nil, fmt.Errorf("Missing `kind` in config file")
|
cfg, err = defaultConfig.GetConfigByKind(kind)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("Unknown `kind` '%s' in config file", config.GetString("kind"))
|
return nil, fmt.Errorf("cannot read config with apiversion '%s'", config.GetString("apiversion"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := config.Unmarshal(&cfg); err != nil {
|
if err := config.Unmarshal(&cfg); err != nil {
|
||||||
@ -76,3 +84,12 @@ func FromViper(config *viper.Viper) (conf.Config, error) {
|
|||||||
|
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getMigrations(version string) map[string]func(types.Config) (types.Config, error) {
|
||||||
|
switch version {
|
||||||
|
case v1alpha3.ApiVersion:
|
||||||
|
return v1alpha3.Migrations
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -26,7 +26,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-test/deep"
|
"github.com/go-test/deep"
|
||||||
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha2"
|
configtypes "github.com/rancher/k3d/v4/pkg/config/types"
|
||||||
|
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
k3d "github.com/rancher/k3d/v4/pkg/types"
|
k3d "github.com/rancher/k3d/v4/pkg/types"
|
||||||
@ -39,8 +40,8 @@ func TestReadSimpleConfig(t *testing.T) {
|
|||||||
exposedAPI.HostPort = "6443"
|
exposedAPI.HostPort = "6443"
|
||||||
|
|
||||||
expectedConfig := conf.SimpleConfig{
|
expectedConfig := conf.SimpleConfig{
|
||||||
TypeMeta: conf.TypeMeta{
|
TypeMeta: configtypes.TypeMeta{
|
||||||
APIVersion: "k3d.io/v1alpha2",
|
APIVersion: "k3d.io/v1alpha3",
|
||||||
Kind: "Simple",
|
Kind: "Simple",
|
||||||
},
|
},
|
||||||
Name: "test",
|
Name: "test",
|
||||||
@ -83,8 +84,12 @@ func TestReadSimpleConfig(t *testing.T) {
|
|||||||
DisableImageVolume: false,
|
DisableImageVolume: false,
|
||||||
},
|
},
|
||||||
K3sOptions: conf.SimpleConfigOptionsK3s{
|
K3sOptions: conf.SimpleConfigOptionsK3s{
|
||||||
ExtraServerArgs: []string{"--tls-san=127.0.0.1"},
|
ExtraArgs: []conf.K3sArgWithNodeFilters{
|
||||||
ExtraAgentArgs: []string{},
|
{
|
||||||
|
Arg: "--tls-san=127.0.0.1",
|
||||||
|
NodeFilters: []string{"server[*]"},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
KubeconfigOptions: conf.SimpleConfigOptionsKubeconfig{
|
KubeconfigOptions: conf.SimpleConfigOptionsKubeconfig{
|
||||||
UpdateDefaultKubeconfig: true,
|
UpdateDefaultKubeconfig: true,
|
||||||
@ -107,7 +112,7 @@ func TestReadSimpleConfig(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg, err := FromViperSimple(config)
|
cfg, err := FromViper(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -123,8 +128,8 @@ func TestReadSimpleConfig(t *testing.T) {
|
|||||||
func TestReadClusterConfig(t *testing.T) {
|
func TestReadClusterConfig(t *testing.T) {
|
||||||
|
|
||||||
expectedConfig := conf.ClusterConfig{
|
expectedConfig := conf.ClusterConfig{
|
||||||
TypeMeta: conf.TypeMeta{
|
TypeMeta: configtypes.TypeMeta{
|
||||||
APIVersion: "k3d.io/v1alpha2",
|
APIVersion: "k3d.io/v1alpha3",
|
||||||
Kind: "Cluster",
|
Kind: "Cluster",
|
||||||
},
|
},
|
||||||
Cluster: k3d.Cluster{
|
Cluster: k3d.Cluster{
|
||||||
@ -168,8 +173,8 @@ func TestReadClusterConfig(t *testing.T) {
|
|||||||
func TestReadClusterListConfig(t *testing.T) {
|
func TestReadClusterListConfig(t *testing.T) {
|
||||||
|
|
||||||
expectedConfig := conf.ClusterListConfig{
|
expectedConfig := conf.ClusterListConfig{
|
||||||
TypeMeta: conf.TypeMeta{
|
TypeMeta: configtypes.TypeMeta{
|
||||||
APIVersion: "k3d.io/v1alpha2",
|
APIVersion: "k3d.io/v1alpha3",
|
||||||
Kind: "ClusterList",
|
Kind: "ClusterList",
|
||||||
},
|
},
|
||||||
Clusters: []k3d.Cluster{
|
Clusters: []k3d.Cluster{
|
||||||
@ -237,7 +242,7 @@ func TestReadUnknownConfig(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := FromViperSimple(config)
|
_, err := FromViper(config)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
@ -24,14 +24,14 @@ package config
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/rancher/k3d/v4/pkg/config/v1alpha2"
|
"github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestValidateSchema(t *testing.T) {
|
func TestValidateSchema(t *testing.T) {
|
||||||
|
|
||||||
cfgPath := "./test_assets/config_test_simple.yaml"
|
cfgPath := "./test_assets/config_test_simple.yaml"
|
||||||
|
|
||||||
if err := ValidateSchemaFile(cfgPath, []byte(v1alpha2.JSONSchema)); err != nil {
|
if err := ValidateSchemaFile(cfgPath, []byte(v1alpha3.JSONSchema)); err != nil {
|
||||||
t.Errorf("Validation of config file %s against the default schema failed: %+v", cfgPath, err)
|
t.Errorf("Validation of config file %s against the default schema failed: %+v", cfgPath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ func TestValidateSchemaFail(t *testing.T) {
|
|||||||
cfgPath := "./test_assets/config_test_simple_invalid_servers.yaml"
|
cfgPath := "./test_assets/config_test_simple_invalid_servers.yaml"
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if err = ValidateSchemaFile(cfgPath, []byte(v1alpha2.JSONSchema)); err == nil {
|
if err = ValidateSchemaFile(cfgPath, []byte(v1alpha3.JSONSchema)); err == nil {
|
||||||
t.Errorf("Validation of config file %s against the default schema passed where we expected a failure", cfgPath)
|
t.Errorf("Validation of config file %s against the default schema passed where we expected a failure", cfgPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/imdario/mergo"
|
"github.com/imdario/mergo"
|
||||||
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha2"
|
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,7 +25,8 @@ package config
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha2"
|
configtypes "github.com/rancher/k3d/v4/pkg/config/types"
|
||||||
|
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"gotest.tools/assert"
|
"gotest.tools/assert"
|
||||||
)
|
)
|
||||||
@ -34,7 +35,7 @@ func TestMergeSimpleConfig(t *testing.T) {
|
|||||||
srcConfig := "./test_assets/config_test_simple.yaml"
|
srcConfig := "./test_assets/config_test_simple.yaml"
|
||||||
destConfig := "./test_assets/config_test_simple_2.yaml"
|
destConfig := "./test_assets/config_test_simple_2.yaml"
|
||||||
|
|
||||||
var src, dest conf.Config
|
var src, dest configtypes.Config
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
cfg1 := viper.New()
|
cfg1 := viper.New()
|
||||||
@ -45,11 +46,11 @@ func TestMergeSimpleConfig(t *testing.T) {
|
|||||||
cfg2.SetConfigFile(destConfig)
|
cfg2.SetConfigFile(destConfig)
|
||||||
_ = cfg2.ReadInConfig()
|
_ = cfg2.ReadInConfig()
|
||||||
|
|
||||||
if src, err = FromViperSimple(cfg1); err != nil {
|
if src, err = FromViper(cfg1); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if dest, err = FromViperSimple(cfg2); err != nil {
|
if dest, err = FromViper(cfg2); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
40
pkg/config/migrate.go
Normal file
40
pkg/config/migrate.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
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 config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
types "github.com/rancher/k3d/v4/pkg/config/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Migrate(config types.Config, targetVersion string) (types.Config, error) {
|
||||||
|
|
||||||
|
migration, ok := getMigrations(targetVersion)[config.GetAPIVersion()]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("no migration possible from '%s' to '%s'", config.GetAPIVersion(), targetVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
return migration(config)
|
||||||
|
|
||||||
|
}
|
@ -23,7 +23,7 @@ THE SOFTWARE.
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha2"
|
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||||
"github.com/rancher/k3d/v4/pkg/runtimes"
|
"github.com/rancher/k3d/v4/pkg/runtimes"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"gotest.tools/assert"
|
"gotest.tools/assert"
|
||||||
@ -38,14 +39,14 @@ func TestProcessClusterConfig(t *testing.T) {
|
|||||||
vip.SetConfigFile(cfgFile)
|
vip.SetConfigFile(cfgFile)
|
||||||
_ = vip.ReadInConfig()
|
_ = vip.ReadInConfig()
|
||||||
|
|
||||||
cfg, err := FromViperSimple(vip)
|
cfg, err := FromViper(vip)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("\n========== Read Config and transform to cluster ==========\n%+v\n=================================\n", cfg)
|
t.Logf("\n========== Read Config and transform to cluster ==========\n%+v\n=================================\n", cfg)
|
||||||
|
|
||||||
clusterCfg, err := TransformSimpleToClusterConfig(context.Background(), runtimes.Docker, cfg)
|
clusterCfg, err := TransformSimpleToClusterConfig(context.Background(), runtimes.Docker, cfg.(conf.SimpleConfig))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
apiVersion: k3d.io/v1alpha2
|
apiVersion: k3d.io/v1alpha3
|
||||||
kind: Cluster
|
kind: Cluster
|
||||||
name: foo
|
name: foo
|
||||||
nodes:
|
nodes:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
apiVersion: k3d.io/v1alpha2
|
apiVersion: k3d.io/v1alpha3
|
||||||
kind: ClusterList
|
kind: ClusterList
|
||||||
clusters:
|
clusters:
|
||||||
- name: foo
|
- name: foo
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
apiVersion: k3d.io/v1alpha2
|
apiVersion: k3d.io/v1alpha3
|
||||||
kind: Simple
|
kind: Simple
|
||||||
name: test
|
name: test
|
||||||
servers: 1
|
servers: 1
|
||||||
@ -25,7 +25,7 @@ env:
|
|||||||
labels:
|
labels:
|
||||||
- label: foo=bar
|
- label: foo=bar
|
||||||
nodeFilters:
|
nodeFilters:
|
||||||
- server[0]
|
- "server[0]"
|
||||||
- loadbalancer
|
- loadbalancer
|
||||||
|
|
||||||
options:
|
options:
|
||||||
@ -35,9 +35,10 @@ options:
|
|||||||
disableLoadbalancer: false
|
disableLoadbalancer: false
|
||||||
disableImageVolume: false
|
disableImageVolume: false
|
||||||
k3s:
|
k3s:
|
||||||
extraServerArgs:
|
extraArgs:
|
||||||
- --tls-san=127.0.0.1
|
- arg: --tls-san=127.0.0.1
|
||||||
extraAgentArgs: []
|
nodeFilters:
|
||||||
|
- "server[*]"
|
||||||
kubeconfig:
|
kubeconfig:
|
||||||
updateDefaultKubeconfig: true
|
updateDefaultKubeconfig: true
|
||||||
switchCurrentContext: true
|
switchCurrentContext: true
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
apiVersion: k3d.io/v1alpha2
|
apiVersion: k3d.io/v1alpha3
|
||||||
kind: Simple
|
kind: Simple
|
||||||
name: supertest
|
name: supertest
|
||||||
agents: 8
|
agents: 8
|
@ -1,4 +1,4 @@
|
|||||||
apiVersion: k3d.io/v1alpha2
|
apiVersion: k3d.io/v1alpha3
|
||||||
kind: Simple
|
kind: Simple
|
||||||
name: 1234
|
name: 1234
|
||||||
servers: 1
|
servers: 1
|
||||||
@ -35,9 +35,10 @@ options:
|
|||||||
disableLoadbalancer: false
|
disableLoadbalancer: false
|
||||||
disableImageVolume: false
|
disableImageVolume: false
|
||||||
k3s:
|
k3s:
|
||||||
extraServerArgs:
|
extraArgs:
|
||||||
- --tls-san=127.0.0.1
|
- arg: --tls-san=127.0.0.1
|
||||||
extraAgentArgs: []
|
nodeFilters:
|
||||||
|
- "server[*]"
|
||||||
kubeconfig:
|
kubeconfig:
|
||||||
updateDefaultKubeconfig: true
|
updateDefaultKubeconfig: true
|
||||||
switchCurrentContext: true
|
switchCurrentContext: true
|
@ -1,3 +1,3 @@
|
|||||||
apiVersion: k3d.io/v1alpha2
|
apiVersion: k3d.io/v1alpha3
|
||||||
kind: Unknown
|
kind: Unknown
|
||||||
foo: bar
|
foo: bar
|
@ -31,7 +31,7 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/go-connections/nat"
|
"github.com/docker/go-connections/nat"
|
||||||
cliutil "github.com/rancher/k3d/v4/cmd/util" // TODO: move parseapiport to pkg
|
cliutil "github.com/rancher/k3d/v4/cmd/util" // TODO: move parseapiport to pkg
|
||||||
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha2"
|
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||||
"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"
|
||||||
"github.com/rancher/k3d/v4/pkg/types/k3s"
|
"github.com/rancher/k3d/v4/pkg/types/k3s"
|
||||||
@ -117,7 +117,6 @@ func TransformSimpleToClusterConfig(ctx context.Context, runtime runtimes.Runtim
|
|||||||
serverNode := k3d.Node{
|
serverNode := k3d.Node{
|
||||||
Role: k3d.ServerRole,
|
Role: k3d.ServerRole,
|
||||||
Image: simpleConfig.Image,
|
Image: simpleConfig.Image,
|
||||||
Args: simpleConfig.Options.K3sOptions.ExtraServerArgs,
|
|
||||||
ServerOpts: k3d.ServerOpts{},
|
ServerOpts: k3d.ServerOpts{},
|
||||||
Memory: simpleConfig.Options.Runtime.ServersMemory,
|
Memory: simpleConfig.Options.Runtime.ServersMemory,
|
||||||
}
|
}
|
||||||
@ -135,7 +134,6 @@ func TransformSimpleToClusterConfig(ctx context.Context, runtime runtimes.Runtim
|
|||||||
agentNode := k3d.Node{
|
agentNode := k3d.Node{
|
||||||
Role: k3d.AgentRole,
|
Role: k3d.AgentRole,
|
||||||
Image: simpleConfig.Image,
|
Image: simpleConfig.Image,
|
||||||
Args: simpleConfig.Options.K3sOptions.ExtraAgentArgs,
|
|
||||||
Memory: simpleConfig.Options.Runtime.AgentsMemory,
|
Memory: simpleConfig.Options.Runtime.AgentsMemory,
|
||||||
}
|
}
|
||||||
newCluster.Nodes = append(newCluster.Nodes, &agentNode)
|
newCluster.Nodes = append(newCluster.Nodes, &agentNode)
|
||||||
@ -228,6 +226,22 @@ func TransformSimpleToClusterConfig(ctx context.Context, runtime runtimes.Runtim
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -> ARGS
|
||||||
|
for _, argWithNodeFilters := range simpleConfig.Options.K3sOptions.ExtraArgs {
|
||||||
|
if len(argWithNodeFilters.NodeFilters) == 0 && nodeCount > 1 {
|
||||||
|
return nil, fmt.Errorf("K3sExtraArg '%s' lacks a node filter, but there's more than one node", argWithNodeFilters.Arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes, err := util.FilterNodes(nodeList, argWithNodeFilters.NodeFilters)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, node := range nodes {
|
||||||
|
node.Args = append(node.Args, argWithNodeFilters.Arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**************************
|
/**************************
|
||||||
* Cluster Create Options *
|
* Cluster Create Options *
|
||||||
**************************/
|
**************************/
|
||||||
@ -238,8 +252,6 @@ func TransformSimpleToClusterConfig(ctx context.Context, runtime runtimes.Runtim
|
|||||||
WaitForServer: simpleConfig.Options.K3dOptions.Wait,
|
WaitForServer: simpleConfig.Options.K3dOptions.Wait,
|
||||||
Timeout: simpleConfig.Options.K3dOptions.Timeout,
|
Timeout: simpleConfig.Options.K3dOptions.Timeout,
|
||||||
DisableLoadBalancer: simpleConfig.Options.K3dOptions.DisableLoadbalancer,
|
DisableLoadBalancer: simpleConfig.Options.K3dOptions.DisableLoadbalancer,
|
||||||
K3sServerArgs: simpleConfig.Options.K3sOptions.ExtraServerArgs,
|
|
||||||
K3sAgentArgs: simpleConfig.Options.K3sOptions.ExtraAgentArgs,
|
|
||||||
GPURequest: simpleConfig.Options.Runtime.GPURequest,
|
GPURequest: simpleConfig.Options.Runtime.GPURequest,
|
||||||
ServersMemory: simpleConfig.Options.Runtime.ServersMemory,
|
ServersMemory: simpleConfig.Options.Runtime.ServersMemory,
|
||||||
AgentsMemory: simpleConfig.Options.Runtime.AgentsMemory,
|
AgentsMemory: simpleConfig.Options.Runtime.AgentsMemory,
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||||
"github.com/rancher/k3d/v4/pkg/runtimes"
|
"github.com/rancher/k3d/v4/pkg/runtimes"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
@ -37,14 +38,14 @@ func TestTransformSimpleConfigToClusterConfig(t *testing.T) {
|
|||||||
vip.SetConfigFile(cfgFile)
|
vip.SetConfigFile(cfgFile)
|
||||||
_ = vip.ReadInConfig()
|
_ = vip.ReadInConfig()
|
||||||
|
|
||||||
cfg, err := FromViperSimple(vip)
|
cfg, err := FromViper(vip)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Logf("\n========== Read Config ==========\n%+v\n=================================\n", cfg)
|
t.Logf("\n========== Read Config ==========\n%+v\n=================================\n", cfg)
|
||||||
|
|
||||||
clusterCfg, err := TransformSimpleToClusterConfig(context.Background(), runtimes.Docker, cfg)
|
clusterCfg, err := TransformSimpleToClusterConfig(context.Background(), runtimes.Docker, cfg.(conf.SimpleConfig))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
34
pkg/config/types/types.go
Normal file
34
pkg/config/types/types.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
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 types
|
||||||
|
|
||||||
|
// TypeMeta is basically copied from https://github.com/kubernetes/apimachinery/blob/a3b564b22db316a41e94fdcffcf9995424fe924c/pkg/apis/meta/v1/types.go#L36-L56
|
||||||
|
type TypeMeta struct {
|
||||||
|
Kind string `mapstructure:"kind,omitempty" yaml:"kind,omitempty" json:"kind,omitempty"`
|
||||||
|
APIVersion string `mapstructure:"apiVersion,omitempty" yaml:"apiVersion,omitempty" json:"apiVersion,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config interface.
|
||||||
|
type Config interface {
|
||||||
|
GetKind() string
|
||||||
|
GetAPIVersion() string
|
||||||
|
}
|
@ -27,6 +27,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
configtypes "github.com/rancher/k3d/v4/pkg/config/types"
|
||||||
k3d "github.com/rancher/k3d/v4/pkg/types"
|
k3d "github.com/rancher/k3d/v4/pkg/types"
|
||||||
"github.com/rancher/k3d/v4/version"
|
"github.com/rancher/k3d/v4/version"
|
||||||
)
|
)
|
||||||
@ -35,9 +36,11 @@ import (
|
|||||||
//go:embed schema.json
|
//go:embed schema.json
|
||||||
var JSONSchema string
|
var JSONSchema string
|
||||||
|
|
||||||
|
const ApiVersion = "k3d.io/v1alpha2"
|
||||||
|
|
||||||
// DefaultConfigTpl for printing
|
// DefaultConfigTpl for printing
|
||||||
const DefaultConfigTpl = `---
|
const DefaultConfigTpl = `---
|
||||||
apiVersion: k3d.io/v1alpha2
|
apiVersion: %s
|
||||||
kind: Simple
|
kind: Simple
|
||||||
name: %s
|
name: %s
|
||||||
servers: 1
|
servers: 1
|
||||||
@ -48,21 +51,11 @@ image: %s
|
|||||||
// DefaultConfig templated DefaultConfigTpl
|
// DefaultConfig templated DefaultConfigTpl
|
||||||
var DefaultConfig = fmt.Sprintf(
|
var DefaultConfig = fmt.Sprintf(
|
||||||
DefaultConfigTpl,
|
DefaultConfigTpl,
|
||||||
|
ApiVersion,
|
||||||
k3d.DefaultClusterName,
|
k3d.DefaultClusterName,
|
||||||
fmt.Sprintf("%s:%s", k3d.DefaultK3sImageRepo, version.GetK3sVersion(false)),
|
fmt.Sprintf("%s:%s", k3d.DefaultK3sImageRepo, version.GetK3sVersion(false)),
|
||||||
)
|
)
|
||||||
|
|
||||||
// TypeMeta is basically copied from https://github.com/kubernetes/apimachinery/blob/a3b564b22db316a41e94fdcffcf9995424fe924c/pkg/apis/meta/v1/types.go#L36-L56
|
|
||||||
type TypeMeta struct {
|
|
||||||
Kind string `mapstructure:"kind,omitempty" yaml:"kind,omitempty" json:"kind,omitempty"`
|
|
||||||
APIVersion string `mapstructure:"apiVersion,omitempty" yaml:"apiVersion,omitempty" json:"apiVersion,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config interface.
|
|
||||||
type Config interface {
|
|
||||||
GetKind() string
|
|
||||||
}
|
|
||||||
|
|
||||||
type VolumeWithNodeFilters struct {
|
type VolumeWithNodeFilters struct {
|
||||||
Volume string `mapstructure:"volume" yaml:"volume" json:"volume,omitempty"`
|
Volume string `mapstructure:"volume" yaml:"volume" json:"volume,omitempty"`
|
||||||
NodeFilters []string `mapstructure:"nodeFilters" yaml:"nodeFilters" json:"nodeFilters,omitempty"`
|
NodeFilters []string `mapstructure:"nodeFilters" yaml:"nodeFilters" json:"nodeFilters,omitempty"`
|
||||||
@ -119,21 +112,21 @@ type SimpleConfigOptionsK3s struct {
|
|||||||
|
|
||||||
// SimpleConfig describes the toplevel k3d configuration file.
|
// SimpleConfig describes the toplevel k3d configuration file.
|
||||||
type SimpleConfig struct {
|
type SimpleConfig struct {
|
||||||
TypeMeta `mapstructure:",squash" yaml:",inline"`
|
configtypes.TypeMeta `mapstructure:",squash" yaml:",inline"`
|
||||||
Name string `mapstructure:"name" yaml:"name" json:"name,omitempty"`
|
Name string `mapstructure:"name" yaml:"name" json:"name,omitempty"`
|
||||||
Servers int `mapstructure:"servers" yaml:"servers" json:"servers,omitempty"` //nolint:lll // default 1
|
Servers int `mapstructure:"servers" yaml:"servers" json:"servers,omitempty"` //nolint:lll // default 1
|
||||||
Agents int `mapstructure:"agents" yaml:"agents" json:"agents,omitempty"` //nolint:lll // default 0
|
Agents int `mapstructure:"agents" yaml:"agents" json:"agents,omitempty"` //nolint:lll // default 0
|
||||||
ExposeAPI SimpleExposureOpts `mapstructure:"kubeAPI" yaml:"kubeAPI" json:"kubeAPI,omitempty"`
|
ExposeAPI SimpleExposureOpts `mapstructure:"kubeAPI" yaml:"kubeAPI" json:"kubeAPI,omitempty"`
|
||||||
Image string `mapstructure:"image" yaml:"image" json:"image,omitempty"`
|
Image string `mapstructure:"image" yaml:"image" json:"image,omitempty"`
|
||||||
Network string `mapstructure:"network" yaml:"network" json:"network,omitempty"`
|
Network string `mapstructure:"network" yaml:"network" json:"network,omitempty"`
|
||||||
Subnet string `mapstructure:"subnet" yaml:"subnet" json:"subnet,omitempty"`
|
Subnet string `mapstructure:"subnet" yaml:"subnet" json:"subnet,omitempty"`
|
||||||
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"`
|
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 {
|
||||||
Use []string `mapstructure:"use" yaml:"use,omitempty" json:"use,omitempty"`
|
Use []string `mapstructure:"use" yaml:"use,omitempty" json:"use,omitempty"`
|
||||||
Create bool `mapstructure:"create" yaml:"create,omitempty" json:"create,omitempty"`
|
Create bool `mapstructure:"create" yaml:"create,omitempty" json:"create,omitempty"`
|
||||||
Config string `mapstructure:"config" yaml:"config,omitempty" json:"config,omitempty"` // registries.yaml (k3s config for containerd registry override)
|
Config string `mapstructure:"config" yaml:"config,omitempty" json:"config,omitempty"` // registries.yaml (k3s config for containerd registry override)
|
||||||
@ -147,30 +140,60 @@ type SimpleExposureOpts struct {
|
|||||||
HostPort string `mapstructure:"hostPort" yaml:"hostPort,omitempty" json:"hostPort,omitempty"`
|
HostPort string `mapstructure:"hostPort" yaml:"hostPort,omitempty" json:"hostPort,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetKind implements Config.GetKind
|
// Kind implements Config.Kind
|
||||||
func (c SimpleConfig) GetKind() string {
|
func (c SimpleConfig) GetKind() string {
|
||||||
return "Cluster"
|
return "Simple"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c SimpleConfig) GetAPIVersion() string {
|
||||||
|
return ApiVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClusterConfig describes a single cluster config
|
// ClusterConfig describes a single cluster config
|
||||||
type ClusterConfig struct {
|
type ClusterConfig struct {
|
||||||
TypeMeta `mapstructure:",squash" yaml:",inline"`
|
configtypes.TypeMeta `mapstructure:",squash" yaml:",inline"`
|
||||||
Cluster k3d.Cluster `mapstructure:",squash" yaml:",inline"`
|
Cluster k3d.Cluster `mapstructure:",squash" yaml:",inline"`
|
||||||
ClusterCreateOpts k3d.ClusterCreateOpts `mapstructure:"options" yaml:"options"`
|
ClusterCreateOpts k3d.ClusterCreateOpts `mapstructure:"options" yaml:"options"`
|
||||||
KubeconfigOpts SimpleConfigOptionsKubeconfig `mapstructure:"kubeconfig" yaml:"kubeconfig"`
|
KubeconfigOpts SimpleConfigOptionsKubeconfig `mapstructure:"kubeconfig" yaml:"kubeconfig"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetKind implements Config.GetKind
|
// Kind implements Config.Kind
|
||||||
func (c ClusterConfig) GetKind() string {
|
func (c ClusterConfig) GetKind() string {
|
||||||
return "Cluster"
|
return "Simple"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ClusterConfig) GetAPIVersion() string {
|
||||||
|
return ApiVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClusterListConfig describes a list of clusters
|
// ClusterListConfig describes a list of clusters
|
||||||
type ClusterListConfig struct {
|
type ClusterListConfig struct {
|
||||||
TypeMeta `mapstructure:",squash" yaml:",inline"`
|
configtypes.TypeMeta `mapstructure:",squash" yaml:",inline"`
|
||||||
Clusters []k3d.Cluster `mapstructure:"clusters" yaml:"clusters"`
|
Clusters []k3d.Cluster `mapstructure:"clusters" yaml:"clusters"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c ClusterListConfig) GetKind() string {
|
func (c ClusterListConfig) GetKind() string {
|
||||||
return "ClusterList"
|
return "Simple"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ClusterListConfig) GetAPIVersion() string {
|
||||||
|
return ApiVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetConfigByKind(kind string) (configtypes.Config, error) {
|
||||||
|
|
||||||
|
// determine config kind
|
||||||
|
switch kind {
|
||||||
|
case "simple":
|
||||||
|
return SimpleConfig{}, nil
|
||||||
|
case "cluster":
|
||||||
|
return ClusterConfig{}, nil
|
||||||
|
case "clusterlist":
|
||||||
|
return ClusterListConfig{}, nil
|
||||||
|
case "":
|
||||||
|
return nil, fmt.Errorf("missing `kind` in config file")
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown `kind` '%s' in config file", kind)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
84
pkg/config/v1alpha3/migrations.go
Normal file
84
pkg/config/v1alpha3/migrations.go
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
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 v1alpha3
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
configtypes "github.com/rancher/k3d/v4/pkg/config/types"
|
||||||
|
"github.com/rancher/k3d/v4/pkg/config/v1alpha2"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Migrations = map[string]func(configtypes.Config) (configtypes.Config, error){
|
||||||
|
v1alpha2.ApiVersion: MigrateV1Alpha2,
|
||||||
|
}
|
||||||
|
|
||||||
|
func MigrateV1Alpha2(input configtypes.Config) (configtypes.Config, error) {
|
||||||
|
log.Debugln("Migrating v1alpha2 to v1alpha3")
|
||||||
|
|
||||||
|
injson, err := json.Marshal(input)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.GetKind() == "Simple" {
|
||||||
|
cfg := SimpleConfig{}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(injson, &cfg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.Options.K3sOptions.ExtraArgs = []K3sArgWithNodeFilters{}
|
||||||
|
|
||||||
|
for _, arg := range input.(v1alpha2.SimpleConfig).Options.K3sOptions.ExtraServerArgs {
|
||||||
|
cfg.Options.K3sOptions.ExtraArgs = append(cfg.Options.K3sOptions.ExtraArgs, K3sArgWithNodeFilters{
|
||||||
|
Arg: arg,
|
||||||
|
NodeFilters: []string{
|
||||||
|
"server[*]",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, arg := range input.(v1alpha2.SimpleConfig).Options.K3sOptions.ExtraAgentArgs {
|
||||||
|
cfg.Options.K3sOptions.ExtraArgs = append(cfg.Options.K3sOptions.ExtraArgs, K3sArgWithNodeFilters{
|
||||||
|
Arg: arg,
|
||||||
|
NodeFilters: []string{
|
||||||
|
"agent[*]",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.APIVersion = ApiVersion
|
||||||
|
|
||||||
|
log.Debugf("Migrated config: %+v", cfg)
|
||||||
|
|
||||||
|
return cfg, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debugf("No migration needed for %s#%s -> %s#%s", input.GetAPIVersion(), input.GetKind(), ApiVersion, input.GetKind())
|
||||||
|
|
||||||
|
return input, nil
|
||||||
|
|
||||||
|
}
|
254
pkg/config/v1alpha3/schema.json
Normal file
254
pkg/config/v1alpha3/schema.json
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "SimpleConfig",
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"apiVersion",
|
||||||
|
"kind"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"apiVersion": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"k3d.io/v1alpha3"
|
||||||
|
],
|
||||||
|
"default": "k3d.io/v1alpha3"
|
||||||
|
},
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"Simple"
|
||||||
|
],
|
||||||
|
"default": "Simple"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"description": "Name of the cluster (must be a valid hostname and will be prefixed with 'k3d-'). Example: 'mycluster'.",
|
||||||
|
"type": "string",
|
||||||
|
"format": "hostname"
|
||||||
|
},
|
||||||
|
"servers": {
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"agents": {
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 0
|
||||||
|
},
|
||||||
|
"kubeAPI": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"host": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "hostname"
|
||||||
|
},
|
||||||
|
"hostIP": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "ipv4",
|
||||||
|
"examples": [
|
||||||
|
"0.0.0.0",
|
||||||
|
"192.168.178.55"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hostPort": {
|
||||||
|
"type":"string",
|
||||||
|
"examples": [
|
||||||
|
"6443"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"image": {
|
||||||
|
"type": "string",
|
||||||
|
"examples": [
|
||||||
|
"rancher/k3s:latest"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"network": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"subnet": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "auto",
|
||||||
|
"examples": [
|
||||||
|
"172.28.0.0/16",
|
||||||
|
"192.162.0.0/16"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"token": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"volumes": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"volume": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"nodeFilters": {
|
||||||
|
"$ref": "#/definitions/nodeFilters"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ports": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"port": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"nodeFilters": {
|
||||||
|
"$ref": "#/definitions/nodeFilters"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"label": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"nodeFilters": {
|
||||||
|
"$ref": "#/definitions/nodeFilters"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"k3d": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"wait": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"timeout": {
|
||||||
|
"type": "string",
|
||||||
|
"examples": [
|
||||||
|
"60s",
|
||||||
|
"1m",
|
||||||
|
"1m30s"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"disableLoadbalancer": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"disableImageVolume": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"disableRollback": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"disableHostIPInjection": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"k3s": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"extraArgs": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"arg": {
|
||||||
|
"type": "string",
|
||||||
|
"examples": [
|
||||||
|
"--tls-san=127.0.0.1",
|
||||||
|
"--disable=traefik"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nodeFilters": {
|
||||||
|
"$ref": "#/definitions/nodeFilters"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"kubeconfig": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"updateDefaultKubeconfig": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"switchCurrentContext": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"runtime": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"gpuRequest": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"serversMemory": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"agentsMemory": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"envVar": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"nodeFilters": {
|
||||||
|
"$ref": "#/definitions/nodeFilters"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"registries": {
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"definitions": {
|
||||||
|
"nodeFilters": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"examples": [
|
||||||
|
"loadbalancer",
|
||||||
|
"server[*]",
|
||||||
|
"server[0]",
|
||||||
|
"agent[1]",
|
||||||
|
"all"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
203
pkg/config/v1alpha3/types.go
Normal file
203
pkg/config/v1alpha3/types.go
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
/*
|
||||||
|
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 v1alpha3
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
config "github.com/rancher/k3d/v4/pkg/config/types"
|
||||||
|
k3d "github.com/rancher/k3d/v4/pkg/types"
|
||||||
|
"github.com/rancher/k3d/v4/version"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ApiVersion = "k3d.io/v1alpha3"
|
||||||
|
|
||||||
|
// JSONSchema describes the schema used to validate config files
|
||||||
|
//go:embed schema.json
|
||||||
|
var JSONSchema string
|
||||||
|
|
||||||
|
// DefaultConfigTpl for printing
|
||||||
|
const DefaultConfigTpl = `---
|
||||||
|
apiVersion: k3d.io/v1alpha3
|
||||||
|
kind: Simple
|
||||||
|
name: %s
|
||||||
|
servers: 1
|
||||||
|
agents: 0
|
||||||
|
image: %s
|
||||||
|
`
|
||||||
|
|
||||||
|
// DefaultConfig templated DefaultConfigTpl
|
||||||
|
var DefaultConfig = fmt.Sprintf(
|
||||||
|
DefaultConfigTpl,
|
||||||
|
k3d.DefaultClusterName,
|
||||||
|
fmt.Sprintf("%s:%s", k3d.DefaultK3sImageRepo, version.GetK3sVersion(false)),
|
||||||
|
)
|
||||||
|
|
||||||
|
type VolumeWithNodeFilters struct {
|
||||||
|
Volume string `mapstructure:"volume" yaml:"volume" json:"volume,omitempty"`
|
||||||
|
NodeFilters []string `mapstructure:"nodeFilters" yaml:"nodeFilters" json:"nodeFilters,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PortWithNodeFilters struct {
|
||||||
|
Port string `mapstructure:"port" yaml:"port" json:"port,omitempty"`
|
||||||
|
NodeFilters []string `mapstructure:"nodeFilters" yaml:"nodeFilters" json:"nodeFilters,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LabelWithNodeFilters struct {
|
||||||
|
Label string `mapstructure:"label" yaml:"label" json:"label,omitempty"`
|
||||||
|
NodeFilters []string `mapstructure:"nodeFilters" yaml:"nodeFilters" json:"nodeFilters,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type EnvVarWithNodeFilters struct {
|
||||||
|
EnvVar string `mapstructure:"envVar" yaml:"envVar" json:"envVar,omitempty"`
|
||||||
|
NodeFilters []string `mapstructure:"nodeFilters" yaml:"nodeFilters" json:"nodeFilters,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type K3sArgWithNodeFilters struct {
|
||||||
|
Arg string `mapstructure:"arg" yaml:"arg" json:"arg,omitempty"`
|
||||||
|
NodeFilters []string `mapstructure:"nodeFilters" yaml:"nodeFilters" json:"nodeFilters,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimpleConfigOptionsKubeconfig describes the set of options referring to the kubeconfig during cluster creation.
|
||||||
|
type SimpleConfigOptionsKubeconfig struct {
|
||||||
|
UpdateDefaultKubeconfig bool `mapstructure:"updateDefaultKubeconfig" yaml:"updateDefaultKubeconfig" json:"updateDefaultKubeconfig,omitempty"` // default: true
|
||||||
|
SwitchCurrentContext bool `mapstructure:"switchCurrentContext" yaml:"switchCurrentContext" json:"switchCurrentContext,omitempty"` //nolint:lll // default: true
|
||||||
|
}
|
||||||
|
|
||||||
|
type SimpleConfigOptions struct {
|
||||||
|
K3dOptions SimpleConfigOptionsK3d `mapstructure:"k3d" yaml:"k3d"`
|
||||||
|
K3sOptions SimpleConfigOptionsK3s `mapstructure:"k3s" yaml:"k3s"`
|
||||||
|
KubeconfigOptions SimpleConfigOptionsKubeconfig `mapstructure:"kubeconfig" yaml:"kubeconfig"`
|
||||||
|
Runtime SimpleConfigOptionsRuntime `mapstructure:"runtime" yaml:"runtime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SimpleConfigOptionsRuntime struct {
|
||||||
|
GPURequest string `mapstructure:"gpuRequest" yaml:"gpuRequest"`
|
||||||
|
ServersMemory string `mapstructure:"serversMemory" yaml:"serversMemory"`
|
||||||
|
AgentsMemory string `mapstructure:"agentsMemory" yaml:"agentsMemory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SimpleConfigOptionsK3d struct {
|
||||||
|
Wait bool `mapstructure:"wait" yaml:"wait"`
|
||||||
|
Timeout time.Duration `mapstructure:"timeout" yaml:"timeout"`
|
||||||
|
DisableLoadbalancer bool `mapstructure:"disableLoadbalancer" yaml:"disableLoadbalancer"`
|
||||||
|
DisableImageVolume bool `mapstructure:"disableImageVolume" yaml:"disableImageVolume"`
|
||||||
|
NoRollback bool `mapstructure:"disableRollback" yaml:"disableRollback"`
|
||||||
|
PrepDisableHostIPInjection bool `mapstructure:"disableHostIPInjection" yaml:"disableHostIPInjection"`
|
||||||
|
NodeHookActions []k3d.NodeHookAction `mapstructure:"nodeHookActions" yaml:"nodeHookActions,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SimpleConfigOptionsK3s struct {
|
||||||
|
ExtraArgs []K3sArgWithNodeFilters `mapstructure:"extraArgs" yaml:"extraArgs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimpleConfig describes the toplevel k3d configuration file.
|
||||||
|
type SimpleConfig struct {
|
||||||
|
config.TypeMeta `mapstructure:",squash" yaml:",inline"`
|
||||||
|
Name string `mapstructure:"name" yaml:"name" json:"name,omitempty"`
|
||||||
|
Servers int `mapstructure:"servers" yaml:"servers" json:"servers,omitempty"` //nolint:lll // default 1
|
||||||
|
Agents int `mapstructure:"agents" yaml:"agents" json:"agents,omitempty"` //nolint:lll // default 0
|
||||||
|
ExposeAPI SimpleExposureOpts `mapstructure:"kubeAPI" yaml:"kubeAPI" json:"kubeAPI,omitempty"`
|
||||||
|
Image string `mapstructure:"image" yaml:"image" json:"image,omitempty"`
|
||||||
|
Network string `mapstructure:"network" yaml:"network" json:"network,omitempty"`
|
||||||
|
Subnet string `mapstructure:"subnet" yaml:"subnet" json:"subnet,omitempty"`
|
||||||
|
ClusterToken string `mapstructure:"token" yaml:"clusterToken" json:"clusterToken,omitempty"` // default: auto-generated
|
||||||
|
Volumes []VolumeWithNodeFilters `mapstructure:"volumes" yaml:"volumes" json:"volumes,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"`
|
||||||
|
Env []EnvVarWithNodeFilters `mapstructure:"env" yaml:"env" json:"env,omitempty"`
|
||||||
|
Registries struct {
|
||||||
|
Use []string `mapstructure:"use" yaml:"use,omitempty" json:"use,omitempty"`
|
||||||
|
Create bool `mapstructure:"create" yaml:"create,omitempty" json:"create,omitempty"`
|
||||||
|
Config string `mapstructure:"config" yaml:"config,omitempty" json:"config,omitempty"` // registries.yaml (k3s config for containerd registry override)
|
||||||
|
} `mapstructure:"registries" yaml:"registries,omitempty" json:"registries,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimpleExposureOpts provides a simplified syntax compared to the original k3d.ExposureOpts
|
||||||
|
type SimpleExposureOpts struct {
|
||||||
|
Host string `mapstructure:"host" yaml:"host,omitempty" json:"host,omitempty"`
|
||||||
|
HostIP string `mapstructure:"hostIP" yaml:"hostIP,omitempty" json:"hostIP,omitempty"`
|
||||||
|
HostPort string `mapstructure:"hostPort" yaml:"hostPort,omitempty" json:"hostPort,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKind implements Config.GetKind
|
||||||
|
func (c SimpleConfig) GetKind() string {
|
||||||
|
return "Simple"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c SimpleConfig) GetAPIVersion() string {
|
||||||
|
return ApiVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClusterConfig describes a single cluster config
|
||||||
|
type ClusterConfig struct {
|
||||||
|
config.TypeMeta `mapstructure:",squash" yaml:",inline"`
|
||||||
|
Cluster k3d.Cluster `mapstructure:",squash" yaml:",inline"`
|
||||||
|
ClusterCreateOpts k3d.ClusterCreateOpts `mapstructure:"options" yaml:"options"`
|
||||||
|
KubeconfigOpts SimpleConfigOptionsKubeconfig `mapstructure:"kubeconfig" yaml:"kubeconfig"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKind implements Config.GetKind
|
||||||
|
func (c ClusterConfig) GetKind() string {
|
||||||
|
return "Simple"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ClusterConfig) GetAPIVersion() string {
|
||||||
|
return ApiVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClusterListConfig describes a list of clusters
|
||||||
|
type ClusterListConfig struct {
|
||||||
|
config.TypeMeta `mapstructure:",squash" yaml:",inline"`
|
||||||
|
Clusters []k3d.Cluster `mapstructure:"clusters" yaml:"clusters"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ClusterListConfig) GetKind() string {
|
||||||
|
return "Simple"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ClusterListConfig) GetAPIVersion() string {
|
||||||
|
return ApiVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetConfigByKind(kind string) (config.Config, error) {
|
||||||
|
|
||||||
|
// determine config kind
|
||||||
|
switch strings.ToLower(kind) {
|
||||||
|
case "simple":
|
||||||
|
return SimpleConfig{}, nil
|
||||||
|
case "cluster":
|
||||||
|
return ClusterConfig{}, nil
|
||||||
|
case "clusterlist":
|
||||||
|
return ClusterListConfig{}, nil
|
||||||
|
case "":
|
||||||
|
return nil, fmt.Errorf("missing `kind` in config file")
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown `kind` '%s' in config file", kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -27,7 +27,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
k3dc "github.com/rancher/k3d/v4/pkg/client"
|
k3dc "github.com/rancher/k3d/v4/pkg/client"
|
||||||
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha2"
|
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||||
"github.com/rancher/k3d/v4/pkg/runtimes"
|
"github.com/rancher/k3d/v4/pkg/runtimes"
|
||||||
runtimeutil "github.com/rancher/k3d/v4/pkg/runtimes/util"
|
runtimeutil "github.com/rancher/k3d/v4/pkg/runtimes/util"
|
||||||
k3d "github.com/rancher/k3d/v4/pkg/types"
|
k3d "github.com/rancher/k3d/v4/pkg/types"
|
||||||
|
@ -26,7 +26,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha2"
|
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||||
"github.com/rancher/k3d/v4/pkg/runtimes"
|
"github.com/rancher/k3d/v4/pkg/runtimes"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
@ -184,8 +184,6 @@ type ClusterCreateOpts struct {
|
|||||||
WaitForServer bool `yaml:"waitForServer" json:"waitForServer,omitempty"`
|
WaitForServer bool `yaml:"waitForServer" json:"waitForServer,omitempty"`
|
||||||
Timeout time.Duration `yaml:"timeout" json:"timeout,omitempty"`
|
Timeout time.Duration `yaml:"timeout" json:"timeout,omitempty"`
|
||||||
DisableLoadBalancer bool `yaml:"disableLoadbalancer" json:"disableLoadbalancer,omitempty"`
|
DisableLoadBalancer bool `yaml:"disableLoadbalancer" json:"disableLoadbalancer,omitempty"`
|
||||||
K3sServerArgs []string `yaml:"k3sServerArgs" json:"k3sServerArgs,omitempty"`
|
|
||||||
K3sAgentArgs []string `yaml:"k3sAgentArgs" json:"k3sAgentArgs,omitempty"`
|
|
||||||
GPURequest string `yaml:"gpuRequest" json:"gpuRequest,omitempty"`
|
GPURequest string `yaml:"gpuRequest" json:"gpuRequest,omitempty"`
|
||||||
ServersMemory string `yaml:"serversMemory" json:"serversMemory,omitempty"`
|
ServersMemory string `yaml:"serversMemory" json:"serversMemory,omitempty"`
|
||||||
AgentsMemory string `yaml:"agentsMemory" json:"agentsMemory,omitempty"`
|
AgentsMemory string `yaml:"agentsMemory" json:"agentsMemory,omitempty"`
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
apiVersion: k3d.io/v1alpha2
|
apiVersion: k3d.io/v1alpha3
|
||||||
kind: Simple
|
kind: Simple
|
||||||
name: test
|
name: test
|
||||||
servers: 3
|
servers: 3
|
||||||
@ -43,9 +43,10 @@ options:
|
|||||||
disableLoadbalancer: false
|
disableLoadbalancer: false
|
||||||
disableImageVolume: false
|
disableImageVolume: false
|
||||||
k3s:
|
k3s:
|
||||||
extraServerArgs:
|
extraArgs:
|
||||||
- --tls-san=127.0.0.1
|
- arg: --tls-san=127.0.0.1
|
||||||
extraAgentArgs: []
|
nodeFilters:
|
||||||
|
- server[*]
|
||||||
kubeconfig:
|
kubeconfig:
|
||||||
updateDefaultKubeconfig: true
|
updateDefaultKubeconfig: true
|
||||||
switchCurrentContext: true
|
switchCurrentContext: true
|
51
tests/assets/config_test_simple_migration_v1alpha2.yaml
Executable file
51
tests/assets/config_test_simple_migration_v1alpha2.yaml
Executable file
@ -0,0 +1,51 @@
|
|||||||
|
apiVersion: k3d.io/v1alpha2
|
||||||
|
kind: Simple
|
||||||
|
name: test
|
||||||
|
servers: 3
|
||||||
|
agents: 2
|
||||||
|
kubeAPI:
|
||||||
|
hostIP: "0.0.0.0"
|
||||||
|
hostPort: "6446"
|
||||||
|
image: rancher/k3s:latest
|
||||||
|
volumes:
|
||||||
|
- volume: /my/path:/some/path
|
||||||
|
nodeFilters:
|
||||||
|
- all
|
||||||
|
ports:
|
||||||
|
- port: 80:80
|
||||||
|
nodeFilters:
|
||||||
|
- loadbalancer
|
||||||
|
- port: 0.0.0.0:443:443
|
||||||
|
nodeFilters:
|
||||||
|
- loadbalancer
|
||||||
|
env:
|
||||||
|
- envVar: bar=baz,bob
|
||||||
|
nodeFilters:
|
||||||
|
- all
|
||||||
|
labels:
|
||||||
|
- label: foo=bar
|
||||||
|
nodeFilters:
|
||||||
|
- server[0]
|
||||||
|
- loadbalancer
|
||||||
|
registries:
|
||||||
|
create: true
|
||||||
|
use: []
|
||||||
|
config: |
|
||||||
|
mirrors:
|
||||||
|
"my.company.registry":
|
||||||
|
endpoint:
|
||||||
|
- http://my.company.registry:5000
|
||||||
|
|
||||||
|
options:
|
||||||
|
k3d:
|
||||||
|
wait: true
|
||||||
|
timeout: "360s" # should be pretty high for multi-server clusters to allow for a proper startup routine
|
||||||
|
disableLoadbalancer: false
|
||||||
|
disableImageVolume: false
|
||||||
|
k3s:
|
||||||
|
extraServerArgs:
|
||||||
|
- --tls-san=127.0.0.1
|
||||||
|
extraAgentArgs: []
|
||||||
|
kubeconfig:
|
||||||
|
updateDefaultKubeconfig: true
|
||||||
|
switchCurrentContext: true
|
52
tests/assets/config_test_simple_migration_v1alpha3.yaml
Executable file
52
tests/assets/config_test_simple_migration_v1alpha3.yaml
Executable file
@ -0,0 +1,52 @@
|
|||||||
|
apiVersion: k3d.io/v1alpha3
|
||||||
|
kind: Simple
|
||||||
|
name: test
|
||||||
|
servers: 3
|
||||||
|
agents: 2
|
||||||
|
kubeAPI:
|
||||||
|
hostIP: "0.0.0.0"
|
||||||
|
hostPort: "6446"
|
||||||
|
image: rancher/k3s:latest
|
||||||
|
volumes:
|
||||||
|
- volume: /my/path:/some/path
|
||||||
|
nodeFilters:
|
||||||
|
- all
|
||||||
|
ports:
|
||||||
|
- port: 80:80
|
||||||
|
nodeFilters:
|
||||||
|
- loadbalancer
|
||||||
|
- port: 0.0.0.0:443:443
|
||||||
|
nodeFilters:
|
||||||
|
- loadbalancer
|
||||||
|
env:
|
||||||
|
- envVar: bar=baz,bob
|
||||||
|
nodeFilters:
|
||||||
|
- all
|
||||||
|
labels:
|
||||||
|
- label: foo=bar
|
||||||
|
nodeFilters:
|
||||||
|
- server[0]
|
||||||
|
- loadbalancer
|
||||||
|
registries:
|
||||||
|
create: true
|
||||||
|
use: []
|
||||||
|
config: |
|
||||||
|
mirrors:
|
||||||
|
"my.company.registry":
|
||||||
|
endpoint:
|
||||||
|
- http://my.company.registry:5000
|
||||||
|
|
||||||
|
options:
|
||||||
|
k3d:
|
||||||
|
wait: true
|
||||||
|
timeout: "360s" # should be pretty high for multi-server clusters to allow for a proper startup routine
|
||||||
|
disableLoadbalancer: false
|
||||||
|
disableImageVolume: false
|
||||||
|
k3s:
|
||||||
|
extraArgs:
|
||||||
|
- arg: --tls-san=127.0.0.1
|
||||||
|
nodeFilters:
|
||||||
|
- server[*]
|
||||||
|
kubeconfig:
|
||||||
|
updateDefaultKubeconfig: true
|
||||||
|
switchCurrentContext: true
|
27
tests/test_config_file_migration.sh
Executable file
27
tests/test_config_file_migration.sh
Executable file
@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
CURR_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
|
[ -d "$CURR_DIR" ] || { echo "FATAL: no current dir (maybe running in zsh?)"; exit 1; }
|
||||||
|
|
||||||
|
# shellcheck source=./common.sh
|
||||||
|
source "$CURR_DIR/common.sh"
|
||||||
|
|
||||||
|
|
||||||
|
export CURRENT_STAGE="Test | config-file-migration"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
highlight "[START] ConfigMigrateTest"
|
||||||
|
|
||||||
|
tempdir=$(mktemp -d)
|
||||||
|
$EXE config migrate "$CURR_DIR/assets/config_test_simple_migration_v1alpha2.yaml" "$tempdir/expected.yaml" || failed "failed on $CURR_DIR/assets/config_test_simple.yaml"
|
||||||
|
$EXE config migrate "$CURR_DIR/assets/config_test_simple_migration_v1alpha3.yaml" "$tempdir/actual.yaml" || failed "failed on $CURR_DIR/assets/config_test_simple_migrate.yaml"
|
||||||
|
|
||||||
|
diff "$tempdir/actual.yaml" "$tempdir/expected.yaml" || failed "config migration failed" && passed "config migration succeeded"
|
||||||
|
|
||||||
|
|
||||||
|
highlight "[DONE] ConfigMigrateTest"
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user