mirror of https://github.com/k3d-io/k3d
[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 migrationpull/670/head
parent
296f24c9b7
commit
261ac0faf4
@ -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 |
||||
} |
@ -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) |
||||
|
||||
} |
@ -1,4 +1,4 @@ |
||||
apiVersion: k3d.io/v1alpha2 |
||||
apiVersion: k3d.io/v1alpha3 |
||||
kind: Simple |
||||
name: supertest |
||||
agents: 8 |
@ -1,3 +1,3 @@ |
||||
apiVersion: k3d.io/v1alpha2 |
||||
apiVersion: k3d.io/v1alpha3 |
||||
kind: Unknown |
||||
foo: bar |
@ -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 |
||||
} |
@ -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 |
||||
|
||||
} |
@ -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" |
||||
] |
||||
} |
||||
} |
||||
} |
@ -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) |
||||
} |
||||
|
||||
} |
@ -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 |
@ -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 |
@ -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