-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: Add feature status to environment vars #266
base: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ | |
package env | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"sort" | ||
"strconv" | ||
|
@@ -42,6 +43,27 @@ const ( | |
DURATION | ||
) | ||
|
||
type FeatureStatus byte | ||
|
||
const ( | ||
Alpha FeatureStatus = iota | ||
Beta | ||
Stable | ||
Unknown | ||
) | ||
|
||
func (s FeatureStatus) String() string { | ||
switch s { | ||
case Alpha: | ||
return "Alpha" | ||
case Beta: | ||
return "Beta" | ||
case Stable: | ||
return "Stable" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does it mean for an env var to be stable? Don't we currently document that all env vars are alpha? Put another way, why would we promote an env var to stable vs moving it to an API/mesh config? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am all for the idea of migrating all stable environment variables to an API, but that does not represent the current state of the project. For instance, I believe we set the PILOT_TRACE_SAMPLING variable on every istio deployment, and it should probably be considered stable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PILOT_TRACE_SAMPLING will be deprecated in 1.9 by the tracing api. We shouldn't mark something "stable" just because its been around for a while, we should mark it stable if we know its the right long term API and its properly tested There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The overall idea here is to give users a way to visualize the maturity of the features they are leveraging. We've already got that for Annotations with Nate's PR, and this would provide visibility into env vars, which could be combined in a single istioctl command to show users what features they are using, and what support they can expect. Given the prominence of many env vars, I doubt we would feed comfortable telling our users that all of them have only alpha level support. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we track the same state we're now tracking for annotation to cover the transition intent deprecated, deprecatedBy etc. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. It might be helpful to track the removal of deprecated features too, so we can highlight that when checking upgrade readiness. It's also useful to note that users may not be setting these directly, but via operator or helm values. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we add experimental to here as well? |
||
} | ||
return "Unknown" | ||
} | ||
|
||
// Var describes a single environment variable | ||
type Var struct { | ||
// The name of the environment variable. | ||
|
@@ -61,6 +83,9 @@ type Var struct { | |
|
||
// The type of the variable's value | ||
Type VarType | ||
|
||
// The support level of the feature controlled by this env var | ||
FeatureStatus FeatureStatus | ||
} | ||
|
||
// StringVar represents a single string environment variable. | ||
|
@@ -109,39 +134,49 @@ func VarDescriptions() []Var { | |
|
||
// RegisterStringVar registers a new string environment variable. | ||
func RegisterStringVar(name string, defaultValue string, description string) StringVar { | ||
v := Var{Name: name, DefaultValue: defaultValue, Description: description, Type: STRING} | ||
v := Var{Name: name, DefaultValue: defaultValue, Description: description, Type: STRING, FeatureStatus: Unknown} | ||
RegisterVar(v) | ||
return StringVar{getVar(name)} | ||
} | ||
|
||
// RegisterBoolVar registers a new boolean environment variable. | ||
func RegisterBoolVar(name string, defaultValue bool, description string) BoolVar { | ||
v := Var{Name: name, DefaultValue: strconv.FormatBool(defaultValue), Description: description, Type: BOOL} | ||
v := Var{Name: name, DefaultValue: strconv.FormatBool(defaultValue), Description: description, Type: BOOL, FeatureStatus: Unknown} | ||
RegisterVar(v) | ||
return BoolVar{getVar(name)} | ||
} | ||
|
||
// RegisterIntVar registers a new integer environment variable. | ||
func RegisterIntVar(name string, defaultValue int, description string) IntVar { | ||
v := Var{Name: name, DefaultValue: strconv.FormatInt(int64(defaultValue), 10), Description: description, Type: INT} | ||
v := Var{Name: name, DefaultValue: strconv.FormatInt(int64(defaultValue), 10), Description: description, Type: INT, FeatureStatus: Unknown} | ||
RegisterVar(v) | ||
return IntVar{getVar(name)} | ||
} | ||
|
||
// RegisterFloatVar registers a new floating-point environment variable. | ||
func RegisterFloatVar(name string, defaultValue float64, description string) FloatVar { | ||
v := Var{Name: name, DefaultValue: strconv.FormatFloat(defaultValue, 'G', -1, 64), Description: description, Type: FLOAT} | ||
v := Var{Name: name, DefaultValue: strconv.FormatFloat(defaultValue, 'G', -1, 64), Description: description, Type: FLOAT, FeatureStatus: Unknown} | ||
RegisterVar(v) | ||
return FloatVar{v} | ||
} | ||
|
||
// RegisterDurationVar registers a new duration environment variable. | ||
func RegisterDurationVar(name string, defaultValue time.Duration, description string) DurationVar { | ||
v := Var{Name: name, DefaultValue: defaultValue.String(), Description: description, Type: DURATION} | ||
v := Var{Name: name, DefaultValue: defaultValue.String(), Description: description, Type: DURATION, FeatureStatus: Unknown} | ||
RegisterVar(v) | ||
return DurationVar{getVar(name)} | ||
} | ||
|
||
func SetVarStatus(v Var, f FeatureStatus) { | ||
if val, ok := allVars[v.Name]; ok { | ||
val.FeatureStatus = f | ||
allVars[v.Name] = val | ||
} else { | ||
v.FeatureStatus = f | ||
RegisterVar(v) | ||
} | ||
} | ||
|
||
// RegisterVar registers a generic environment variable. | ||
func RegisterVar(v Var) { | ||
mutex.Lock() | ||
|
@@ -169,6 +204,32 @@ func getVar(name string) Var { | |
return result | ||
} | ||
|
||
func (v Var) LookupGeneric() (string, bool) { | ||
switch v.Type { | ||
case STRING: | ||
return StringVar{Var: v}.Lookup() | ||
case INT: | ||
val, found := IntVar{Var: v}.Lookup() | ||
return strconv.Itoa(val), found | ||
case BOOL: | ||
val, found := BoolVar{Var: v}.Lookup() | ||
return strconv.FormatBool(val), found | ||
case FLOAT: | ||
val, found := FloatVar{Var: v}.Lookup() | ||
return strconv.FormatFloat(val, 'f', -1, 64), found | ||
case DURATION: | ||
val, found := DurationVar{Var: v}.Lookup() | ||
return val.String(), found | ||
default: | ||
return fmt.Sprintf("type %T is not recognized", v), false | ||
} | ||
} | ||
|
||
func (v Var) GetGeneric() string { | ||
val, _ := v.LookupGeneric() | ||
return val | ||
} | ||
|
||
// Get retrieves the value of the environment variable. | ||
// It returns the value, which will be the default if the variable is not present. | ||
// To distinguish between an empty value and an unset value, use Lookup. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In a world where we canonicalize these Unknown's should become forbidden. Can we add a 'Dev' status
I think there's also a class of 'industry std' environment variables that we depend on which would not belong to our canonicalization. (PATH, USER, ...) How would we handle those? Maybe add a "Platform" ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Platform env vars are not registered with the env package, and the ctrlz page lists their default values as UNKNOWN. I don't think we have any concept of 'Dev' status elsewhere in the project. Would 'experimental' make more sense?