Skip to content

Commit bf8a951

Browse files
authored
Collect Deployment Flag Options (#1578)
Problem: We want to collect deployment flag options so we can understand what a typical installation is using. Solution: Collect the deployment flag options.
1 parent be029fa commit bf8a951

File tree

7 files changed

+186
-3
lines changed

7 files changed

+186
-3
lines changed

cmd/gateway/commands.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"time"
88

99
"github.com/spf13/cobra"
10+
"github.com/spf13/pflag"
1011
"go.uber.org/zap"
1112
"k8s.io/apimachinery/pkg/types"
1213
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
@@ -178,6 +179,8 @@ func createStaticModeCommand() *cobra.Command {
178179
}
179180
}
180181

182+
flagKeys, flagValues := parseFlags(cmd.Flags())
183+
181184
conf := config.Config{
182185
GatewayCtlrName: gatewayCtlrName.value,
183186
ConfigName: configName.String(),
@@ -215,6 +218,10 @@ func createStaticModeCommand() *cobra.Command {
215218
Version: version,
216219
ExperimentalFeatures: gwExperimentalFeatures,
217220
ImageSource: imageSource,
221+
Flags: config.Flags{
222+
Names: flagKeys,
223+
Values: flagValues,
224+
},
218225
}
219226

220227
if err := static.StartManager(conf); err != nil {
@@ -450,3 +457,26 @@ func createSleepCommand() *cobra.Command {
450457

451458
return cmd
452459
}
460+
461+
func parseFlags(flags *pflag.FlagSet) ([]string, []string) {
462+
var flagKeys, flagValues []string
463+
464+
flags.VisitAll(
465+
func(flag *pflag.Flag) {
466+
flagKeys = append(flagKeys, flag.Name)
467+
468+
if flag.Value.Type() == "bool" {
469+
flagValues = append(flagValues, flag.Value.String())
470+
} else {
471+
val := "user-defined"
472+
if flag.Value.String() == flag.DefValue {
473+
val = "default"
474+
}
475+
476+
flagValues = append(flagValues, val)
477+
}
478+
},
479+
)
480+
481+
return flagKeys, flagValues
482+
}

cmd/gateway/commands_test.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66

77
. "github.com/onsi/gomega"
88
"github.com/spf13/cobra"
9+
"github.com/spf13/pflag"
10+
"k8s.io/apimachinery/pkg/types"
911
)
1012

1113
type flagTestCase struct {
@@ -454,3 +456,128 @@ func TestSleepCmdFlagValidation(t *testing.T) {
454456
})
455457
}
456458
}
459+
460+
func TestParseFlags(t *testing.T) {
461+
g := NewWithT(t)
462+
463+
flagSet := pflag.NewFlagSet("flagSet", 0)
464+
// set SortFlags to false for testing purposes so when parseFlags loops over the flagSet it
465+
// goes off of primordial order.
466+
flagSet.SortFlags = false
467+
468+
var boolFlagTrue bool
469+
flagSet.BoolVar(
470+
&boolFlagTrue,
471+
"boolFlagTrue",
472+
true,
473+
"boolean true test flag",
474+
)
475+
476+
var boolFlagFalse bool
477+
flagSet.BoolVar(
478+
&boolFlagFalse,
479+
"boolFlagFalse",
480+
false,
481+
"boolean false test flag",
482+
)
483+
484+
customIntFlagDefault := intValidatingValue{
485+
validator: validatePort,
486+
value: 8080,
487+
}
488+
flagSet.Var(
489+
&customIntFlagDefault,
490+
"customIntFlagDefault",
491+
"default custom int test flag",
492+
)
493+
494+
customIntFlagUserDefined := intValidatingValue{
495+
validator: validatePort,
496+
value: 8080,
497+
}
498+
flagSet.Var(
499+
&customIntFlagUserDefined,
500+
"customIntFlagUserDefined",
501+
"user defined custom int test flag",
502+
)
503+
err := flagSet.Set("customIntFlagUserDefined", "8081")
504+
g.Expect(err).To(Not(HaveOccurred()))
505+
506+
customStringFlagDefault := stringValidatingValue{
507+
validator: validateResourceName,
508+
value: "default-custom-string-test-flag",
509+
}
510+
flagSet.Var(
511+
&customStringFlagDefault,
512+
"customStringFlagDefault",
513+
"default custom string test flag",
514+
)
515+
516+
customStringFlagUserDefined := stringValidatingValue{
517+
validator: validateResourceName,
518+
value: "user-defined-custom-string-test-flag",
519+
}
520+
flagSet.Var(
521+
&customStringFlagUserDefined,
522+
"customStringFlagUserDefined",
523+
"user defined custom string test flag",
524+
)
525+
err = flagSet.Set("customStringFlagUserDefined", "changed-test-flag-value")
526+
g.Expect(err).To(Not(HaveOccurred()))
527+
528+
customStringFlagNoDefaultValueUnset := namespacedNameValue{
529+
value: types.NamespacedName{},
530+
}
531+
flagSet.Var(
532+
&customStringFlagNoDefaultValueUnset,
533+
"customStringFlagNoDefaultValueUnset",
534+
"no default value custom string test flag",
535+
)
536+
537+
customStringFlagNoDefaultValueUserDefined := namespacedNameValue{
538+
value: types.NamespacedName{},
539+
}
540+
flagSet.Var(
541+
&customStringFlagNoDefaultValueUserDefined,
542+
"customStringFlagNoDefaultValueUserDefined",
543+
"no default value but with user defined namespacedName test flag",
544+
)
545+
userDefinedNamespacedName := types.NamespacedName{
546+
Namespace: "changed-namespace",
547+
Name: "changed-name",
548+
}
549+
err = flagSet.Set("customStringFlagNoDefaultValueUserDefined", userDefinedNamespacedName.String())
550+
g.Expect(err).To(Not(HaveOccurred()))
551+
552+
expectedKeys := []string{
553+
"boolFlagTrue",
554+
"boolFlagFalse",
555+
556+
"customIntFlagDefault",
557+
"customIntFlagUserDefined",
558+
559+
"customStringFlagDefault",
560+
"customStringFlagUserDefined",
561+
562+
"customStringFlagNoDefaultValueUnset",
563+
"customStringFlagNoDefaultValueUserDefined",
564+
}
565+
expectedValues := []string{
566+
"true",
567+
"false",
568+
569+
"default",
570+
"user-defined",
571+
572+
"default",
573+
"user-defined",
574+
575+
"default",
576+
"user-defined",
577+
}
578+
579+
flagKeys, flagValues := parseFlags(flagSet)
580+
581+
g.Expect(flagKeys).Should(Equal(expectedKeys))
582+
g.Expect(flagValues).Should(Equal(expectedValues))
583+
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ require (
1717
github.com/prometheus/client_golang v1.18.0
1818
github.com/prometheus/common v0.48.0
1919
github.com/spf13/cobra v1.8.0
20+
github.com/spf13/pflag v1.0.5
2021
github.com/tsenart/vegeta/v12 v12.11.1
2122
go.uber.org/zap v1.27.0
2223
k8s.io/api v0.29.2
@@ -71,7 +72,6 @@ require (
7172
github.com/prometheus/client_model v0.5.0 // indirect
7273
github.com/prometheus/procfs v0.12.0 // indirect
7374
github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417 // indirect
74-
github.com/spf13/pflag v1.0.5 // indirect
7575
github.com/stretchr/testify v1.8.4 // indirect
7676
go.uber.org/multierr v1.11.0 // indirect
7777
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect

internal/mode/static/config/config.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ type Config struct {
1515
ImageSource string
1616
// AtomicLevel is an atomically changeable, dynamic logging level.
1717
AtomicLevel zap.AtomicLevel
18+
// Flags contains the NGF command-line flag names and values.
19+
Flags Flags
1820
// GatewayNsName is the namespaced name of a Gateway resource that the Gateway will use.
1921
// The Gateway will ignore all other Gateway resources.
2022
GatewayNsName *types.NamespacedName
@@ -105,3 +107,13 @@ type UsageReportConfig struct {
105107
// InsecureSkipVerify controls whether the client verifies the server cert.
106108
InsecureSkipVerify bool
107109
}
110+
111+
// Flags contains the NGF command-line flag names and values.
112+
// Flag Names and Values are paired based off of index in slice.
113+
type Flags struct {
114+
// Names contains the name of the flag.
115+
Names []string
116+
// Values contains the value of the flag in string form.
117+
// Each Value will be either true or false for boolean flags and default or user-defined for non-boolean flags.
118+
Values []string
119+
}

internal/mode/static/manager.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ func StartManager(cfg config.Config) error {
253253
Name: cfg.GatewayPodConfig.Name,
254254
},
255255
ImageSource: cfg.ImageSource,
256+
Flags: cfg.Flags,
256257
})
257258
if err = mgr.Add(createTelemetryJob(cfg, dataCollector, nginxChecker.getReadyCh())); err != nil {
258259
return fmt.Errorf("cannot register telemetry job: %w", err)

internal/mode/static/telemetry/collector.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"k8s.io/apimachinery/pkg/types"
1313
"sigs.k8s.io/controller-runtime/pkg/client"
1414

15+
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/config"
1516
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/state/dataplane"
1617
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/state/graph"
1718
)
@@ -55,6 +56,7 @@ type Data struct {
5556
Arch string
5657
DeploymentID string
5758
ImageSource string
59+
Flags config.Flags
5860
NGFResourceCounts NGFResourceCounts
5961
NodeCount int
6062
NGFReplicaCount int
@@ -74,6 +76,8 @@ type DataCollectorConfig struct {
7476
PodNSName types.NamespacedName
7577
// ImageSource is the source of the NGF image.
7678
ImageSource string
79+
// Flags contains the command-line NGF flag keys and values.
80+
Flags config.Flags
7781
}
7882

7983
// DataCollectorImpl is am implementation of DataCollector.
@@ -134,6 +138,7 @@ func (c DataCollectorImpl) Collect(ctx context.Context) (Data, error) {
134138
ImageSource: c.cfg.ImageSource,
135139
Arch: runtime.GOARCH,
136140
DeploymentID: deploymentID,
141+
Flags: c.cfg.Flags,
137142
}
138143

139144
return data, nil

internal/mode/static/telemetry/collector_test.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
1818

1919
"github.com/nginxinc/nginx-gateway-fabric/internal/framework/events/eventsfakes"
20+
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/config"
2021
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/state/dataplane"
2122
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/state/graph"
2223
"github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/state/resolver"
@@ -77,8 +78,8 @@ var _ = Describe("Collector", Ordered, func() {
7778
ngfPod *v1.Pod
7879
ngfReplicaSet *appsv1.ReplicaSet
7980
kubeNamespace *v1.Namespace
80-
81-
baseGetCalls getCallsFunc
81+
baseGetCalls getCallsFunc
82+
flags config.Flags
8283
)
8384

8485
BeforeAll(func() {
@@ -125,6 +126,11 @@ var _ = Describe("Collector", Ordered, func() {
125126
UID: "test-uid",
126127
},
127128
}
129+
130+
flags = config.Flags{
131+
Names: []string{"boolFlag", "intFlag", "stringFlag"},
132+
Values: []string{"false", "default", "user-defined"},
133+
}
128134
})
129135

130136
BeforeEach(func() {
@@ -137,6 +143,7 @@ var _ = Describe("Collector", Ordered, func() {
137143
ImageSource: "local",
138144
Arch: runtime.GOARCH,
139145
DeploymentID: string(ngfReplicaSet.ObjectMeta.OwnerReferences[0].UID),
146+
Flags: flags,
140147
}
141148

142149
k8sClientReader = &eventsfakes.FakeReader{}
@@ -153,6 +160,7 @@ var _ = Describe("Collector", Ordered, func() {
153160
Version: version,
154161
PodNSName: podNSName,
155162
ImageSource: "local",
163+
Flags: flags,
156164
})
157165

158166
baseGetCalls = createGetCallsFunc(ngfPod, ngfReplicaSet, kubeNamespace)

0 commit comments

Comments
 (0)