From 27045cae76691085557bba5ce54f27100bb6322e Mon Sep 17 00:00:00 2001 From: therealmitchconnors Date: Wed, 4 Nov 2020 13:39:36 -0800 Subject: [PATCH 1/3] Add feature status to environment vars --- ctrlz/topics/assets/assets.gen.go | 4 ++ ctrlz/topics/assets/templates/env.html | 4 ++ ctrlz/topics/env.go | 23 ++++++--- env/var.go | 71 ++++++++++++++++++++++++-- env/var_test.go | 29 +++++++++++ 5 files changed, 120 insertions(+), 11 deletions(-) diff --git a/ctrlz/topics/assets/assets.gen.go b/ctrlz/topics/assets/assets.gen.go index 9fcdc67c..0b7d76eb 100644 --- a/ctrlz/topics/assets/assets.gen.go +++ b/ctrlz/topics/assets/assets.gen.go @@ -239,6 +239,8 @@ var _templatesEnvHtml = []byte(`{{ define "content" }} Name Value + Default + Status @@ -247,6 +249,8 @@ var _templatesEnvHtml = []byte(`{{ define "content" }} {{.Name}} {{.Value}} + {{.DefaultValue}} + {{.FeatureStatus}} {{ end }} diff --git a/ctrlz/topics/assets/templates/env.html b/ctrlz/topics/assets/templates/env.html index 4569d3dc..e96a4dbe 100644 --- a/ctrlz/topics/assets/templates/env.html +++ b/ctrlz/topics/assets/templates/env.html @@ -9,6 +9,8 @@ Name Value + Default + Status @@ -17,6 +19,8 @@ {{.Name}} {{.Value}} + {{.DefaultValue}} + {{.FeatureStatus}} {{ end }} diff --git a/ctrlz/topics/env.go b/ctrlz/topics/env.go index 8f73bdb8..874b7f99 100644 --- a/ctrlz/topics/env.go +++ b/ctrlz/topics/env.go @@ -1,4 +1,4 @@ -// Copyright 2018 Istio Authors +/// Copyright 2018 Istio Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package topics import ( "html/template" + "istio.io/pkg/env" "net/http" "os" "sort" @@ -44,18 +45,28 @@ func (envTopic) Prefix() string { type envVar struct { Name string `json:"name"` Value string `json:"value"` + DefaultValue string `json:"defaultvalue"` + FeatureStatus string `json:"featurestatus"` } func getVars() []envVar { - env := os.Environ() - sort.Strings(env) + regEnv := env.VarDescriptions() + otherEnv := os.Environ() + sort.Strings(otherEnv) result := []envVar{} - for _, v := range env { + visited := make(map[string]bool, len(regEnv)) + for _, v := range regEnv { + visited[v.Name] = true + result = append(result, envVar{Name: v.Name, Value: v.GetGeneric(), DefaultValue: v.DefaultValue, FeatureStatus: v.FeatureStatus.String()}) + } + for _, v := range otherEnv { var eq = strings.Index(v, "=") var name = v[:eq] - var value = v[eq+1:] - result = append(result, envVar{Name: name, Value: value}) + if _, ok := visited[name]; !ok { + var value = v[eq+1:] + result = append(result, envVar{Name: name, Value: value, DefaultValue: "UNKNOWN", FeatureStatus: "UNKNOWN"}) + } } return result diff --git a/env/var.go b/env/var.go index dd06caf9..ad1db56a 100644 --- a/env/var.go +++ b/env/var.go @@ -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" + } + 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. diff --git a/env/var_test.go b/env/var_test.go index 5fd993f9..5a4763f2 100644 --- a/env/var_test.go +++ b/env/var_test.go @@ -329,3 +329,32 @@ func TestDupes(t *testing.T) { t.Errorf("Expected 'XYZ', got '%s'", v.Description) } } + +func TestVar_GetGeneric(t *testing.T) { + type fields struct { + Var Var + Value string + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "first", + fields: fields{ + Var: RegisterStringVar("test", "defaultval", "description").Var, + Value: "non-default", + }, + want: "non-default", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + os.Setenv(tt.fields.Var.Name, tt.fields.Value) + if got := tt.fields.Var.GetGeneric(); got != tt.want { + t.Errorf("GetGeneric() = %v, want %v", got, tt.want) + } + }) + } +} \ No newline at end of file From 96c43263baf6e786af8160593de00f0c73762549 Mon Sep 17 00:00:00 2001 From: therealmitchconnors Date: Thu, 5 Nov 2020 09:46:04 -0800 Subject: [PATCH 2/3] fmt --- ctrlz/topics/env.go | 8 ++++---- env/var_test.go | 6 +++--- ledger/ledger_test.go | 3 +-- ledger/trie_cache.go | 3 +-- viperconfig/viperconfig.go | 3 +-- 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/ctrlz/topics/env.go b/ctrlz/topics/env.go index 874b7f99..72161080 100644 --- a/ctrlz/topics/env.go +++ b/ctrlz/topics/env.go @@ -16,7 +16,6 @@ package topics import ( "html/template" - "istio.io/pkg/env" "net/http" "os" "sort" @@ -24,6 +23,7 @@ import ( "istio.io/pkg/ctrlz/fw" "istio.io/pkg/ctrlz/topics/assets" + "istio.io/pkg/env" ) type envTopic struct { @@ -43,9 +43,9 @@ func (envTopic) Prefix() string { } type envVar struct { - Name string `json:"name"` - Value string `json:"value"` - DefaultValue string `json:"defaultvalue"` + Name string `json:"name"` + Value string `json:"value"` + DefaultValue string `json:"defaultvalue"` FeatureStatus string `json:"featurestatus"` } diff --git a/env/var_test.go b/env/var_test.go index 5a4763f2..a80e52c8 100644 --- a/env/var_test.go +++ b/env/var_test.go @@ -332,8 +332,8 @@ func TestDupes(t *testing.T) { func TestVar_GetGeneric(t *testing.T) { type fields struct { - Var Var - Value string + Var Var + Value string } tests := []struct { name string @@ -349,7 +349,7 @@ func TestVar_GetGeneric(t *testing.T) { want: "non-default", }, } - for _, tt := range tests { + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { os.Setenv(tt.fields.Var.Name, tt.fields.Value) if got := tt.fields.Var.GetGeneric(); got != tt.want { diff --git a/ledger/ledger_test.go b/ledger/ledger_test.go index ec8c0281..cf3c71c3 100644 --- a/ledger/ledger_test.go +++ b/ledger/ledger_test.go @@ -22,10 +22,9 @@ import ( "testing" "time" - "golang.org/x/sync/errgroup" - "github.com/google/uuid" "github.com/spaolacci/murmur3" + "golang.org/x/sync/errgroup" "gotest.tools/assert" ) diff --git a/ledger/trie_cache.go b/ledger/trie_cache.go index f1683533..0a507644 100644 --- a/ledger/trie_cache.go +++ b/ledger/trie_cache.go @@ -15,11 +15,10 @@ package ledger import ( + "sync" "time" "istio.io/pkg/cache" - - "sync" ) type cacheDB struct { diff --git a/viperconfig/viperconfig.go b/viperconfig/viperconfig.go index 380bd51e..0ff407d0 100644 --- a/viperconfig/viperconfig.go +++ b/viperconfig/viperconfig.go @@ -18,10 +18,9 @@ import ( "fmt" "os" - "github.com/spf13/viper" - "github.com/spf13/cobra" "github.com/spf13/pflag" + "github.com/spf13/viper" ) // AddConfigFlag appends a persistent flag for retrieving Viper config, as well as an initializer From df1880d25713d29f55d5c1e6fbe99fe37922ee28 Mon Sep 17 00:00:00 2001 From: therealmitchconnors Date: Thu, 5 Nov 2020 09:50:13 -0800 Subject: [PATCH 3/3] newline --- env/var_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/env/var_test.go b/env/var_test.go index a80e52c8..68d3b680 100644 --- a/env/var_test.go +++ b/env/var_test.go @@ -357,4 +357,4 @@ func TestVar_GetGeneric(t *testing.T) { } }) } -} \ No newline at end of file +}