diff --git a/core/communicator/device_class_communicator.go b/core/communicator/device_class_communicator.go index 3203738..cf46bb7 100644 --- a/core/communicator/device_class_communicator.go +++ b/core/communicator/device_class_communicator.go @@ -103,12 +103,19 @@ func (o *deviceClassCommunicator) GetInterfaces(ctx context.Context) ([]device.I return nil, tholaerr.NewNotImplementedError("not implemented") } - networkInterfacesRaw, _, err := o.components.interfaces.Values.getProperty(ctx) + interfacesRaw, err := o.components.interfaces.Values.getProperty(ctx) if err != nil { return nil, err } - return convertRawInterfaces(ctx, networkInterfacesRaw) + var interfaces []device.Interface + + err = interfacesRaw.Decode(&interfaces) + if err != nil { + return nil, errors.Wrap(err, "failed to decode raw interfaces into interface structs") + } + + return interfaces, nil } func (o *deviceClassCommunicator) GetCountInterfaces(ctx context.Context) (int, error) { @@ -214,7 +221,7 @@ func (o *deviceClassCommunicator) GetDiskComponentStorages(ctx context.Context) } logger := log.Ctx(ctx).With().Str("groupProperty", "DiskComponentStorages").Logger() ctx = logger.WithContext(ctx) - res, _, err := o.components.disk.storages.getProperty(ctx) + res, err := o.components.disk.storages.getProperty(ctx) if err != nil { return nil, errors.Wrap(err, "failed to get property") } @@ -449,7 +456,7 @@ func (o *deviceClassCommunicator) GetSBCComponentAgents(ctx context.Context) ([] } logger := log.Ctx(ctx).With().Str("groupProperty", "SBCComponentAgents").Logger() ctx = logger.WithContext(ctx) - res, _, err := o.components.sbc.agents.getProperty(ctx) + res, err := o.components.sbc.agents.getProperty(ctx) if err != nil { return nil, errors.Wrap(err, "failed to get property") } @@ -468,7 +475,7 @@ func (o *deviceClassCommunicator) GetSBCComponentRealms(ctx context.Context) ([] } logger := log.Ctx(ctx).With().Str("groupProperty", "SBCComponentRealms").Logger() ctx = logger.WithContext(ctx) - res, _, err := o.components.sbc.realms.getProperty(ctx) + res, err := o.components.sbc.realms.getProperty(ctx) if err != nil { return nil, errors.Wrap(err, "failed to get property") } @@ -677,7 +684,7 @@ func (o *deviceClassCommunicator) GetHardwareHealthComponentFans(ctx context.Con } logger := log.Ctx(ctx).With().Str("groupProperty", "HardwareHealthComponentFans").Logger() ctx = logger.WithContext(ctx) - res, _, err := o.components.hardwareHealth.fans.getProperty(ctx) + res, err := o.components.hardwareHealth.fans.getProperty(ctx) if err != nil { return nil, errors.Wrap(err, "failed to get property") } @@ -696,7 +703,7 @@ func (o *deviceClassCommunicator) GetHardwareHealthComponentPowerSupply(ctx cont } logger := log.Ctx(ctx).With().Str("groupProperty", "HardwareHealthComponentPowerSupply").Logger() ctx = logger.WithContext(ctx) - res, _, err := o.components.hardwareHealth.powerSupply.getProperty(ctx) + res, err := o.components.hardwareHealth.powerSupply.getProperty(ctx) if err != nil { return nil, errors.Wrap(err, "failed to get property") } @@ -707,19 +714,3 @@ func (o *deviceClassCommunicator) GetHardwareHealthComponentPowerSupply(ctx cont } return powerSupply, nil } - -func convertRawInterfaces(ctx context.Context, interfacesRaw groupProperties) ([]device.Interface, error) { - var networkInterfaces []device.Interface - - for _, oidValue := range interfacesRaw { - var networkInterface device.Interface - err := mapstructure.WeakDecode(oidValue, &networkInterface) - if err != nil { - log.Ctx(ctx).Trace().Err(err).Msg("can't parse oid values into Interface struct") - return nil, errors.Wrap(err, "can't parse oid values into Interface struct") - } - networkInterfaces = append(networkInterfaces, networkInterface) - } - - return networkInterfaces, nil -} diff --git a/core/communicator/device_class_group_properties.go b/core/communicator/device_class_group_properties.go index e7a497f..56d0b7f 100644 --- a/core/communicator/device_class_group_properties.go +++ b/core/communicator/device_class_group_properties.go @@ -15,33 +15,29 @@ import ( type propertyGroup map[string]interface{} -func (g propertyGroup) Decode(destination interface{}) error { - return mapstructure.WeakDecode(g, destination) -} +type propertyGroups []propertyGroup -type groupProperties []propertyGroup - -func (g groupProperties) Decode(destination interface{}) error { +func (g *propertyGroups) Decode(destination interface{}) error { return mapstructure.WeakDecode(g, destination) } type groupPropertyReader interface { - getProperty(ctx context.Context) (groupProperties, map[string]int, error) + getProperty(ctx context.Context) (propertyGroups, error) } type snmpGroupPropertyReader struct { oids deviceClassOIDs } -func (s *snmpGroupPropertyReader) getProperty(ctx context.Context) (groupProperties, map[string]int, error) { +func (s *snmpGroupPropertyReader) getProperty(ctx context.Context) (propertyGroups, error) { groups, err := s.oids.readOID(ctx) if err != nil { - return nil, nil, errors.Wrap(err, "failed to read oids") + return nil, errors.Wrap(err, "failed to read oids") } - var res groupProperties - indices := make(map[string]int) + var res propertyGroups + // this sorts the groups after their ifIndex //TODO efficiency size := len(groups) for i := 0; i < size; i++ { @@ -58,50 +54,40 @@ func (s *snmpGroupPropertyReader) getProperty(ctx context.Context) (groupPropert } x, ok := groups[smallestIndex].(map[string]interface{}) if !ok { - return nil, nil, fmt.Errorf("oidReader for index '%d' returned unexpected data type: %T", smallestIndex, groups[smallestIndex]) + return nil, fmt.Errorf("oidReader for index '%d' returned unexpected data type: %T", smallestIndex, groups[smallestIndex]) } res = append(res, x) - indices[fmt.Sprint(smallestIndex)] = i delete(groups, smallestIndex) } - return res, indices, nil + return res, nil } type oidReader interface { readOID(context.Context) (map[int]interface{}, error) } -// deviceClassOIDs maps labels to OIDs. +// deviceClassOIDs is a recursive data structure which maps labels to either a single OID (deviceClassOID) or another deviceClassOIDs type deviceClassOIDs map[string]oidReader func (d *deviceClassOIDs) readOID(ctx context.Context) (map[int]interface{}, error) { result := make(map[int]map[string]interface{}) - for name, oidReader := range *d { - res, err := oidReader.readOID(ctx) + for label, reader := range *d { + res, err := reader.readOID(ctx) if err != nil { if tholaerr.IsNotFoundError(err) { - log.Ctx(ctx).Trace().Err(err).Msgf("value %s", name) + log.Ctx(ctx).Trace().Err(err).Msgf("value %s", label) continue } - return nil, errors.Wrapf(err, "failed to get value '%s'", name) + return nil, errors.Wrapf(err, "failed to get value '%s'", label) } for ifIndex, v := range res { + // ifIndex was not known before, so create a new group if _, ok := result[ifIndex]; !ok { result[ifIndex] = make(map[string]interface{}) } - if m, ok := v.(map[string]interface{}); ok { - newMap := make(map[string]interface{}) - for k, val := range m { - newMap[k] = val - } - result[ifIndex][name] = newMap - } else if val, ok := v.(value.Value); ok { - result[ifIndex][name] = val - } else { - return nil, fmt.Errorf("oidReader returned unexpected data type: %T", v) - } + result[ifIndex][label] = v } } @@ -134,6 +120,7 @@ func (d *deviceClassOIDs) merge(overwrite deviceClassOIDs) deviceClassOIDs { return devClassOIDsNew } +// deviceClassOID represents a single OID which can be read type deviceClassOID struct { network.SNMPGetConfiguration operators propertyOperators diff --git a/core/communicator/ekinops.go b/core/communicator/ekinops.go index 6a7e4fc..a2e5137 100644 --- a/core/communicator/ekinops.go +++ b/core/communicator/ekinops.go @@ -70,7 +70,7 @@ func (c *ekinopsCommunicator) GetInterfaces(ctx context.Context) ([]device.Inter return normalizeEkinopsInterfaces(interfaces) } -// GetInterfaces returns the interfaces of ekinops devices. +// GetIfTable returns the ifTable of ekinops devices. // For ekinops devices, only a few interface values are required. func (c *ekinopsCommunicator) GetIfTable(ctx context.Context) ([]device.Interface, error) { if genericDeviceClass.components.interfaces.Values == nil { @@ -92,12 +92,19 @@ func (c *ekinopsCommunicator) GetIfTable(ctx context.Context) ([]device.Interfac } reader.oids = oids - networkInterfacesRaw, _, err := reader.getProperty(ctx) + interfacesRaw, err := reader.getProperty(ctx) if err != nil { return nil, err } - return convertRawInterfaces(ctx, networkInterfacesRaw) + var interfaces []device.Interface + + err = interfacesRaw.Decode(&interfaces) + if err != nil { + return nil, errors.Wrap(err, "failed to decode raw interfaces into interface structs") + } + + return interfaces, nil } func ekinopsInterfacesIfIdentifierToSliceIndex(interfaces []device.Interface) (map[string]int, error) { diff --git a/core/communicator/network_device_communicator.go b/core/communicator/network_device_communicator.go index d68f574..95e23f1 100644 --- a/core/communicator/network_device_communicator.go +++ b/core/communicator/network_device_communicator.go @@ -60,7 +60,6 @@ type availableCommunicatorFunctions interface { GetOSVersion(ctx context.Context) (string, error) // GetInterfaces returns the interfaces of a device. - // This includes special interface values. GetInterfaces(ctx context.Context) ([]device.Interface, error) // GetCountInterfaces returns the count of interfaces of a device.