Repository navigation
DAOS-19809 control: Enable multiprovider functionality #19346
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
2d30093
4827161
d4e2c3a
4c62db8
58a4456
3d8aaa8
1f803f4
55b45f3
414c0b8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -40,7 +40,7 @@ const ( | |
| type FabricConfig struct { | ||
| Provider string `yaml:"provider,omitempty" cmdEnv:"D_PROVIDER"` | ||
| Interface string `yaml:"fabric_iface,omitempty" cmdEnv:"D_INTERFACE"` | ||
| InterfacePort int `yaml:"fabric_iface_port,omitempty" cmdEnv:"D_PORT,nonzero"` | ||
| InterfacePort string `yaml:"fabric_iface_port,omitempty" cmdEnv:"D_PORT"` | ||
|
Comment on lines
41
to
+43
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For example, with two providers:
It already happens with a single provider: From my investigation with copilot, a good place to normalise these lists is // server/server.go
func processConfig(log logging.Logger, cfg *config.Server, ...) error {
processFabricConfig(cfg)
...
// processFabricConfig normalizes the fabric configuration before it is validated: it appends the
// RXM provider where needed and rewrites the provider, interface and port lists without blanks
// and empty items. A list that cannot be parsed is left as it is, for the config validation to
// report.
func processFabricConfig(cfg *config.Server) {
if providers, err := cfg.Fabric.GetProviders(); err == nil {
for i, p := range providers {
if shouldAppendRXM(p) {
providers[i] = p + ";ofi_rxm"
}
}
cfg.WithFabricProvider(strings.Join(providers, engine.MultiProviderSeparator))
}
for _, ec := range cfg.Engines {
if ifaces, err := ec.Fabric.GetInterfaces(); err == nil {
ec.Fabric.Interface = strings.Join(ifaces, engine.MultiProviderSeparator)
}
if ports, err := ec.Fabric.GetInterfacePorts(); err == nil {
strPorts := make([]string, len(ports))
for i, port := range ports {
strPorts[i] = strconv.Itoa(port)
}
ec.Fabric.InterfacePort = strings.Join(strPorts, engine.MultiProviderSeparator)
}
}
}
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Normalizing makes sense. I'll go ahead and do that, thanks.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The getters are called in so many places, the normalization actually has to happen very early, well before |
||
| NumaNodeIndex uint `yaml:"-"` | ||
| BypassHealthChk *bool `yaml:"bypass_health_chk,omitempty" cmdLongFlag:"--bypass_health_chk" cmdShortFlag:"-b"` | ||
| CrtTimeout uint32 `yaml:"crt_timeout,omitempty" cmdEnv:"CRT_TIMEOUT"` | ||
|
|
@@ -50,6 +50,25 @@ type FabricConfig struct { | |
| AuthKey string `yaml:"fabric_auth_key,omitempty" cmdEnv:"D_PROVIDER_AUTH_KEY"` | ||
| } | ||
|
|
||
| // Normalize adjusts the format of the fabric configuration strings that are exported to CaRT. | ||
| func (fc *FabricConfig) Normalize() { | ||
| normalizeMultiprov := func(multiProvStr string) string { | ||
| strs := strings.Split(multiProvStr, MultiProviderSeparator) | ||
| result := []string{} | ||
| for _, s := range strs { | ||
| s = strings.TrimSpace(s) | ||
| if s != "" { | ||
| result = append(result, s) | ||
| } | ||
| } | ||
| return strings.Join(result, MultiProviderSeparator) | ||
| } | ||
|
|
||
| fc.Provider = normalizeMultiprov(fc.Provider) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't we be changing the names to plurals to make sure the naming continues to be accurate and intuitive? if the user could expect the strings to indicate multiple providers then we should be calling the struct field "Providers" so as with Interfaces and InterfacePorts.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I went back and forth on this myself. With the internal names we could go either way, but I was reluctant to render the config file non-backwards-compatible even for folks not using the multiprovider feature (which is most users). |
||
| fc.Interface = normalizeMultiprov(fc.Interface) | ||
| fc.InterfacePort = normalizeMultiprov(fc.InterfacePort) | ||
| } | ||
|
|
||
| // GetPrimaryProvider parses the primary provider from the Provider string. | ||
| func (fc *FabricConfig) GetPrimaryProvider() (string, error) { | ||
| providers, err := fc.GetProviders() | ||
|
|
@@ -76,15 +95,10 @@ func (fc *FabricConfig) GetProviders() ([]string, error) { | |
|
|
||
| func splitMultiProviderStr(str string) []string { | ||
| strs := strings.Split(str, MultiProviderSeparator) | ||
| result := make([]string, 0) | ||
| for _, s := range strs { | ||
| trimmed := strings.TrimSpace(s) | ||
| if trimmed != "" { | ||
| result = append(result, trimmed) | ||
| } | ||
| if len(strs) == 1 && strs[0] == "" { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe this could be handled with a "MultiValueString" type that handed the serialisation/deserialisation internally that we could apply to values like Providers/Interfaces/InterfacePorts that had this behaviour rather than sprinkling around the normalize and split helper functions?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good idea for a future improvement. |
||
| return nil | ||
| } | ||
|
|
||
| return result | ||
| return strs | ||
| } | ||
|
|
||
| // GetNumProviders gets the number of fabric providers configured. | ||
|
|
@@ -121,16 +135,25 @@ func (fc *FabricConfig) GetInterfaces() ([]string, error) { | |
| } | ||
|
|
||
| // GetInterfacePorts parses the InterfacePort string to one or more ports. | ||
| func (fc *FabricConfig) GetInterfacePorts() ([]int, error) { | ||
| func (fc *FabricConfig) GetInterfacePorts() ([]uint, error) { | ||
| if fc == nil { | ||
| return nil, errors.New("FabricConfig is nil") | ||
| } | ||
|
|
||
| if fc.InterfacePort == 0 { | ||
| portStrs := splitMultiProviderStr(fc.InterfacePort) | ||
| if len(portStrs) == 0 { | ||
| return nil, errors.New("fabric_iface_port not set") | ||
| } | ||
|
|
||
| return []int{fc.InterfacePort}, nil | ||
| ports := make([]uint, 0) | ||
| for _, str := range portStrs { | ||
| uint64Port, err := strconv.ParseUint(str, 10, 16) | ||
| if err != nil || uint64Port == 0 { | ||
| return nil, errors.Errorf("fabric_iface_port item %q: must be an integer in the range 1-65535", str) | ||
| } | ||
| ports = append(ports, uint(uint64Port)) // OK to truncate to 32 bits | ||
| } | ||
| return ports, nil | ||
| } | ||
|
|
||
| // Update fills in any missing fields from the provided FabricConfig. | ||
|
|
@@ -145,7 +168,7 @@ func (fc *FabricConfig) Update(other FabricConfig) { | |
| if fc.Interface == "" { | ||
| fc.Interface = other.Interface | ||
| } | ||
| if fc.InterfacePort == 0 { | ||
| if fc.InterfacePort == "" { | ||
| fc.InterfacePort = other.InterfacePort | ||
| } | ||
| if fc.CrtTimeout == 0 { | ||
|
|
@@ -190,13 +213,7 @@ func (fc *FabricConfig) Validate() error { | |
| return err | ||
| } | ||
|
|
||
| for _, p := range ports { | ||
| if p < 0 { | ||
| return errors.New("fabric_iface_port cannot be negative") | ||
| } | ||
| } | ||
|
|
||
| if len(interfaces) != numProv { // TODO SRS-31: check num ports when multiprovider fully enabled: || len(ports) != numProv { | ||
| if len(interfaces) != numProv || len(ports) != numProv { | ||
| return errors.Errorf("provider, fabric_iface and fabric_iface_port must include the same number of items delimited by %q", MultiProviderSeparator) | ||
| } | ||
|
|
||
|
|
@@ -701,7 +718,7 @@ func (c *Config) WithFabricInterface(iface string) *Config { | |
|
|
||
| // WithFabricInterfacePort sets the numeric interface port to be used by this instance. | ||
| func (c *Config) WithFabricInterfacePort(ifacePort int) *Config { | ||
| c.Fabric.InterfacePort = ifacePort | ||
| c.Fabric.InterfacePort = fmt.Sprintf("%d", ifacePort) | ||
| return c | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, I think this probably would look better with the system property flags printed after the provider table