mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-07-17 00:43:36 +00:00
config: enhance Feature structure
Fixes #1226 Add more fields to better describe an experimental feature. Signed-off-by: Wei Zhang <zhangwei555@huawei.com>
This commit is contained in:
parent
111774c859
commit
da80c70c0c
@ -27,7 +27,7 @@ import (
|
|||||||
//
|
//
|
||||||
// XXX: Increment for every change to the output format
|
// XXX: Increment for every change to the output format
|
||||||
// (meaning any change to the EnvInfo type).
|
// (meaning any change to the EnvInfo type).
|
||||||
const formatVersion = "1.0.20"
|
const formatVersion = "1.0.21"
|
||||||
|
|
||||||
// MetaInfo stores information on the format of the output itself
|
// MetaInfo stores information on the format of the output itself
|
||||||
type MetaInfo struct {
|
type MetaInfo struct {
|
||||||
|
@ -858,11 +858,11 @@ func LoadConfiguration(configPath string, ignoreLogging, builtIn bool) (resolved
|
|||||||
|
|
||||||
config.DisableNewNetNs = tomlConf.Runtime.DisableNewNetNs
|
config.DisableNewNetNs = tomlConf.Runtime.DisableNewNetNs
|
||||||
for _, f := range tomlConf.Runtime.Experimental {
|
for _, f := range tomlConf.Runtime.Experimental {
|
||||||
feature := exp.Feature(f)
|
feature := exp.Get(f)
|
||||||
if !exp.Supported(feature) {
|
if feature == nil {
|
||||||
return "", config, fmt.Errorf("Unsupported experimental feature %q", f)
|
return "", config, fmt.Errorf("Unsupported experimental feature %q", f)
|
||||||
}
|
}
|
||||||
config.Experimental = append(config.Experimental, feature)
|
config.Experimental = append(config.Experimental, *feature)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := checkConfig(config); err != nil {
|
if err := checkConfig(config); err != nil {
|
||||||
|
@ -8,7 +8,7 @@ They are **always disabled** by default in Kata components releases,
|
|||||||
and can only be enabled by users when they want to have a try.
|
and can only be enabled by users when they want to have a try.
|
||||||
|
|
||||||
We suggest you **NEVER** enable "experimental" features in production environment,
|
We suggest you **NEVER** enable "experimental" features in production environment,
|
||||||
unless you know what breakage they can bring and have confidence to handle it by youself.
|
unless you know what breakage they can bring and have confidence to handle it by yourself.
|
||||||
|
|
||||||
Criteria of an experimental feature are:
|
Criteria of an experimental feature are:
|
||||||
|
|
||||||
@ -28,7 +28,13 @@ so it can improve in next few releases to be stable enough.
|
|||||||
Some features could be big, it adds/changes lots of codes so may need more tests.
|
Some features could be big, it adds/changes lots of codes so may need more tests.
|
||||||
Our CI can help guarantee correctness of the feature, but it may not cover all scenarios.
|
Our CI can help guarantee correctness of the feature, but it may not cover all scenarios.
|
||||||
Before we're confident that the feature is ready for production use,
|
Before we're confident that the feature is ready for production use,
|
||||||
the feature can be marked as "experimental" first, and users can test it manually in their own environment if intested in it.
|
the feature can be marked as "experimental" first, and users can test it manually in their own environment if interested in it.
|
||||||
|
|
||||||
|
We make no guarantees about experimental features, they can be removed entirely at any point,
|
||||||
|
or become non-experimental at some release, so relative configuration options can change radically.
|
||||||
|
|
||||||
|
An experimental feature **MUST** have a descriptive name containing only lower-case characters, numbers or '_',
|
||||||
|
e.g. new_hypervisor_2, the name **MUST** be unique and will never be re-used in future.
|
||||||
|
|
||||||
## 2. What's the difference between "WIP" and "experimental"?
|
## 2. What's the difference between "WIP" and "experimental"?
|
||||||
|
|
||||||
@ -42,7 +48,7 @@ In one word, "experimental" can be unstable currently but it **MUST** be complet
|
|||||||
|
|
||||||
That depends.
|
That depends.
|
||||||
|
|
||||||
For the feature who breaks backward compatibility, we usually land it as formal feature in a major version bump(x in x.y.z, e.g. 2.0.0).
|
For the feature that breaks backward compatibility, we usually land it as formal feature in a major version bump(x in x.y.z, e.g. 2.0.0).
|
||||||
But for a new feature who becomes stable and ready, we can release it formally in any minor version bump.
|
But for a new feature who becomes stable and ready, we can release it formally in any minor version bump.
|
||||||
|
|
||||||
Check Kata Container [versioning rules](https://github.com/kata-containers/documentation/blob/c556f1853f2e3df69d336de01ad4bb38e64ecc1b/Releases.md#versioning).
|
Check Kata Container [versioning rules](https://github.com/kata-containers/documentation/blob/c556f1853f2e3df69d336de01ad4bb38e64ecc1b/Releases.md#versioning).
|
||||||
|
@ -7,26 +7,57 @@ package experimental
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
nameRegStr = "^[a-z][a-z0-9_]*$"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Feature to be experimental
|
// Feature to be experimental
|
||||||
type Feature string
|
type Feature struct {
|
||||||
|
Name string
|
||||||
|
Description string
|
||||||
|
// the expected release version to move out from experimental
|
||||||
|
ExpRelease string
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
supportedFeatures = make(map[Feature]struct{})
|
supportedFeatures = make(map[string]Feature)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Register register a new experimental feature
|
// Register register a new experimental feature
|
||||||
func Register(feature Feature) error {
|
func Register(feature Feature) error {
|
||||||
if _, ok := supportedFeatures[feature]; ok {
|
if err := validateFeature(feature); err != nil {
|
||||||
return fmt.Errorf("Feature %q had been registered before", feature)
|
return err
|
||||||
}
|
}
|
||||||
supportedFeatures[feature] = struct{}{}
|
|
||||||
|
if _, ok := supportedFeatures[feature.Name]; ok {
|
||||||
|
return fmt.Errorf("Feature %q had been registered before", feature.Name)
|
||||||
|
}
|
||||||
|
supportedFeatures[feature.Name] = feature
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Supported check if the feature is supported
|
// Get returns Feature with requested name
|
||||||
func Supported(feature Feature) bool {
|
func Get(name string) *Feature {
|
||||||
_, ok := supportedFeatures[feature]
|
if f, ok := supportedFeatures[name]; ok {
|
||||||
return ok
|
return &f
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateFeature(feature Feature) error {
|
||||||
|
if len(feature.Name) == 0 ||
|
||||||
|
len(feature.Description) == 0 ||
|
||||||
|
len(feature.ExpRelease) == 0 {
|
||||||
|
return fmt.Errorf("experimental feature must have valid name, description and expected release")
|
||||||
|
}
|
||||||
|
|
||||||
|
reg := regexp.MustCompile(nameRegStr)
|
||||||
|
if !reg.MatchString(feature.Name) {
|
||||||
|
return fmt.Errorf("feature name must in the format %q", nameRegStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -12,15 +12,49 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestExperimental(t *testing.T) {
|
func TestExperimental(t *testing.T) {
|
||||||
f := Feature("mock")
|
f := Feature{
|
||||||
assert.False(t, Supported(f))
|
Name: "mock",
|
||||||
|
Description: "mock experimental feature for test",
|
||||||
|
ExpRelease: "2.0",
|
||||||
|
}
|
||||||
|
assert.Nil(t, Get(f.Name))
|
||||||
|
|
||||||
err := Register("mock")
|
err := Register(f)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
||||||
err = Register("mock")
|
err = Register(f)
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
assert.Equal(t, len(supportedFeatures), 1)
|
assert.Equal(t, len(supportedFeatures), 1)
|
||||||
|
|
||||||
assert.True(t, Supported(f))
|
assert.NotNil(t, Get(f.Name))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateFeature(t *testing.T) {
|
||||||
|
f := Feature{}
|
||||||
|
assert.NotNil(t, validateFeature(f))
|
||||||
|
|
||||||
|
for _, names := range []struct {
|
||||||
|
name string
|
||||||
|
valid bool
|
||||||
|
}{
|
||||||
|
{"mock_test_1", true},
|
||||||
|
{"m1234ock_test_1", true},
|
||||||
|
{"1_mock_test", false},
|
||||||
|
{"_mock_test_1", false},
|
||||||
|
{"Mock", false},
|
||||||
|
{"mock*&", false},
|
||||||
|
} {
|
||||||
|
f := Feature{
|
||||||
|
Name: names.name,
|
||||||
|
Description: "test",
|
||||||
|
ExpRelease: "2.0",
|
||||||
|
}
|
||||||
|
|
||||||
|
err := validateFeature(f)
|
||||||
|
if names.valid {
|
||||||
|
assert.Nil(t, err)
|
||||||
|
} else {
|
||||||
|
assert.NotNil(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ func (sandboxConfig *SandboxConfig) valid() bool {
|
|||||||
|
|
||||||
// validate experimental features
|
// validate experimental features
|
||||||
for _, f := range sandboxConfig.Experimental {
|
for _, f := range sandboxConfig.Experimental {
|
||||||
if !exp.Supported(f) {
|
if exp.Get(f.Name) == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1683,16 +1683,20 @@ func TestSandboxUpdateResources(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSandboxExperimentalFeature(t *testing.T) {
|
func TestSandboxExperimentalFeature(t *testing.T) {
|
||||||
testFeature := exp.Feature("mock")
|
testFeature := exp.Feature{
|
||||||
|
Name: "mock",
|
||||||
|
Description: "exp feature for test",
|
||||||
|
ExpRelease: "1.8.0",
|
||||||
|
}
|
||||||
sconfig := SandboxConfig{
|
sconfig := SandboxConfig{
|
||||||
ID: testSandboxID,
|
ID: testSandboxID,
|
||||||
Experimental: []exp.Feature{testFeature},
|
Experimental: []exp.Feature{testFeature},
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.False(t, exp.Supported(testFeature))
|
assert.Nil(t, exp.Get(testFeature.Name))
|
||||||
assert.False(t, sconfig.valid())
|
assert.False(t, sconfig.valid())
|
||||||
|
|
||||||
exp.Register(testFeature)
|
exp.Register(testFeature)
|
||||||
assert.True(t, exp.Supported(testFeature))
|
assert.NotNil(t, exp.Get(testFeature.Name))
|
||||||
assert.True(t, sconfig.valid())
|
assert.True(t, sconfig.valid())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user