From 08bf145e954583ad54a7c9ef0ecca06444d40628 Mon Sep 17 00:00:00 2001 From: Thorsten Klein Date: Fri, 28 Jan 2022 21:09:17 +0100 Subject: [PATCH] [Feature] Config v1alpha4 (#944) - add: hostAliases - add: hostPidMode --- cmd/cluster/clusterCreate.go | 2 +- cmd/cluster/clusterEdit.go | 2 +- cmd/config/configInit.go | 2 +- docs/usage/configfile.md | 8 +- docs/usage/registries.md | 2 +- pkg/client/cluster.go | 2 +- pkg/client/ports.go | 2 +- pkg/config/config.go | 8 +- pkg/config/config.versions.schema.json | 13 + pkg/config/config_test.go | 10 +- pkg/config/jsonschema_test.go | 6 +- pkg/config/merge.go | 2 +- pkg/config/merge_test.go | 2 +- pkg/config/migrate_test.go | 8 + pkg/config/process.go | 2 +- pkg/config/process_test.go | 2 +- .../test_assets/config_test_cluster.yaml | 4 +- .../test_assets/config_test_cluster_list.yaml | 4 +- .../test_assets/config_test_registries.yaml | 2 +- .../test_assets/config_test_simple.yaml | 2 +- .../test_assets/config_test_simple_2.yaml | 4 +- .../config_test_simple_invalid_servers.yaml | 2 +- .../test_assets/config_test_unknown.yaml | 4 +- pkg/config/transform.go | 2 +- pkg/config/transform_test.go | 2 +- pkg/config/v1alpha3/schema.json | 18 - pkg/config/v1alpha3/types.go | 3 - pkg/config/v1alpha4/migrations.go | 56 +++ pkg/config/v1alpha4/schema.json | 347 ++++++++++++++++++ pkg/config/v1alpha4/types.go | 218 +++++++++++ pkg/config/validate.go | 2 +- pkg/config/validate_test.go | 2 +- tests/assets/config_env.yaml | 2 +- tests/assets/config_test_simple.yaml | 2 +- tests/test_config_file_migration.sh | 1 + 35 files changed, 689 insertions(+), 61 deletions(-) create mode 100644 pkg/config/v1alpha4/migrations.go create mode 100644 pkg/config/v1alpha4/schema.json create mode 100644 pkg/config/v1alpha4/types.go diff --git a/cmd/cluster/clusterCreate.go b/cmd/cluster/clusterCreate.go index 8026c69b6..62bc7be83 100644 --- a/cmd/cluster/clusterCreate.go +++ b/cmd/cluster/clusterCreate.go @@ -42,7 +42,7 @@ import ( cliconfig "github.com/rancher/k3d/v5/cmd/util/config" k3dCluster "github.com/rancher/k3d/v5/pkg/client" "github.com/rancher/k3d/v5/pkg/config" - conf "github.com/rancher/k3d/v5/pkg/config/v1alpha3" + conf "github.com/rancher/k3d/v5/pkg/config/v1alpha4" l "github.com/rancher/k3d/v5/pkg/logger" "github.com/rancher/k3d/v5/pkg/runtimes" k3d "github.com/rancher/k3d/v5/pkg/types" diff --git a/cmd/cluster/clusterEdit.go b/cmd/cluster/clusterEdit.go index c3d916297..503e84c42 100644 --- a/cmd/cluster/clusterEdit.go +++ b/cmd/cluster/clusterEdit.go @@ -25,7 +25,7 @@ import ( "github.com/rancher/k3d/v5/cmd/util" cliutil "github.com/rancher/k3d/v5/cmd/util" "github.com/rancher/k3d/v5/pkg/client" - conf "github.com/rancher/k3d/v5/pkg/config/v1alpha3" + conf "github.com/rancher/k3d/v5/pkg/config/v1alpha4" l "github.com/rancher/k3d/v5/pkg/logger" "github.com/rancher/k3d/v5/pkg/runtimes" k3d "github.com/rancher/k3d/v5/pkg/types" diff --git a/cmd/config/configInit.go b/cmd/config/configInit.go index eaea36278..6d72c320d 100644 --- a/cmd/config/configInit.go +++ b/cmd/config/configInit.go @@ -25,7 +25,7 @@ import ( "fmt" "os" - config "github.com/rancher/k3d/v5/pkg/config/v1alpha3" + config "github.com/rancher/k3d/v5/pkg/config/v1alpha4" l "github.com/rancher/k3d/v5/pkg/logger" "github.com/spf13/cobra" ) diff --git a/docs/usage/configfile.md b/docs/usage/configfile.md index 7fe67a35a..80abbf42b 100644 --- a/docs/usage/configfile.md +++ b/docs/usage/configfile.md @@ -24,13 +24,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/v1alpha3`) +- `apiVersion` to match the version of the config file that you want to use (at this time it would be `apiVersion: k3d.io/v1alpha4`) - `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/v1alpha3 +apiVersion: k3d.io/v1alpha4 kind: Simple ``` @@ -42,7 +42,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 `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. + This JSON-Schema can be found in the specific config version sub-directory in the repository (e.g. [here for `v1alpha4`](https://github.com/rancher/k3d/blob/main/pkg/config/v1alpha4/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 @@ -50,7 +50,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/v1alpha3 # this will change in the future as we make everything more stable +apiVersion: k3d.io/v1alpha4 # 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` diff --git a/docs/usage/registries.md b/docs/usage/registries.md index 88e95d1f3..86bd89375 100644 --- a/docs/usage/registries.md +++ b/docs/usage/registries.md @@ -23,7 +23,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/v1alpha3 +apiVersion: k3d.io/v1alpha4 kind: Simple name: test servers: 1 diff --git a/pkg/client/cluster.go b/pkg/client/cluster.go index fd2db94bc..fbf8d09f1 100644 --- a/pkg/client/cluster.go +++ b/pkg/client/cluster.go @@ -38,7 +38,7 @@ import ( "github.com/imdario/mergo" copystruct "github.com/mitchellh/copystructure" "github.com/rancher/k3d/v5/pkg/actions" - config "github.com/rancher/k3d/v5/pkg/config/v1alpha3" + config "github.com/rancher/k3d/v5/pkg/config/v1alpha4" l "github.com/rancher/k3d/v5/pkg/logger" "github.com/rancher/k3d/v5/pkg/runtimes" k3drt "github.com/rancher/k3d/v5/pkg/runtimes" diff --git a/pkg/client/ports.go b/pkg/client/ports.go index b357caca8..b9f3e36bc 100644 --- a/pkg/client/ports.go +++ b/pkg/client/ports.go @@ -29,7 +29,7 @@ import ( "github.com/docker/go-connections/nat" "github.com/rancher/k3d/v5/pkg/config/types" - config "github.com/rancher/k3d/v5/pkg/config/v1alpha3" + config "github.com/rancher/k3d/v5/pkg/config/v1alpha4" l "github.com/rancher/k3d/v5/pkg/logger" "github.com/rancher/k3d/v5/pkg/runtimes" k3d "github.com/rancher/k3d/v5/pkg/types" diff --git a/pkg/config/config.go b/pkg/config/config.go index 3482ed38c..f9d599de0 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -31,7 +31,8 @@ import ( "github.com/rancher/k3d/v5/pkg/config/v1alpha2" "github.com/rancher/k3d/v5/pkg/config/v1alpha3" - defaultConfig "github.com/rancher/k3d/v5/pkg/config/v1alpha3" + "github.com/rancher/k3d/v5/pkg/config/v1alpha4" + defaultConfig "github.com/rancher/k3d/v5/pkg/config/v1alpha4" types "github.com/rancher/k3d/v5/pkg/config/types" ) @@ -41,6 +42,7 @@ const DefaultConfigApiVersion = defaultConfig.ApiVersion var Schemas = map[string]string{ v1alpha2.ApiVersion: v1alpha2.JSONSchema, v1alpha3.ApiVersion: v1alpha3.JSONSchema, + v1alpha4.ApiVersion: v1alpha4.JSONSchema, } func GetSchemaByVersion(apiVersion string) ([]byte, error) { @@ -66,6 +68,8 @@ func FromViper(config *viper.Viper) (types.Config, error) { cfg, err = v1alpha2.GetConfigByKind(kind) case "k3d.io/v1alpha3": cfg, err = v1alpha3.GetConfigByKind(kind) + case "k3d.io/v1alpha4": + cfg, err = v1alpha4.GetConfigByKind(kind) case "": cfg, err = defaultConfig.GetConfigByKind(kind) default: @@ -87,6 +91,8 @@ func getMigrations(version string) map[string]func(types.Config) (types.Config, switch version { case v1alpha3.ApiVersion: return v1alpha3.Migrations + case v1alpha4.ApiVersion: + return v1alpha4.Migrations default: return nil } diff --git a/pkg/config/config.versions.schema.json b/pkg/config/config.versions.schema.json index dfd299191..f1f481041 100644 --- a/pkg/config/config.versions.schema.json +++ b/pkg/config/config.versions.schema.json @@ -5,6 +5,19 @@ "type": "object", "oneOf": [ { + "allOf": [ + { + "properties": { + "version": { + "const": "v1alpha4" + } + } + }, + { + "$ref": "https://raw.githubusercontent.com/rancher/k3d/main/pkg/config/v1alpha4/schema.json" + } + ] + },{ "allOf": [ { "properties": { diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index e18375522..e7a87d794 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -27,7 +27,7 @@ import ( "github.com/go-test/deep" configtypes "github.com/rancher/k3d/v5/pkg/config/types" - conf "github.com/rancher/k3d/v5/pkg/config/v1alpha3" + conf "github.com/rancher/k3d/v5/pkg/config/v1alpha4" "github.com/spf13/viper" k3d "github.com/rancher/k3d/v5/pkg/types" @@ -41,7 +41,7 @@ func TestReadSimpleConfig(t *testing.T) { expectedConfig := conf.SimpleConfig{ TypeMeta: configtypes.TypeMeta{ - APIVersion: "k3d.io/v1alpha3", + APIVersion: "k3d.io/v1alpha4", Kind: "Simple", }, Name: "test", @@ -137,7 +137,7 @@ func TestReadClusterConfig(t *testing.T) { expectedConfig := conf.ClusterConfig{ TypeMeta: configtypes.TypeMeta{ - APIVersion: "k3d.io/v1alpha3", + APIVersion: "k3d.io/v1alpha4", Kind: "Cluster", }, Cluster: k3d.Cluster{ @@ -182,7 +182,7 @@ func TestReadClusterListConfig(t *testing.T) { expectedConfig := conf.ClusterListConfig{ TypeMeta: configtypes.TypeMeta{ - APIVersion: "k3d.io/v1alpha3", + APIVersion: "k3d.io/v1alpha4", Kind: "ClusterList", }, Clusters: []k3d.Cluster{ @@ -265,7 +265,7 @@ func TestReadSimpleConfigRegistries(t *testing.T) { expectedConfig := conf.SimpleConfig{ TypeMeta: configtypes.TypeMeta{ - APIVersion: "k3d.io/v1alpha3", + APIVersion: "k3d.io/v1alpha4", Kind: "Simple", }, Name: "test", diff --git a/pkg/config/jsonschema_test.go b/pkg/config/jsonschema_test.go index a2d9ff4c6..ddeaa655d 100644 --- a/pkg/config/jsonschema_test.go +++ b/pkg/config/jsonschema_test.go @@ -24,14 +24,14 @@ package config import ( "testing" - "github.com/rancher/k3d/v5/pkg/config/v1alpha3" + conf "github.com/rancher/k3d/v5/pkg/config/v1alpha4" ) func TestValidateSchema(t *testing.T) { cfgPath := "./test_assets/config_test_simple.yaml" - if err := ValidateSchemaFile(cfgPath, []byte(v1alpha3.JSONSchema)); err != nil { + if err := ValidateSchemaFile(cfgPath, []byte(conf.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(v1alpha3.JSONSchema)); err == nil { + if err = ValidateSchemaFile(cfgPath, []byte(conf.JSONSchema)); err == nil { t.Errorf("Validation of config file %s against the default schema passed where we expected a failure", cfgPath) } diff --git a/pkg/config/merge.go b/pkg/config/merge.go index 04816c530..13e070b53 100644 --- a/pkg/config/merge.go +++ b/pkg/config/merge.go @@ -26,7 +26,7 @@ import ( "fmt" "github.com/imdario/mergo" - conf "github.com/rancher/k3d/v5/pkg/config/v1alpha3" + conf "github.com/rancher/k3d/v5/pkg/config/v1alpha4" l "github.com/rancher/k3d/v5/pkg/logger" ) diff --git a/pkg/config/merge_test.go b/pkg/config/merge_test.go index d82f4f6b5..b1007a3da 100644 --- a/pkg/config/merge_test.go +++ b/pkg/config/merge_test.go @@ -26,7 +26,7 @@ import ( "testing" configtypes "github.com/rancher/k3d/v5/pkg/config/types" - conf "github.com/rancher/k3d/v5/pkg/config/v1alpha3" + conf "github.com/rancher/k3d/v5/pkg/config/v1alpha4" "github.com/spf13/viper" "gotest.tools/assert" ) diff --git a/pkg/config/migrate_test.go b/pkg/config/migrate_test.go index 7f08b6e3c..3fedfd7bb 100644 --- a/pkg/config/migrate_test.go +++ b/pkg/config/migrate_test.go @@ -74,3 +74,11 @@ func TestMigrateV1Alpha2ToV1Alpha3(t *testing.T) { } } + +func TestMigrateV1Alpha2ToV1Alpha4(t *testing.T) { + t.Log("not implemented") // TODO: test migration v1alpha2 to v1alpha4 +} + +func TestMigrateV1Alpha3ToV1Alpha4(t *testing.T) { + t.Log("not implemented") // TODO: test migration v1alpha3 to v1alpha4 +} diff --git a/pkg/config/process.go b/pkg/config/process.go index 0cad397f7..264ca8c1f 100644 --- a/pkg/config/process.go +++ b/pkg/config/process.go @@ -25,7 +25,7 @@ package config import ( "strings" - conf "github.com/rancher/k3d/v5/pkg/config/v1alpha3" + conf "github.com/rancher/k3d/v5/pkg/config/v1alpha4" l "github.com/rancher/k3d/v5/pkg/logger" runtimeutil "github.com/rancher/k3d/v5/pkg/runtimes/util" k3d "github.com/rancher/k3d/v5/pkg/types" diff --git a/pkg/config/process_test.go b/pkg/config/process_test.go index a46aa702c..5f301a84e 100644 --- a/pkg/config/process_test.go +++ b/pkg/config/process_test.go @@ -27,7 +27,7 @@ import ( "strings" "testing" - conf "github.com/rancher/k3d/v5/pkg/config/v1alpha3" + conf "github.com/rancher/k3d/v5/pkg/config/v1alpha4" "github.com/rancher/k3d/v5/pkg/runtimes" "github.com/rancher/k3d/v5/pkg/types/k3s" "github.com/spf13/viper" diff --git a/pkg/config/test_assets/config_test_cluster.yaml b/pkg/config/test_assets/config_test_cluster.yaml index f1a8438c6..8f0f4b5d9 100644 --- a/pkg/config/test_assets/config_test_cluster.yaml +++ b/pkg/config/test_assets/config_test_cluster.yaml @@ -1,6 +1,6 @@ -apiVersion: k3d.io/v1alpha3 +apiVersion: k3d.io/v1alpha4 kind: Cluster name: foo nodes: - name: foo-node-0 - role: server \ No newline at end of file + role: server diff --git a/pkg/config/test_assets/config_test_cluster_list.yaml b/pkg/config/test_assets/config_test_cluster_list.yaml index 9d2e55ca3..dcb04cafd 100644 --- a/pkg/config/test_assets/config_test_cluster_list.yaml +++ b/pkg/config/test_assets/config_test_cluster_list.yaml @@ -1,5 +1,5 @@ --- -apiVersion: k3d.io/v1alpha3 +apiVersion: k3d.io/v1alpha4 kind: ClusterList clusters: - name: foo @@ -9,4 +9,4 @@ clusters: - name: bar nodes: - name: bar-node-0 - role: server \ No newline at end of file + role: server diff --git a/pkg/config/test_assets/config_test_registries.yaml b/pkg/config/test_assets/config_test_registries.yaml index b136da94a..79c84d495 100644 --- a/pkg/config/test_assets/config_test_registries.yaml +++ b/pkg/config/test_assets/config_test_registries.yaml @@ -1,4 +1,4 @@ -apiVersion: k3d.io/v1alpha3 +apiVersion: k3d.io/v1alpha4 kind: Simple name: test servers: 1 diff --git a/pkg/config/test_assets/config_test_simple.yaml b/pkg/config/test_assets/config_test_simple.yaml index 9ababa90e..2f2532e67 100644 --- a/pkg/config/test_assets/config_test_simple.yaml +++ b/pkg/config/test_assets/config_test_simple.yaml @@ -1,4 +1,4 @@ -apiVersion: k3d.io/v1alpha3 +apiVersion: k3d.io/v1alpha4 kind: Simple name: test servers: 1 diff --git a/pkg/config/test_assets/config_test_simple_2.yaml b/pkg/config/test_assets/config_test_simple_2.yaml index a849e3224..35a187c64 100644 --- a/pkg/config/test_assets/config_test_simple_2.yaml +++ b/pkg/config/test_assets/config_test_simple_2.yaml @@ -1,4 +1,4 @@ -apiVersion: k3d.io/v1alpha3 +apiVersion: k3d.io/v1alpha4 kind: Simple name: supertest -agents: 8 \ No newline at end of file +agents: 8 diff --git a/pkg/config/test_assets/config_test_simple_invalid_servers.yaml b/pkg/config/test_assets/config_test_simple_invalid_servers.yaml index 6c67602c4..569e20bed 100644 --- a/pkg/config/test_assets/config_test_simple_invalid_servers.yaml +++ b/pkg/config/test_assets/config_test_simple_invalid_servers.yaml @@ -1,4 +1,4 @@ -apiVersion: k3d.io/v1alpha3 +apiVersion: k3d.io/v1alpha4 kind: Simple name: 1234 servers: 1 diff --git a/pkg/config/test_assets/config_test_unknown.yaml b/pkg/config/test_assets/config_test_unknown.yaml index 66fe0c0fa..526601967 100644 --- a/pkg/config/test_assets/config_test_unknown.yaml +++ b/pkg/config/test_assets/config_test_unknown.yaml @@ -1,3 +1,3 @@ -apiVersion: k3d.io/v1alpha3 +apiVersion: k3d.io/v1alpha4 kind: Unknown -foo: bar \ No newline at end of file +foo: bar diff --git a/pkg/config/transform.go b/pkg/config/transform.go index 2f3202db8..1a0bb3242 100644 --- a/pkg/config/transform.go +++ b/pkg/config/transform.go @@ -32,7 +32,7 @@ import ( "github.com/docker/go-connections/nat" cliutil "github.com/rancher/k3d/v5/cmd/util" // TODO: move parseapiport to pkg "github.com/rancher/k3d/v5/pkg/client" - conf "github.com/rancher/k3d/v5/pkg/config/v1alpha3" + conf "github.com/rancher/k3d/v5/pkg/config/v1alpha4" "github.com/rancher/k3d/v5/pkg/runtimes" k3d "github.com/rancher/k3d/v5/pkg/types" "github.com/rancher/k3d/v5/pkg/types/k3s" diff --git a/pkg/config/transform_test.go b/pkg/config/transform_test.go index 4e3e5963a..ec315c3cd 100644 --- a/pkg/config/transform_test.go +++ b/pkg/config/transform_test.go @@ -26,7 +26,7 @@ import ( "context" "testing" - conf "github.com/rancher/k3d/v5/pkg/config/v1alpha3" + conf "github.com/rancher/k3d/v5/pkg/config/v1alpha4" "github.com/rancher/k3d/v5/pkg/runtimes" "github.com/spf13/viper" ) diff --git a/pkg/config/v1alpha3/schema.json b/pkg/config/v1alpha3/schema.json index a65288da4..8dd6d97c9 100644 --- a/pkg/config/v1alpha3/schema.json +++ b/pkg/config/v1alpha3/schema.json @@ -304,24 +304,6 @@ }, "additionalProperties": false } - }, - "hostAliases": { - "type": "array", - "description": "Additional IP to multiple hostnames mappings", - "items": { - "type": "object", - "properties": { - "ip": { - "type": "string" - }, - "hostnames": { - "type": "array", - "items": { - "type": "string" - } - } - } - } } }, "additionalProperties": false, diff --git a/pkg/config/v1alpha3/types.go b/pkg/config/v1alpha3/types.go index 9029c9ef7..9790fba80 100644 --- a/pkg/config/v1alpha3/types.go +++ b/pkg/config/v1alpha3/types.go @@ -29,7 +29,6 @@ import ( "time" config "github.com/rancher/k3d/v5/pkg/config/types" - "github.com/rancher/k3d/v5/pkg/types" k3d "github.com/rancher/k3d/v5/pkg/types" "github.com/rancher/k3d/v5/version" ) @@ -105,7 +104,6 @@ type SimpleConfigOptionsRuntime struct { GPURequest string `mapstructure:"gpuRequest" yaml:"gpuRequest,omitempty" json:"gpuRequest,omitempty"` ServersMemory string `mapstructure:"serversMemory" yaml:"serversMemory,omitempty" json:"serversMemory,omitempty"` AgentsMemory string `mapstructure:"agentsMemory" yaml:"agentsMemory,omitempty" json:"agentsMemory,omitempty"` - HostPidMode bool `mapstructure:"hostPidMode" yaml:"hostPidMode,omitempty" json:"hostPidMode,omitempty"` Labels []LabelWithNodeFilters `mapstructure:"labels" yaml:"labels,omitempty" json:"labels,omitempty"` } @@ -156,7 +154,6 @@ type SimpleConfig struct { Options SimpleConfigOptions `mapstructure:"options" yaml:"options,omitempty" json:"options,omitempty"` Env []EnvVarWithNodeFilters `mapstructure:"env" yaml:"env,omitempty" json:"env,omitempty"` Registries SimpleConfigRegistries `mapstructure:"registries" yaml:"registries,omitempty" json:"registries,omitempty"` - HostAliases []types.HostAlias `mapstructure:"hostAliases" yaml:"hostAliases,omitempty" json:"hostAliases,omitempty"` } type SimpleConfigIntermediateV1alpha2 struct { diff --git a/pkg/config/v1alpha4/migrations.go b/pkg/config/v1alpha4/migrations.go new file mode 100644 index 000000000..cc0818761 --- /dev/null +++ b/pkg/config/v1alpha4/migrations.go @@ -0,0 +1,56 @@ +/* +Copyright © 2020-2022 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 v1alpha4 + +import ( + "fmt" + + configtypes "github.com/rancher/k3d/v5/pkg/config/types" + "github.com/rancher/k3d/v5/pkg/config/v1alpha2" + "github.com/rancher/k3d/v5/pkg/config/v1alpha3" + l "github.com/rancher/k3d/v5/pkg/logger" +) + +var Migrations = map[string]func(configtypes.Config) (configtypes.Config, error){ + v1alpha2.ApiVersion: MigrateV1Alpha2, + v1alpha3.ApiVersion: MigrateV1Alpha3, +} + +func MigrateV1Alpha2(input configtypes.Config) (configtypes.Config, error) { + l.Log().Debugln("Migrating v1alpha2 to v1alpha4") + + // first, migrate to v1alpha3 + input, err := v1alpha3.MigrateV1Alpha2(input) + if err != nil { + return nil, fmt.Errorf("error migration v1alpha2 to v1alpha3: %w", err) + } + + // then, migrate to v1alpha4 + return MigrateV1Alpha3(input) +} + +func MigrateV1Alpha3(input configtypes.Config) (configtypes.Config, error) { + l.Log().Debugln("Migrating v1alpha3 to v1alpha4") + + return input, nil +} diff --git a/pkg/config/v1alpha4/schema.json b/pkg/config/v1alpha4/schema.json new file mode 100644 index 000000000..3bd541cf4 --- /dev/null +++ b/pkg/config/v1alpha4/schema.json @@ -0,0 +1,347 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "SimpleConfig", + "type": "object", + "required": [ + "apiVersion", + "kind" + ], + "properties": { + "apiVersion": { + "type": "string", + "enum": [ + "k3d.io/v1alpha4" + ], + "default": "k3d.io/v1alpha4" + }, + "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 + } + }, + "options": { + "type": "object", + "properties": { + "k3d": { + "type": "object", + "properties": { + "wait": { + "type": "boolean", + "default": true + }, + "timeout": { + "examples": [ + "60s", + "1m", + "1m30s" + ] + }, + "disableLoadbalancer": { + "type": "boolean", + "default": false + }, + "disableImageVolume": { + "type": "boolean", + "default": false + }, + "disableRollback": { + "type": "boolean", + "default": false + }, + "loadbalancer": { + "type": "object", + "properties": { + "configOverrides": { + "type": "array", + "examples": [ + "settings.workerConnections=2048", + "settings.defaultProxyTimeout=900" + ] + } + }, + "additionalProperties": 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 + } + }, + "nodeLabels": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "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" + }, + "hostPidMode": { + "type":"boolean", + "default": false + }, + "labels": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "nodeFilters": { + "$ref": "#/definitions/nodeFilters" + } + }, + "additionalProperties": false + } + } + } + } + }, + "additionalProperties": false + }, + "env": { + "type": "array", + "items": { + "type": "object", + "properties": { + "envVar": { + "type": "string" + }, + "nodeFilters": { + "$ref": "#/definitions/nodeFilters" + } + }, + "additionalProperties": false + } + }, + "registries": { + "type": "object", + "properties": { + "create": { + "type": "object", + "description": "Create a new container image registry alongside the cluster.", + "properties": { + "name": { + "type": "string", + "examples": [ + "myregistry", + "registry.localhost" + ] + }, + "host": { + "type": "string", + "examples": [ + "0.0.0.0", + "localhost", + "127.0.0.1" + ], + "default": "0.0.0.0" + }, + "hostPort": { + "type": "string", + "examples": [ + "5000", + "2345" + ], + "default": "random" + } + }, + "additionalProperties": false + }, + "use": { + "type": "array", + "description": "Connect another container image registry to the cluster.", + "items": { + "type": "string" + }, + "examples": [ + "otherregistry:5000" + ] + }, + "config": { + "type": "string", + "description": "Reference a K3s registry configuration file or at it's contents here." + }, + "additionalProperties": false + } + }, + "hostAliases": { + "type": "array", + "description": "Additional IP to multiple hostnames mappings", + "items": { + "type": "object", + "properties": { + "ip": { + "type": "string" + }, + "hostnames": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "additionalProperties": false, + "definitions": { + "nodeFilters": { + "type": "array", + "items": { + "type": "string" + }, + "examples": [ + "loadbalancer", + "server:*", + "server:0", + "agent:1", + "all" + ] + } + } +} diff --git a/pkg/config/v1alpha4/types.go b/pkg/config/v1alpha4/types.go new file mode 100644 index 000000000..db85ef205 --- /dev/null +++ b/pkg/config/v1alpha4/types.go @@ -0,0 +1,218 @@ +/* +Copyright © 2020-2022 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 v1alpha4 + +import ( + _ "embed" + "fmt" + "strings" + "time" + + config "github.com/rancher/k3d/v5/pkg/config/types" + k3d "github.com/rancher/k3d/v5/pkg/types" + "github.com/rancher/k3d/v5/version" +) + +const ApiVersion = "k3d.io/v1alpha4" + +// JSONSchema describes the schema used to validate config files +//go:embed schema.json +var JSONSchema string + +// DefaultConfigTpl for printing +const DefaultConfigTpl = `--- +apiVersion: k3d.io/v1alpha4 +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.K3sVersion), +) + +type VolumeWithNodeFilters struct { + Volume string `mapstructure:"volume" yaml:"volume,omitempty" json:"volume,omitempty"` + NodeFilters []string `mapstructure:"nodeFilters" yaml:"nodeFilters,omitempty" json:"nodeFilters,omitempty"` +} + +type PortWithNodeFilters struct { + Port string `mapstructure:"port" yaml:"port,omitempty" json:"port,omitempty"` + NodeFilters []string `mapstructure:"nodeFilters" yaml:"nodeFilters,omitempty" json:"nodeFilters,omitempty"` +} + +type LabelWithNodeFilters struct { + Label string `mapstructure:"label" yaml:"label,omitempty" json:"label,omitempty"` + NodeFilters []string `mapstructure:"nodeFilters" yaml:"nodeFilters,omitempty" json:"nodeFilters,omitempty"` +} + +type EnvVarWithNodeFilters struct { + EnvVar string `mapstructure:"envVar" yaml:"envVar,omitempty" json:"envVar,omitempty"` + NodeFilters []string `mapstructure:"nodeFilters" yaml:"nodeFilters,omitempty" json:"nodeFilters,omitempty"` +} + +type K3sArgWithNodeFilters struct { + Arg string `mapstructure:"arg" yaml:"arg,omitempty" json:"arg,omitempty"` + NodeFilters []string `mapstructure:"nodeFilters" yaml:"nodeFilters,omitempty" json:"nodeFilters,omitempty"` +} + +type SimpleConfigRegistryCreateConfig struct { + Name string `mapstructure:"name" yaml:"name,omitempty" json:"name,omitempty"` + Host string `mapstructure:"host" yaml:"host,omitempty" json:"host,omitempty"` + HostPort string `mapstructure:"hostPort" yaml:"hostPort,omitempty" json:"hostPort,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" json:"k3d"` + K3sOptions SimpleConfigOptionsK3s `mapstructure:"k3s" yaml:"k3s" json:"k3s"` + KubeconfigOptions SimpleConfigOptionsKubeconfig `mapstructure:"kubeconfig" yaml:"kubeconfig" json:"kubeconfig"` + Runtime SimpleConfigOptionsRuntime `mapstructure:"runtime" yaml:"runtime" json:"runtime"` +} + +type SimpleConfigOptionsRuntime struct { + GPURequest string `mapstructure:"gpuRequest" yaml:"gpuRequest,omitempty" json:"gpuRequest,omitempty"` + ServersMemory string `mapstructure:"serversMemory" yaml:"serversMemory,omitempty" json:"serversMemory,omitempty"` + AgentsMemory string `mapstructure:"agentsMemory" yaml:"agentsMemory,omitempty" json:"agentsMemory,omitempty"` + HostPidMode bool `mapstructure:"hostPidMode" yaml:"hostPidMode,omitempty" json:"hostPidMode,omitempty"` + Labels []LabelWithNodeFilters `mapstructure:"labels" yaml:"labels,omitempty" json:"labels,omitempty"` +} + +type SimpleConfigOptionsK3d struct { + Wait bool `mapstructure:"wait" yaml:"wait" json:"wait"` + Timeout time.Duration `mapstructure:"timeout" yaml:"timeout,omitempty" json:"timeout,omitempty"` + DisableLoadbalancer bool `mapstructure:"disableLoadbalancer" yaml:"disableLoadbalancer" json:"disableLoadbalancer"` + DisableImageVolume bool `mapstructure:"disableImageVolume" yaml:"disableImageVolume" json:"disableImageVolume"` + NoRollback bool `mapstructure:"disableRollback" yaml:"disableRollback" json:"disableRollback"` + NodeHookActions []k3d.NodeHookAction `mapstructure:"nodeHookActions" yaml:"nodeHookActions,omitempty" json:"nodeHookActions,omitempty"` + Loadbalancer SimpleConfigOptionsK3dLoadbalancer `mapstructure:"loadbalancer" yaml:"loadbalancer,omitempty" json:"loadbalancer,omitempty"` +} + +type SimpleConfigOptionsK3dLoadbalancer struct { + ConfigOverrides []string `mapstructure:"configOverrides" yaml:"configOverrides,omitempty" json:"configOverrides,omitempty"` +} + +type SimpleConfigOptionsK3s struct { + ExtraArgs []K3sArgWithNodeFilters `mapstructure:"extraArgs" yaml:"extraArgs,omitempty" json:"extraArgs,omitempty"` + NodeLabels []LabelWithNodeFilters `mapstructure:"nodeLabels" yaml:"nodeLabels,omitempty" json:"nodeLabels,omitempty"` +} + +type SimpleConfigRegistries struct { + Use []string `mapstructure:"use" yaml:"use,omitempty" json:"use,omitempty"` + Create *SimpleConfigRegistryCreateConfig `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) +} + +// SimpleConfig describes the toplevel k3d configuration file. +type SimpleConfig struct { + config.TypeMeta `mapstructure:",squash" yaml:",inline"` + Name string `mapstructure:"name" yaml:"name,omitempty" json:"name,omitempty"` + Servers int `mapstructure:"servers" yaml:"servers,omitempty" json:"servers,omitempty"` //nolint:lll // default 1 + Agents int `mapstructure:"agents" yaml:"agents,omitempty" json:"agents,omitempty"` //nolint:lll // default 0 + ExposeAPI SimpleExposureOpts `mapstructure:"kubeAPI" yaml:"kubeAPI,omitempty" json:"kubeAPI,omitempty"` + Image string `mapstructure:"image" yaml:"image,omitempty" json:"image,omitempty"` + Network string `mapstructure:"network" yaml:"network,omitempty" json:"network,omitempty"` + Subnet string `mapstructure:"subnet" yaml:"subnet,omitempty" json:"subnet,omitempty"` + ClusterToken string `mapstructure:"token" yaml:"clusterToken,omitempty" json:"clusterToken,omitempty"` // default: auto-generated + Volumes []VolumeWithNodeFilters `mapstructure:"volumes" yaml:"volumes,omitempty" json:"volumes,omitempty"` + Ports []PortWithNodeFilters `mapstructure:"ports" yaml:"ports,omitempty" json:"ports,omitempty"` + Options SimpleConfigOptions `mapstructure:"options" yaml:"options,omitempty" json:"options,omitempty"` + Env []EnvVarWithNodeFilters `mapstructure:"env" yaml:"env,omitempty" json:"env,omitempty"` + Registries SimpleConfigRegistries `mapstructure:"registries" yaml:"registries,omitempty" json:"registries,omitempty"` + HostAliases []k3d.HostAlias `mapstructure:"hostAliases" yaml:"hostAliases,omitempty" json:"hostAliases,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) + } + +} diff --git a/pkg/config/validate.go b/pkg/config/validate.go index 94a7c8523..1eb03b1ec 100644 --- a/pkg/config/validate.go +++ b/pkg/config/validate.go @@ -27,7 +27,7 @@ import ( "time" k3dc "github.com/rancher/k3d/v5/pkg/client" - conf "github.com/rancher/k3d/v5/pkg/config/v1alpha3" + conf "github.com/rancher/k3d/v5/pkg/config/v1alpha4" "github.com/rancher/k3d/v5/pkg/runtimes" runtimeutil "github.com/rancher/k3d/v5/pkg/runtimes/util" k3d "github.com/rancher/k3d/v5/pkg/types" diff --git a/pkg/config/validate_test.go b/pkg/config/validate_test.go index 026acd7fe..32d5317e9 100644 --- a/pkg/config/validate_test.go +++ b/pkg/config/validate_test.go @@ -26,7 +26,7 @@ import ( "context" "testing" - conf "github.com/rancher/k3d/v5/pkg/config/v1alpha3" + conf "github.com/rancher/k3d/v5/pkg/config/v1alpha4" "github.com/rancher/k3d/v5/pkg/runtimes" "github.com/spf13/viper" ) diff --git a/tests/assets/config_env.yaml b/tests/assets/config_env.yaml index ad42b8e6b..f62454898 100644 --- a/tests/assets/config_env.yaml +++ b/tests/assets/config_env.yaml @@ -1,4 +1,4 @@ -apiVersion: k3d.io/v1alpha3 +apiVersion: k3d.io/v1alpha4 kind: Simple name: testenvexpand servers: ${K3D_TEST_SERVERS} diff --git a/tests/assets/config_test_simple.yaml b/tests/assets/config_test_simple.yaml index ef235b043..120319d90 100755 --- a/tests/assets/config_test_simple.yaml +++ b/tests/assets/config_test_simple.yaml @@ -1,4 +1,4 @@ -apiVersion: k3d.io/v1alpha3 +apiVersion: k3d.io/v1alpha4 kind: Simple name: test servers: 3 diff --git a/tests/test_config_file_migration.sh b/tests/test_config_file_migration.sh index b3be395ba..45ef81574 100755 --- a/tests/test_config_file_migration.sh +++ b/tests/test_config_file_migration.sh @@ -27,6 +27,7 @@ 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_migration_v1alpha2.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_migration_v1alpha3.yaml" +# TODO: migrate to v1alpha4 diff "$tempdir/actual.yaml" "$tempdir/expected.yaml" || failed "config migration failed" && passed "config migration succeeded"