diff --git a/clustermesh-apiserver/health.go b/clustermesh-apiserver/health.go index 75a3087ce3785..8c779e1e3aedd 100644 --- a/clustermesh-apiserver/health.go +++ b/clustermesh-apiserver/health.go @@ -26,6 +26,8 @@ func (HealthAPIServerConfig) Flags(flags *pflag.FlagSet) { var healthAPIServerCell = cell.Module( "health-api-server", + "ClusterMesh Health API Server", + cell.Config(HealthAPIServerConfig{}), cell.Invoke(registerHealthAPIServer), ) diff --git a/operator/cmd/lifecycle.go b/operator/cmd/lifecycle.go index 057f9e4059397..cbdbdc1f74f14 100644 --- a/operator/cmd/lifecycle.go +++ b/operator/cmd/lifecycle.go @@ -18,6 +18,8 @@ type LeaderLifecycle struct { func WithLeaderLifecycle(cells ...cell.Cell) cell.Cell { return cell.Module( "leader-lifecycle", + "Operator Leader Lifecycle", + cell.Provide( func() *LeaderLifecycle { return &LeaderLifecycle{} }, ), diff --git a/operator/cmd/root.go b/operator/cmd/root.go index 70f1e97672d0f..2cd4a287e5d01 100644 --- a/operator/cmd/root.go +++ b/operator/cmd/root.go @@ -91,6 +91,7 @@ var ( // Used also in tests. OperatorCell = cell.Module( "operator", + "Cilium Operator", cell.Invoke( registerOperatorHooks, diff --git a/pkg/gops/cell.go b/pkg/gops/cell.go index 8c59f76b89a96..3dfae3eb3b594 100644 --- a/pkg/gops/cell.go +++ b/pkg/gops/cell.go @@ -21,6 +21,8 @@ import ( func Cell(defaultPort uint16) cell.Cell { return cell.Module( "gops", + "Gops Agent", + cell.Config(GopsConfig{GopsPort: defaultPort}), cell.Invoke(registerGopsHooks), ) diff --git a/pkg/hive/cell/module.go b/pkg/hive/cell/module.go index dca460e44c16a..c07411d910876 100644 --- a/pkg/hive/cell/module.go +++ b/pkg/hive/cell/module.go @@ -4,30 +4,59 @@ package cell import ( + "fmt" + "regexp" + "github.com/sirupsen/logrus" "github.com/cilium/cilium/pkg/logging/logfields" ) -// Module creates a named set of cells. -// The name will be included in the object dump (hive.PrintObjects) and -// in the dot graph (hive.PrintDotGraph). -func Module(name string, cells ...Cell) Cell { - return &module{name, cells} +// Module creates a scoped set of cells with a given identifier. +// +// The id and title will be included in the object dump (hive.PrintObjects). +// The id must be lower-case, at most 30 characters and only contain [a-z0-9-_]. +// Title can contain [a-zA-Z0-9_- ] and must be shorter than 80 characters. +// +// Private constructors with a module (ProvidePrivate) are only accessible +// within this module and its sub-modules. +func Module(id, title string, cells ...Cell) Cell { + validateIdAndTitle(id, title) + return &module{id, title, cells} +} + +var ( + idRegex = regexp.MustCompile(`^[a-z][a-z0-9_\-]{1,30}$`) + titleRegex = regexp.MustCompile(`^[a-zA-Z0-9_\- ]{1,80}$`) +) + +func validateIdAndTitle(id, title string) { + if !idRegex.MatchString(id) { + panic(fmt.Sprintf("Invalid hive.Module id: %q, expected to id match %s", id, idRegex)) + } + if !titleRegex.MatchString(title) { + panic(fmt.Sprintf("Invalid hive.Module title: %q, expected to title match %s", title, titleRegex)) + } } -// module is a named set of cells. type module struct { - name string + // id is the module identity. It is shown in object output and is used to derive + // the scoped logger. + id string + + // title is a human-readable short title for the module. Shown in object output + // alongside the identifier. + title string + cells []Cell } func (m *module) logger(log logrus.FieldLogger) logrus.FieldLogger { - return log.WithField(logfields.LogSubsys, m.name) + return log.WithField(logfields.LogSubsys, m.id) } func (m *module) Apply(c container) error { - scope := c.Scope(m.name) + scope := c.Scope(m.id) if err := scope.Decorate(m.logger); err != nil { return err @@ -42,7 +71,7 @@ func (m *module) Apply(c container) error { } func (m *module) Info() Info { - n := NewInfoNode("Ⓜ️ " + m.name) + n := NewInfoNode("Ⓜ️ " + m.id + " (" + m.title + ")") for _, cell := range m.cells { n.Add(cell.Info()) n.AddBreak() diff --git a/pkg/hive/example/main.go b/pkg/hive/example/main.go index 837c168623f61..26b46b8daa11f 100644 --- a/pkg/hive/example/main.go +++ b/pkg/hive/example/main.go @@ -22,6 +22,8 @@ import ( // way around. var exampleCell = cell.Module( "example", + "Example", + cell.Config(defaultExampleConfig), cell.Provide(newExampleObject), cell.ProvidePrivate(newPrivateObject), diff --git a/pkg/hive/hive_test.go b/pkg/hive/hive_test.go index f1281ff44a7f1..cb48f92013866 100644 --- a/pkg/hive/hive_test.go +++ b/pkg/hive/hive_test.go @@ -30,6 +30,7 @@ func TestHiveGoodConfig(t *testing.T) { var cfg Config testCell := cell.Module( "test", + "Test Module", cell.Config(Config{}), cell.Invoke(func(c Config) { cfg = c @@ -68,6 +69,7 @@ func (BadConfig) Flags(flags *pflag.FlagSet) { func TestHiveBadConfig(t *testing.T) { testCell := cell.Module( "test", + "Test Module", cell.Config(BadConfig{}), cell.Invoke(func(c BadConfig) {}), ) @@ -88,6 +90,7 @@ func TestProvideInvoke(t *testing.T) { testCell := cell.Module( "test", + "Test Module", cell.Provide(func() *SomeObject { return &SomeObject{10} }), cell.Invoke(func(*SomeObject) { invoked = true }), ) @@ -106,6 +109,7 @@ func TestProvidePrivate(t *testing.T) { testCell := cell.Module( "test", + "Test Module", cell.ProvidePrivate(func() *SomeObject { return &SomeObject{10} }), cell.Invoke(func(*SomeObject) { invoked = true }), ) diff --git a/pkg/k8s/client/cell.go b/pkg/k8s/client/cell.go index 3ba1b41335d4d..5b9061d570bd4 100644 --- a/pkg/k8s/client/cell.go +++ b/pkg/k8s/client/cell.go @@ -50,6 +50,7 @@ import ( // used by Cilium. var Cell = cell.Module( "k8s-client", + "Kubernetes Client", cell.Config(defaultConfig), cell.Provide(newClientset), diff --git a/pkg/k8s/resource/example/main.go b/pkg/k8s/resource/example/main.go index 6b23ce9a513e6..e2356476634f6 100644 --- a/pkg/k8s/resource/example/main.go +++ b/pkg/k8s/resource/example/main.go @@ -55,6 +55,8 @@ func main() { var resourcesCell = cell.Module( "resources", + "Kubernetes Pod and Service resources", + cell.Provide( func(lc hive.Lifecycle, c client.Clientset) resource.Resource[*corev1.Pod] { if !c.IsEnabled() { @@ -75,6 +77,8 @@ var resourcesCell = cell.Module( var printServicesCell = cell.Module( "print-services", + "Prints Kubernetes Services", + cell.Provide(newPrintServices), )