Skip to content

Commit e0bee3b

Browse files
authored
refactor: Split component manager registry wiring (#530)
Signed-off-by: Jin Wang <jinwan@nvidia.com>
1 parent 26368b9 commit e0bee3b

36 files changed

Lines changed: 2968 additions & 1535 deletions

flow/cmd/serve.go

Lines changed: 1 addition & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import (
3636
svc "github.com/NVIDIA/infra-controller-rest/flow/internal/service"
3737
cmbuiltin "github.com/NVIDIA/infra-controller-rest/flow/internal/task/componentmanager/builtin"
3838
cmconfig "github.com/NVIDIA/infra-controller-rest/flow/internal/task/componentmanager/config"
39-
"github.com/NVIDIA/infra-controller-rest/flow/internal/task/componentmanager/providerapi"
4039
temporalmanager "github.com/NVIDIA/infra-controller-rest/flow/internal/task/executor/temporalworkflow/manager"
4140
pkgcerts "github.com/NVIDIA/infra-controller-rest/flow/pkg/certs"
4241
)
@@ -88,64 +87,6 @@ func init() {
8887
serveCmd.Flags().BoolVar(&devMode, "dev-mode", false, "Enable developer options (gRPC reflection, debug logging). Not for production use.") //nolint:lll
8988
}
9089

91-
// initProviderRegistry creates and initializes the provider registry from
92-
// decoded provider configs.
93-
func initProviderRegistry(
94-
ctx context.Context,
95-
config cmconfig.Config,
96-
) (*providerapi.ProviderRegistry, error) {
97-
providerRegistry := providerapi.NewProviderRegistry()
98-
99-
for name, providerConfig := range config.ProviderConfigs {
100-
// loadComponentManagerConfig builds ProviderConfigs through the
101-
// service decoders, which either return a concrete config or an
102-
// error. The nil check below is defensive: a custom decoder
103-
// registry passed to cmconfig.ParseConfig is not bound by that
104-
// invariant, so we reject nil configs here rather than panic on
105-
// providerConfig.Name().
106-
if providerConfig == nil {
107-
return nil, providerapi.ProviderNotConfiguredError{Name: name}
108-
}
109-
configName := providerConfig.Name()
110-
if name != configName {
111-
return nil, providerapi.ProviderConfigNameMismatchError{
112-
Name: name,
113-
ConfigName: configName,
114-
}
115-
}
116-
117-
provider, err := providerConfig.NewProvider(ctx)
118-
if err != nil {
119-
return nil, fmt.Errorf("create provider %q: %w", name, err)
120-
}
121-
if provider == nil {
122-
return nil, providerapi.ProviderNotConfiguredError{Name: name}
123-
}
124-
125-
providerName := provider.Name()
126-
if providerName != name {
127-
return nil, providerapi.ProviderNameMismatchError{
128-
Name: name,
129-
ProviderName: providerName,
130-
}
131-
}
132-
if err := providerRegistry.Register(provider); err != nil {
133-
return nil, err
134-
}
135-
log.Info().
136-
Str("provider", name).
137-
Msg("Initialized provider")
138-
}
139-
140-
// Log all registered providers
141-
registeredProviders := providerRegistry.List()
142-
log.Info().
143-
Strs("providers", registeredProviders).
144-
Msg("Provider registry initialized")
145-
146-
return providerRegistry, nil
147-
}
148-
14990
// loadComponentManagerConfig loads the component manager configuration with the following priority:
15091
//
15192
// 1. CLI flag: --component-config / -c <path>
@@ -224,7 +165,7 @@ func doServe() {
224165
}
225166

226167
// Initialize provider registry (creates API clients based on config)
227-
providerRegistry, err := initProviderRegistry(ctx, cmConfig)
168+
providerRegistry, err := cmbuiltin.NewProviderRegistry(ctx, cmConfig)
228169
if err != nil {
229170
log.Fatal().Msgf("failed to initialize provider registry: %v", err)
230171
}

flow/docs/component-manager-architecture.md

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ provider, err := providerapi.GetTyped[*nico.Provider](
7171

7272
```go
7373
type ComponentManager interface {
74-
Type() devicetypes.ComponentType
74+
Descriptor() cmcatalog.Descriptor
7575
InjectExpectation(ctx, target, info) error
7676
PowerControl(ctx, target, info) error
7777
FirmwareControl(ctx, target, info) error
@@ -88,17 +88,21 @@ type ManagerFactory func(providers *providerapi.ProviderRegistry) (ComponentMana
8888

8989
Factory functions create component manager instances. They receive the `ProviderRegistry` to retrieve any required providers.
9090

91+
`catalog.Descriptor` contains static implementation metadata used for
92+
configuration validation. `FactorySpec` pairs that descriptor with the runtime
93+
factory used after service config has been loaded.
94+
9195
### Catalog and Registry
9296

93-
The `Catalog` stores validated descriptors for implementations compiled into a
94-
service binary:
95-
- `NewCatalog()` - Validate descriptors and index them by component type and
97+
The `catalog.Catalog` stores validated descriptors for implementations compiled
98+
into a service binary:
99+
- `catalog.New()` - Validate descriptors and index them by component type and
96100
implementation
97101
- `ListImplementations()` - List supported implementations by component type
98102

99-
The `Registry` stores active managers selected from a catalog:
103+
The `Registry` stores active managers selected from runtime factory specs:
100104
- `NewRegistry()` - Create managers based on configuration and the supplied
101-
catalog
105+
factory specs
102106
- `GetManager()` - Retrieve active manager for a component type, returning a
103107
descriptive error when the registry is not configured or no manager is active
104108
- `GetDescriptor()` - Retrieve the descriptor selected for a component type
@@ -108,7 +112,9 @@ The `Registry` stores active managers selected from a catalog:
108112

109113
```
110114
internal/task/componentmanager/
111-
├── componentmanager.go # ComponentManager interface, Registry
115+
├── manager.go # ComponentManager interface
116+
├── factory_spec.go # Manager factories and factory specs
117+
├── registry.go # Active component manager registry
112118
├── providerapi/ # Provider interfaces and registries
113119
├── config.go # Configuration parsing
114120
├── mock/
@@ -235,7 +241,7 @@ func serviceProviderConfigDecoders() []providerapi.ProviderConfigDecoder {
235241
`cmd/serve.go` does not need provider-specific construction code. It loads the
236242
service config through `builtin.LoadConfig`, then creates providers from the
237243
decoded generic provider configs. Built-in provider decoders and component
238-
manager factory registration both live in `internal/task/componentmanager/builtin`.
244+
manager factory specs both live in `internal/task/componentmanager/builtin`.
239245

240246
---
241247

@@ -255,6 +261,7 @@ import (
255261
"fmt"
256262

257263
"github.com/NVIDIA/infra-controller-rest/flow/internal/task/componentmanager"
264+
cmcatalog "github.com/NVIDIA/infra-controller-rest/flow/internal/task/componentmanager/catalog"
258265
"github.com/NVIDIA/infra-controller-rest/flow/internal/task/componentmanager/providerapi"
259266
myapiprovider "github.com/NVIDIA/infra-controller-rest/flow/internal/task/componentmanager/providers/myapi"
260267
"github.com/NVIDIA/infra-controller-rest/flow/internal/task/executor/temporalworkflow/common"
@@ -287,18 +294,25 @@ func Factory(providers *providerapi.ProviderRegistry) (componentmanager.Componen
287294
}
288295

289296
// Descriptor returns this implementation's descriptor.
290-
func Descriptor() componentmanager.Descriptor {
291-
return componentmanager.Descriptor{
297+
func Descriptor() cmcatalog.Descriptor {
298+
return cmcatalog.Descriptor{
292299
Type: devicetypes.ComponentTypeCompute,
293300
Implementation: ImplementationName,
294301
RequiredProviders: []string{myapiprovider.ProviderName},
295-
Factory: Factory,
296302
}
297303
}
298304

299-
// Type returns the component type.
300-
func (m *Manager) Type() devicetypes.ComponentType {
301-
return devicetypes.ComponentTypeCompute
305+
// FactorySpec returns this implementation's runtime factory spec.
306+
func FactorySpec() componentmanager.FactorySpec {
307+
return componentmanager.FactorySpec{
308+
Descriptor: Descriptor(),
309+
Factory: Factory,
310+
}
311+
}
312+
313+
// Descriptor returns this implementation's descriptor.
314+
func (m *Manager) Descriptor() cmcatalog.Descriptor {
315+
return Descriptor()
302316
}
303317

304318
// InjectExpectation implements ComponentManager.
@@ -324,15 +338,26 @@ Update the service-supported manager catalog in
324338

325339
```go
326340
import (
341+
"github.com/NVIDIA/infra-controller-rest/flow/internal/task/componentmanager"
342+
cmcatalog "github.com/NVIDIA/infra-controller-rest/flow/internal/task/componentmanager/catalog"
343+
cmconfig "github.com/NVIDIA/infra-controller-rest/flow/internal/task/componentmanager/config"
327344
myimpl "github.com/NVIDIA/infra-controller-rest/flow/internal/task/componentmanager/compute/myimpl"
328345
)
329346

330-
func serviceCatalog(config cmconfig.Config) (componentmanager.Catalog, error) {
331-
descriptors := []componentmanager.Descriptor{
347+
func serviceDescriptors() []cmcatalog.Descriptor {
348+
descriptors := []cmcatalog.Descriptor{
332349
// ... existing descriptors ...
333350
myimpl.Descriptor(), // Add new implementation
334351
}
335-
return componentmanager.NewCatalog(descriptors)
352+
return descriptors
353+
}
354+
355+
func serviceFactorySpecs(config cmconfig.Config) ([]componentmanager.FactorySpec, error) {
356+
factorySpecs := []componentmanager.FactorySpec{
357+
// ... existing factory specs ...
358+
myimpl.FactorySpec(), // Add new implementation
359+
}
360+
return factorySpecs, nil
336361
}
337362
```
338363

flow/docs/flow-architecture.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ See [Component Manager Architecture](component-manager-architecture.md) for deta
341341

342342
```go
343343
type ComponentManager interface {
344-
Type() devicetypes.ComponentType
344+
Descriptor() cmcatalog.Descriptor
345345

346346
// Inject expectation
347347
InjectExpectation(ctx, target, info) error

0 commit comments

Comments
 (0)