[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"
|
||||
k3dCluster "github.com/rancher/k3d/v4/pkg/client"
|
||||
"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"
|
||||
k3d "github.com/rancher/k3d/v4/pkg/types"
|
||||
"github.com/rancher/k3d/v4/version"
|
||||
@ -77,11 +77,6 @@ func initConfig() {
|
||||
if _, err := os.Stat(configFile); err != nil {
|
||||
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)
|
||||
if err := cfgViper.ReadInConfig(); err != nil {
|
||||
@ -92,7 +87,16 @@ func initConfig() {
|
||||
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 {
|
||||
c, _ := yaml.Marshal(cfgViper.AllSettings())
|
||||
@ -121,19 +125,35 @@ func NewCmdClusterCreate() *cobra.Command {
|
||||
/*************************
|
||||
* 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 {
|
||||
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 {
|
||||
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 *
|
||||
@ -141,10 +161,10 @@ func NewCmdClusterCreate() *cobra.Command {
|
||||
|
||||
// Set the name
|
||||
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 {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
@ -178,7 +198,7 @@ func NewCmdClusterCreate() *cobra.Command {
|
||||
if err := k3dCluster.ClusterRun(cmd.Context(), runtimes.SelectedRuntime, clusterConfig); err != nil {
|
||||
// rollback if creation failed
|
||||
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.")
|
||||
}
|
||||
// rollback if creation failed
|
||||
@ -202,7 +222,7 @@ func NewCmdClusterCreate() *cobra.Command {
|
||||
|
||||
if clusterConfig.KubeconfigOpts.UpdateDefaultKubeconfig {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -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]\"`")
|
||||
_ = 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 *
|
||||
******************
|
||||
@ -340,13 +364,6 @@ func NewCmdClusterCreate() *cobra.Command {
|
||||
cmd.Flags().String("registry-config", "", "Specify path to an extra registries.yaml file")
|
||||
_ = 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 */
|
||||
|
||||
// done
|
||||
@ -520,5 +537,30 @@ func applyCLIOverrides(cfg conf.SimpleConfig) (conf.SimpleConfig, error) {
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ func NewCmdConfig() *cobra.Command {
|
||||
}
|
||||
|
||||
cmd.AddCommand(NewCmdConfigInit())
|
||||
cmd.AddCommand(NewCmdConfigMigrate())
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
config "github.com/rancher/k3d/v4/pkg/config/v1alpha2"
|
||||
config "github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"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
|
||||
|
||||
- may required a `replace github.com/rancher/k3d/v4 => PATH/TO/LOCAL/REPO` in the `go.mod`
|
||||
|
||||
```bash
|
||||
# ensure that you're in the docgen dir, as the relative path to the docs/ dir is hardcoded
|
||||
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]
|
||||
-h, --help help for create
|
||||
-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-server-arg k3s server Additional args passed to the k3s server command on server nodes (new flag per arg)
|
||||
--k3s-arg ARG@NODEFILTER[;@NODEFILTER] Additional args passed to k3s command (Format: ARG@NODEFILTER[;@NODEFILTER])
|
||||
- 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-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...]]
|
||||
|
@ -28,4 +28,5 @@ k3d config [flags]
|
||||
|
||||
* [k3d](k3d.md) - https://k3d.io/ -> Run k3s in Docker!
|
||||
* [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
|
||||
|
||||
```
|
||||
-h, --help help for docgen
|
||||
-h, --help help for migrate
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
@ -22,5 +22,5 @@ k3d docgen [flags]
|
||||
|
||||
### SEE ALSO
|
||||
|
||||
* [k3d](k3d.md) - https://k3d.io/ -> Run k3s in Docker!
|
||||
* [k3d config](k3d_config.md) - Work with config file(s)
|
||||
|
@ -16,6 +16,7 @@ k3d node create NAME [flags]
|
||||
-c, --cluster string Select the cluster that the node shall connect to. (default "k3s-default")
|
||||
-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")
|
||||
--k3s-node-label strings Specify k3s node labels in format "foo=bar"
|
||||
--memory string Memory limit imposed on the node [From docker]
|
||||
--replicas int Number of replicas of this node specification. (default 1)
|
||||
--role string Specify node role [server, agent] (default "agent")
|
||||
|
@ -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:
|
||||
|
||||
- `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)
|
||||
|
||||
So this would be the minimal config file, which configures absolutely nothing:
|
||||
|
||||
```yaml
|
||||
apiVersion: k3d.io/v1alpha2
|
||||
apiVersion: k3d.io/v1alpha3
|
||||
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"
|
||||
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 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
|
||||
|
||||
@ -51,7 +51,7 @@ Since the config options and the config file are changing quite a bit, it's hard
|
||||
|
||||
```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
|
||||
name: mycluster # name that you want to give to your cluster (will still be prefixed with `k3d-`)
|
||||
servers: 1 # same as `--servers 1`
|
||||
@ -98,9 +98,10 @@ options:
|
||||
disableRollback: false # same as `--no-Rollback`
|
||||
disableHostIPInjection: false # same as `--no-hostip`
|
||||
k3s: # options passed on to K3s itself
|
||||
extraServerArgs: # additional arguments passed to the `k3s server` command; same as `--k3s-server-arg`
|
||||
- --tls-san=my.host.domain
|
||||
extraAgentArgs: [] # addditional arguments passed to the `k3s agent` command; same as `--k3s-agent-arg`
|
||||
extraArgs: # additional arguments passed to the `k3s server|agent` command; same as `--k3s-arg`
|
||||
- arg: --tls-san=my.host.domain
|
||||
nodeFilters:
|
||||
- server[*]
|
||||
kubeconfig:
|
||||
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)
|
||||
|
@ -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:
|
||||
|
||||
```yaml
|
||||
apiVersion: k3d.io/v1alpha2
|
||||
apiVersion: k3d.io/v1alpha3
|
||||
kind: Simple
|
||||
name: test
|
||||
servers: 1
|
||||
|
@ -36,7 +36,7 @@ import (
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/imdario/mergo"
|
||||
"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"
|
||||
"github.com/rancher/k3d/v4/pkg/runtimes/docker"
|
||||
runtimeErr "github.com/rancher/k3d/v4/pkg/runtimes/errors"
|
||||
|
@ -29,43 +29,51 @@ import (
|
||||
|
||||
"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
|
||||
|
||||
// determine config kind
|
||||
if config.GetString("kind") != "" && strings.ToLower(config.GetString("kind")) != "simple" {
|
||||
return cfg, fmt.Errorf("Wrong `kind` '%s' != 'simple' in config file", config.GetString("kind"))
|
||||
var Schemas = map[string]string{
|
||||
v1alpha2.ApiVersion: v1alpha2.JSONSchema,
|
||||
v1alpha3.ApiVersion: v1alpha3.JSONSchema,
|
||||
}
|
||||
|
||||
if err := config.Unmarshal(&cfg); err != nil {
|
||||
log.Errorln("Failed to unmarshal File config")
|
||||
|
||||
return cfg, err
|
||||
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
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
func FromViper(config *viper.Viper) (types.Config, error) {
|
||||
|
||||
func FromViper(config *viper.Viper) (conf.Config, error) {
|
||||
var cfg types.Config
|
||||
var err error
|
||||
|
||||
var cfg conf.Config
|
||||
apiVersion := strings.ToLower(config.GetString("apiversion"))
|
||||
kind := strings.ToLower(config.GetString("kind"))
|
||||
|
||||
// determine config kind
|
||||
switch strings.ToLower(config.GetString("kind")) {
|
||||
case "simple":
|
||||
cfg = conf.SimpleConfig{}
|
||||
case "cluster":
|
||||
cfg = conf.ClusterConfig{}
|
||||
case "clusterlist":
|
||||
cfg = conf.ClusterListConfig{}
|
||||
log.Tracef("Trying to read config apiVersion='%s', kind='%s'", apiVersion, kind)
|
||||
|
||||
switch apiVersion {
|
||||
case "k3d.io/v1alpha2":
|
||||
cfg, err = v1alpha2.GetConfigByKind(kind)
|
||||
case "k3d.io/v1alpha3":
|
||||
cfg, err = v1alpha3.GetConfigByKind(kind)
|
||||
case "":
|
||||
return nil, fmt.Errorf("Missing `kind` in config file")
|
||||
cfg, err = defaultConfig.GetConfigByKind(kind)
|
||||
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 {
|
||||
@ -76,3 +84,12 @@ func FromViper(config *viper.Viper) (conf.Config, error) {
|
||||
|
||||
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"
|
||||
|
||||
"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"
|
||||
|
||||
k3d "github.com/rancher/k3d/v4/pkg/types"
|
||||
@ -39,8 +40,8 @@ func TestReadSimpleConfig(t *testing.T) {
|
||||
exposedAPI.HostPort = "6443"
|
||||
|
||||
expectedConfig := conf.SimpleConfig{
|
||||
TypeMeta: conf.TypeMeta{
|
||||
APIVersion: "k3d.io/v1alpha2",
|
||||
TypeMeta: configtypes.TypeMeta{
|
||||
APIVersion: "k3d.io/v1alpha3",
|
||||
Kind: "Simple",
|
||||
},
|
||||
Name: "test",
|
||||
@ -83,8 +84,12 @@ func TestReadSimpleConfig(t *testing.T) {
|
||||
DisableImageVolume: false,
|
||||
},
|
||||
K3sOptions: conf.SimpleConfigOptionsK3s{
|
||||
ExtraServerArgs: []string{"--tls-san=127.0.0.1"},
|
||||
ExtraAgentArgs: []string{},
|
||||
ExtraArgs: []conf.K3sArgWithNodeFilters{
|
||||
{
|
||||
Arg: "--tls-san=127.0.0.1",
|
||||
NodeFilters: []string{"server[*]"},
|
||||
},
|
||||
},
|
||||
},
|
||||
KubeconfigOptions: conf.SimpleConfigOptionsKubeconfig{
|
||||
UpdateDefaultKubeconfig: true,
|
||||
@ -107,7 +112,7 @@ func TestReadSimpleConfig(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
cfg, err := FromViperSimple(config)
|
||||
cfg, err := FromViper(config)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@ -123,8 +128,8 @@ func TestReadSimpleConfig(t *testing.T) {
|
||||
func TestReadClusterConfig(t *testing.T) {
|
||||
|
||||
expectedConfig := conf.ClusterConfig{
|
||||
TypeMeta: conf.TypeMeta{
|
||||
APIVersion: "k3d.io/v1alpha2",
|
||||
TypeMeta: configtypes.TypeMeta{
|
||||
APIVersion: "k3d.io/v1alpha3",
|
||||
Kind: "Cluster",
|
||||
},
|
||||
Cluster: k3d.Cluster{
|
||||
@ -168,8 +173,8 @@ func TestReadClusterConfig(t *testing.T) {
|
||||
func TestReadClusterListConfig(t *testing.T) {
|
||||
|
||||
expectedConfig := conf.ClusterListConfig{
|
||||
TypeMeta: conf.TypeMeta{
|
||||
APIVersion: "k3d.io/v1alpha2",
|
||||
TypeMeta: configtypes.TypeMeta{
|
||||
APIVersion: "k3d.io/v1alpha3",
|
||||
Kind: "ClusterList",
|
||||
},
|
||||
Clusters: []k3d.Cluster{
|
||||
@ -237,7 +242,7 @@ func TestReadUnknownConfig(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err := FromViperSimple(config)
|
||||
_, err := FromViper(config)
|
||||
if err == nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
@ -24,14 +24,14 @@ package config
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/rancher/k3d/v4/pkg/config/v1alpha2"
|
||||
"github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||
)
|
||||
|
||||
func TestValidateSchema(t *testing.T) {
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ func TestValidateSchemaFail(t *testing.T) {
|
||||
cfgPath := "./test_assets/config_test_simple_invalid_servers.yaml"
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ package config
|
||||
|
||||
import (
|
||||
"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"
|
||||
)
|
||||
|
||||
|
@ -25,7 +25,8 @@ package config
|
||||
import (
|
||||
"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"
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
@ -34,7 +35,7 @@ func TestMergeSimpleConfig(t *testing.T) {
|
||||
srcConfig := "./test_assets/config_test_simple.yaml"
|
||||
destConfig := "./test_assets/config_test_simple_2.yaml"
|
||||
|
||||
var src, dest conf.Config
|
||||
var src, dest configtypes.Config
|
||||
var err error
|
||||
|
||||
cfg1 := viper.New()
|
||||
@ -45,11 +46,11 @@ func TestMergeSimpleConfig(t *testing.T) {
|
||||
cfg2.SetConfigFile(destConfig)
|
||||
_ = cfg2.ReadInConfig()
|
||||
|
||||
if src, err = FromViperSimple(cfg1); err != nil {
|
||||
if src, err = FromViper(cfg1); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if dest, err = FromViperSimple(cfg2); err != nil {
|
||||
if dest, err = FromViper(cfg2); err != nil {
|
||||
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
|
||||
|
||||
import (
|
||||
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha2"
|
||||
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
|
@ -26,6 +26,7 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||
"github.com/rancher/k3d/v4/pkg/runtimes"
|
||||
"github.com/spf13/viper"
|
||||
"gotest.tools/assert"
|
||||
@ -38,14 +39,14 @@ func TestProcessClusterConfig(t *testing.T) {
|
||||
vip.SetConfigFile(cfgFile)
|
||||
_ = vip.ReadInConfig()
|
||||
|
||||
cfg, err := FromViperSimple(vip)
|
||||
cfg, err := FromViper(vip)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
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 {
|
||||
t.Error(err)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
apiVersion: k3d.io/v1alpha2
|
||||
apiVersion: k3d.io/v1alpha3
|
||||
kind: Cluster
|
||||
name: foo
|
||||
nodes:
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
apiVersion: k3d.io/v1alpha2
|
||||
apiVersion: k3d.io/v1alpha3
|
||||
kind: ClusterList
|
||||
clusters:
|
||||
- name: foo
|
||||
|
@ -1,4 +1,4 @@
|
||||
apiVersion: k3d.io/v1alpha2
|
||||
apiVersion: k3d.io/v1alpha3
|
||||
kind: Simple
|
||||
name: test
|
||||
servers: 1
|
||||
@ -25,7 +25,7 @@ env:
|
||||
labels:
|
||||
- label: foo=bar
|
||||
nodeFilters:
|
||||
- server[0]
|
||||
- "server[0]"
|
||||
- loadbalancer
|
||||
|
||||
options:
|
||||
@ -35,9 +35,10 @@ options:
|
||||
disableLoadbalancer: false
|
||||
disableImageVolume: false
|
||||
k3s:
|
||||
extraServerArgs:
|
||||
- --tls-san=127.0.0.1
|
||||
extraAgentArgs: []
|
||||
extraArgs:
|
||||
- arg: --tls-san=127.0.0.1
|
||||
nodeFilters:
|
||||
- "server[*]"
|
||||
kubeconfig:
|
||||
updateDefaultKubeconfig: true
|
||||
switchCurrentContext: true
|
@ -1,4 +1,4 @@
|
||||
apiVersion: k3d.io/v1alpha2
|
||||
apiVersion: k3d.io/v1alpha3
|
||||
kind: Simple
|
||||
name: supertest
|
||||
agents: 8
|
@ -1,4 +1,4 @@
|
||||
apiVersion: k3d.io/v1alpha2
|
||||
apiVersion: k3d.io/v1alpha3
|
||||
kind: Simple
|
||||
name: 1234
|
||||
servers: 1
|
||||
@ -35,9 +35,10 @@ options:
|
||||
disableLoadbalancer: false
|
||||
disableImageVolume: false
|
||||
k3s:
|
||||
extraServerArgs:
|
||||
- --tls-san=127.0.0.1
|
||||
extraAgentArgs: []
|
||||
extraArgs:
|
||||
- arg: --tls-san=127.0.0.1
|
||||
nodeFilters:
|
||||
- "server[*]"
|
||||
kubeconfig:
|
||||
updateDefaultKubeconfig: true
|
||||
switchCurrentContext: true
|
@ -1,3 +1,3 @@
|
||||
apiVersion: k3d.io/v1alpha2
|
||||
apiVersion: k3d.io/v1alpha3
|
||||
kind: Unknown
|
||||
foo: bar
|
@ -31,7 +31,7 @@ import (
|
||||
|
||||
"github.com/docker/go-connections/nat"
|
||||
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"
|
||||
k3d "github.com/rancher/k3d/v4/pkg/types"
|
||||
"github.com/rancher/k3d/v4/pkg/types/k3s"
|
||||
@ -117,7 +117,6 @@ func TransformSimpleToClusterConfig(ctx context.Context, runtime runtimes.Runtim
|
||||
serverNode := k3d.Node{
|
||||
Role: k3d.ServerRole,
|
||||
Image: simpleConfig.Image,
|
||||
Args: simpleConfig.Options.K3sOptions.ExtraServerArgs,
|
||||
ServerOpts: k3d.ServerOpts{},
|
||||
Memory: simpleConfig.Options.Runtime.ServersMemory,
|
||||
}
|
||||
@ -135,7 +134,6 @@ func TransformSimpleToClusterConfig(ctx context.Context, runtime runtimes.Runtim
|
||||
agentNode := k3d.Node{
|
||||
Role: k3d.AgentRole,
|
||||
Image: simpleConfig.Image,
|
||||
Args: simpleConfig.Options.K3sOptions.ExtraAgentArgs,
|
||||
Memory: simpleConfig.Options.Runtime.AgentsMemory,
|
||||
}
|
||||
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 *
|
||||
**************************/
|
||||
@ -238,8 +252,6 @@ func TransformSimpleToClusterConfig(ctx context.Context, runtime runtimes.Runtim
|
||||
WaitForServer: simpleConfig.Options.K3dOptions.Wait,
|
||||
Timeout: simpleConfig.Options.K3dOptions.Timeout,
|
||||
DisableLoadBalancer: simpleConfig.Options.K3dOptions.DisableLoadbalancer,
|
||||
K3sServerArgs: simpleConfig.Options.K3sOptions.ExtraServerArgs,
|
||||
K3sAgentArgs: simpleConfig.Options.K3sOptions.ExtraAgentArgs,
|
||||
GPURequest: simpleConfig.Options.Runtime.GPURequest,
|
||||
ServersMemory: simpleConfig.Options.Runtime.ServersMemory,
|
||||
AgentsMemory: simpleConfig.Options.Runtime.AgentsMemory,
|
||||
|
@ -26,6 +26,7 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
conf "github.com/rancher/k3d/v4/pkg/config/v1alpha3"
|
||||
"github.com/rancher/k3d/v4/pkg/runtimes"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
@ -37,14 +38,14 @@ func TestTransformSimpleConfigToClusterConfig(t *testing.T) {
|
||||
vip.SetConfigFile(cfgFile)
|
||||
_ = vip.ReadInConfig()
|
||||
|
||||
cfg, err := FromViperSimple(vip)
|
||||
cfg, err := FromViper(vip)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
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 {
|
||||
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"
|
||||
"time"
|
||||
|
||||
configtypes "github.com/rancher/k3d/v4/pkg/config/types"
|
||||
k3d "github.com/rancher/k3d/v4/pkg/types"
|
||||
"github.com/rancher/k3d/v4/version"
|
||||
)
|
||||
@ -35,9 +36,11 @@ import (
|
||||
//go:embed schema.json
|
||||
var JSONSchema string
|
||||
|
||||
const ApiVersion = "k3d.io/v1alpha2"
|
||||
|
||||
// DefaultConfigTpl for printing
|
||||
const DefaultConfigTpl = `---
|
||||
apiVersion: k3d.io/v1alpha2
|
||||
apiVersion: %s
|
||||
kind: Simple
|
||||
name: %s
|
||||
servers: 1
|
||||
@ -48,21 +51,11 @@ image: %s
|
||||
// DefaultConfig templated DefaultConfigTpl
|
||||
var DefaultConfig = fmt.Sprintf(
|
||||
DefaultConfigTpl,
|
||||
ApiVersion,
|
||||
k3d.DefaultClusterName,
|
||||
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 {
|
||||
Volume string `mapstructure:"volume" yaml:"volume" json:"volume,omitempty"`
|
||||
NodeFilters []string `mapstructure:"nodeFilters" yaml:"nodeFilters" json:"nodeFilters,omitempty"`
|
||||
@ -119,7 +112,7 @@ type SimpleConfigOptionsK3s struct {
|
||||
|
||||
// SimpleConfig describes the toplevel k3d configuration file.
|
||||
type SimpleConfig struct {
|
||||
TypeMeta `mapstructure:",squash" yaml:",inline"`
|
||||
configtypes.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
|
||||
@ -147,30 +140,60 @@ type SimpleExposureOpts struct {
|
||||
HostPort string `mapstructure:"hostPort" yaml:"hostPort,omitempty" json:"hostPort,omitempty"`
|
||||
}
|
||||
|
||||
// GetKind implements Config.GetKind
|
||||
// Kind implements Config.Kind
|
||||
func (c SimpleConfig) GetKind() string {
|
||||
return "Cluster"
|
||||
return "Simple"
|
||||
}
|
||||
|
||||
func (c SimpleConfig) GetAPIVersion() string {
|
||||
return ApiVersion
|
||||
}
|
||||
|
||||
// ClusterConfig describes a single cluster config
|
||||
type ClusterConfig struct {
|
||||
TypeMeta `mapstructure:",squash" yaml:",inline"`
|
||||
configtypes.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
|
||||
// Kind implements Config.Kind
|
||||
func (c ClusterConfig) GetKind() string {
|
||||
return "Cluster"
|
||||
return "Simple"
|
||||
}
|
||||
|
||||
func (c ClusterConfig) GetAPIVersion() string {
|
||||
return ApiVersion
|
||||
}
|
||||
|
||||
// ClusterListConfig describes a list of clusters
|
||||
type ClusterListConfig struct {
|
||||
TypeMeta `mapstructure:",squash" yaml:",inline"`
|
||||
configtypes.TypeMeta `mapstructure:",squash" yaml:",inline"`
|
||||
Clusters []k3d.Cluster `mapstructure:"clusters" yaml:"clusters"`
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
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"
|
||||
runtimeutil "github.com/rancher/k3d/v4/pkg/runtimes/util"
|
||||
k3d "github.com/rancher/k3d/v4/pkg/types"
|
||||
|
@ -26,7 +26,7 @@ import (
|
||||
"context"
|
||||
"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/spf13/viper"
|
||||
)
|
||||
|
@ -184,8 +184,6 @@ type ClusterCreateOpts struct {
|
||||
WaitForServer bool `yaml:"waitForServer" json:"waitForServer,omitempty"`
|
||||
Timeout time.Duration `yaml:"timeout" json:"timeout,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"`
|
||||
ServersMemory string `yaml:"serversMemory" json:"serversMemory,omitempty"`
|
||||
AgentsMemory string `yaml:"agentsMemory" json:"agentsMemory,omitempty"`
|
||||
|
@ -1,4 +1,4 @@
|
||||
apiVersion: k3d.io/v1alpha2
|
||||
apiVersion: k3d.io/v1alpha3
|
||||
kind: Simple
|
||||
name: test
|
||||
servers: 3
|
||||
@ -43,9 +43,10 @@ options:
|
||||
disableLoadbalancer: false
|
||||
disableImageVolume: false
|
||||
k3s:
|
||||
extraServerArgs:
|
||||
- --tls-san=127.0.0.1
|
||||
extraAgentArgs: []
|
||||
extraArgs:
|
||||
- arg: --tls-san=127.0.0.1
|
||||
nodeFilters:
|
||||
- server[*]
|
||||
kubeconfig:
|
||||
updateDefaultKubeconfig: 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