-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Feature gate CLI flag and visibility changes (#4368)
* Expose feature gate registry type and its methods Signed-off-by: Anthony J Mirabella <a9@aneurysm9.com> * Add CLI flags for feature gates Signed-off-by: Anthony J Mirabella <a9@aneurysm9.com> * Add accessor for global feature gate registry Signed-off-by: Anthony J Mirabella <a9@aneurysm9.com> * add canonical import comment Signed-off-by: Anthony J Mirabella <a9@aneurysm9.com> * Revert "Add accessor for global feature gate registry" This reverts commit 23c957c. * Revert "Expose feature gate registry type and its methods" This reverts commit df64ad2. Signed-off-by: Anthony J Mirabella <a9@aneurysm9.com> * Add CHANGELOG entry, update docblock for Flags() Signed-off-by: Anthony J Mirabella <a9@aneurysm9.com>
- Loading branch information
Showing
5 changed files
with
197 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package featuregate // import "go.opentelemetry.io/collector/service/featuregate" | ||
|
||
import ( | ||
"flag" | ||
"sort" | ||
"strings" | ||
) | ||
|
||
const gatesListCfg = "feature-gates" | ||
|
||
var gatesList = FlagValue{} | ||
|
||
// Flags adds CLI flags for managing feature gates to the provided FlagSet | ||
// Feature gates can be configured with `--feature-gates=foo,-bar`. This would | ||
// enable the `foo` feature gate and disable the `bar` feature gate. | ||
func Flags(flags *flag.FlagSet) { | ||
flags.Var( | ||
gatesList, | ||
gatesListCfg, | ||
"Comma-delimited list of feature gate identifiers. Prefix with '-' to disable the feature. '+' or no prefix will enable the feature.") | ||
} | ||
|
||
// GetFlags returns the FlagValue used with Flags() | ||
func GetFlags() FlagValue { | ||
return gatesList | ||
} | ||
|
||
var _ flag.Value = (*FlagValue)(nil) | ||
|
||
// FlagValue implements the flag.Value interface and provides a mechanism for applying feature | ||
// gate statuses to a Registry | ||
type FlagValue map[string]bool | ||
|
||
// String returns a string representing the FlagValue | ||
func (f FlagValue) String() string { | ||
var t []string | ||
for k, v := range f { | ||
if v { | ||
t = append(t, k) | ||
} else { | ||
t = append(t, "-"+k) | ||
} | ||
} | ||
|
||
// Sort the list of identifiers for consistent results | ||
sort.Strings(t) | ||
return strings.Join(t, ",") | ||
} | ||
|
||
// Set applies the FlagValue encoded in the input string | ||
func (f FlagValue) Set(s string) error { | ||
return f.SetSlice(strings.Split(s, ",")) | ||
} | ||
|
||
// SetSlice applies the feature gate statuses in the input slice to the FlagValue | ||
func (f FlagValue) SetSlice(s []string) error { | ||
for _, v := range s { | ||
var id string | ||
var val bool | ||
switch v[0] { | ||
case '-': | ||
id = v[1:] | ||
val = false | ||
case '+': | ||
id = v[1:] | ||
val = true | ||
default: | ||
id = v | ||
val = true | ||
} | ||
|
||
if _, exists := f[id]; exists { | ||
// If the status has already been set, ignore it | ||
// This allows CLI flags, which are processed first | ||
// to take precedence over config settings | ||
continue | ||
} | ||
f[id] = val | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package featuregate | ||
|
||
import ( | ||
"flag" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestFlags(t *testing.T) { | ||
fs := flag.NewFlagSet("test", flag.ContinueOnError) | ||
Flags(fs) | ||
assert.Equal(t, gatesList, fs.Lookup(gatesListCfg).Value) | ||
} | ||
|
||
func TestGetFlags(t *testing.T) { | ||
assert.Equal(t, gatesList, GetFlags()) | ||
} | ||
|
||
func TestFlagValue_basic(t *testing.T) { | ||
for _, tc := range []struct { | ||
name string | ||
expected string | ||
input FlagValue | ||
}{ | ||
{ | ||
name: "single item", | ||
input: FlagValue{"foo": true}, | ||
expected: "foo", | ||
}, | ||
{ | ||
name: "single disabled item", | ||
input: FlagValue{"foo": false}, | ||
expected: "-foo", | ||
}, | ||
{ | ||
name: "multiple items", | ||
input: FlagValue{"foo": true, "bar": false}, | ||
expected: "-bar,foo", | ||
}, | ||
} { | ||
t.Run(tc.name, func(t *testing.T) { | ||
assert.Equal(t, tc.expected, tc.input.String()) | ||
v := FlagValue{} | ||
assert.NoError(t, v.Set(tc.expected)) | ||
assert.Equal(t, tc.input, v) | ||
}) | ||
} | ||
} | ||
|
||
func TestFlagValue_SetSlice(t *testing.T) { | ||
for _, tc := range []struct { | ||
name string | ||
input []string | ||
expected FlagValue | ||
}{ | ||
{ | ||
name: "single item", | ||
input: []string{"foo"}, | ||
expected: FlagValue{"foo": true}, | ||
}, | ||
{ | ||
name: "multiple items", | ||
input: []string{"foo", "-bar", "+baz"}, | ||
expected: FlagValue{"foo": true, "bar": false, "baz": true}, | ||
}, | ||
{ | ||
name: "repeated items", | ||
input: []string{"foo", "-bar", "-foo"}, | ||
expected: FlagValue{"foo": true, "bar": false}, | ||
}, | ||
} { | ||
t.Run(tc.name, func(t *testing.T) { | ||
v := FlagValue{} | ||
assert.NoError(t, v.SetSlice(tc.input)) | ||
assert.Equal(t, tc.expected, v) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters