-
Notifications
You must be signed in to change notification settings - Fork 8
Refactor BMC ID Mapping and add deterministic generated XNAMEs #114
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
Merged
+315
−120
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package util | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "net" | ||
| ) | ||
|
|
||
| func IPAddrStrToInt(ipStr string)(int, error) { | ||
| // Generate an integer from an IP address. This is not | ||
| // sensitive to byte ordering, so the integer produced on | ||
| // different systems may be different. It will be consistent | ||
| // for any specific architecture. | ||
| ip := net.ParseIP(ipStr).To4() | ||
| if ip == nil { | ||
| return 0, fmt.Errorf("cannot convert invalid IPv4 address string '%s' to integer", ipStr) | ||
| } | ||
| return (int(ip[0]) * (1 << 24)) + (int(ip[1]) * (1 << 16)) + (int(ip[2]) * (1 << 8)) + int(ip[3]), nil | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,19 +39,10 @@ type CollectParams struct { | |
| Format string // set the output format | ||
| ForceUpdate bool // set whether to force updating SMD with 'force-update' flag | ||
| AccessToken string // set the access token to include in request with 'access-token' flag | ||
| BMCIdMap string // Set the path to the BMC ID mapping YAML or JSON file (if any) | ||
| BMCIDMap string // Set the path to the BMC ID mapping YAML or JSON data or file name (if any) | ||
| SecretStore secrets.SecretStore // set BMC credentials | ||
| } | ||
|
|
||
| // BMCIdMap contains the mapping of host address strings to BMC Identifiers | ||
| // supplied by the --bmc-id-map option to collect. IdMap is the mapping itself, | ||
| // MapKey specifies what string to use as the key to the map. For now, that is | ||
| // always 'bmc-ip-addr'. In the future other options may be available. | ||
| type BMCIdMap struct { | ||
| IdMap map[string]string `json:"id_map" yaml:"id_map"` | ||
| MapKey string `json:"map_key" yaml:"map_key"` | ||
| } | ||
|
|
||
| // This is the main function used to collect information from the BMC nodes via Redfish. | ||
| // The results of the collect are stored in a cache specified with the `--cache` flag. | ||
| // The function expects a list of hosts found using the `ScanForAssets()` function. | ||
|
|
@@ -74,27 +65,9 @@ func CollectInventory(assets *[]RemoteAsset, params *CollectParams) ([]map[strin | |
| found = make([]string, 0, len(*assets)) | ||
| done = make(chan struct{}, params.Concurrency+1) | ||
| chanAssets = make(chan RemoteAsset, params.Concurrency+1) | ||
| bmcIdMap *BMCIdMap | ||
| mapper idMapper = pickIDMapper(params) | ||
| err error | ||
| ) | ||
| // Get the host to BMC ID mapping | ||
| bmcIdMap, err = getBMCIdMap(params.BMCIdMap, params.Format) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| // Validate the MapKey field in the ID Map if a map was found | ||
| // (the only value currently allowed is 'bmc-ip-addr', but | ||
| // this is where any other legal values would be added). | ||
| if bmcIdMap != nil { | ||
| switch bmcIdMap.MapKey { | ||
| case "bmc-ip-addr": | ||
| break | ||
| default: | ||
| return nil, fmt.Errorf("invalid 'map_key' field '%s' in BMC ID Map a valid value is 'bmc-ip-addr", bmcIdMap.MapKey) | ||
| } | ||
| } else { | ||
| log.Warn().Msg("no BMC ID Map (--bmc-id-map string option) provided, BMC IDs will be IP addresses which are incompatible with SMD") | ||
| } | ||
|
|
||
| // set the client's params from CLI | ||
| wg.Add(params.Concurrency) | ||
|
|
@@ -109,13 +82,18 @@ func CollectInventory(assets *[]RemoteAsset, params *CollectParams) ([]map[strin | |
|
|
||
| trimmedHost := strings.TrimPrefix(sr.Host, "https://") | ||
| uri := fmt.Sprintf("%s:%d", sr.Host, sr.Port) | ||
| bmcId := getBMCId(bmcIdMap, trimmedHost) | ||
|
|
||
| // If bmcId is empty, skip this BMC. Empty means that there | ||
| // is a valid mapping, but there was no match for this host | ||
| // in the mapping, meaning that the BMC is unrecognized. Skip | ||
| // this BMC. | ||
| if bmcId == "" { | ||
| keys := &idMapperKeys { | ||
| IPv4Addr: trimmedHost, | ||
| } | ||
| bmcID := mapper.getMappedID(keys) | ||
|
|
||
| // If bmcID is empty, skip this | ||
| // BMC. Empty means that there is a | ||
| // valid mapping, but there was no | ||
| // match for this host in the mapping, | ||
| // meaning that the BMC is | ||
| // unrecognized. Skip this BMC. | ||
| if bmcID == "" { | ||
| continue | ||
| } | ||
|
|
||
|
|
@@ -154,7 +132,7 @@ func CollectInventory(assets *[]RemoteAsset, params *CollectParams) ([]map[strin | |
|
|
||
| // data to be sent to smd | ||
| data := map[string]any{ | ||
| "ID": bmcId, | ||
| "ID": bmcID, | ||
| "Type": "", | ||
| "Name": "", | ||
| "FQDN": strings.TrimPrefix(sr.Host, "https://"), | ||
|
|
@@ -359,73 +337,3 @@ func FindMACAddressWithIP(config crawler.CrawlerConfig, targetIP net.IP) (string | |
| // no matches found, so return an empty string | ||
| return "", fmt.Errorf("no ethernet interfaces found with IP address") | ||
| } | ||
|
|
||
|
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. REVIEWERS: I moved this code to the User Porvided ID Mapper implementation. |
||
| func getBMCIdMap(data string, format string)(*BMCIdMap, error) { | ||
| // If no mapping is provided, there is no error, but there is | ||
| // also no mapping, just return nil with no error and let the | ||
| // caller pass that around. | ||
| if data == "" { | ||
| return nil, nil | ||
| } | ||
|
|
||
| var bmcIdMap BMCIdMap | ||
| // First, check whether 'data' specifies a file (i.e. starts | ||
| // with '@'). If not, it should be a JSON string containing the | ||
| // map data. Otherwise, strip the '@' and fall through. | ||
| if data[0] != '@' { | ||
| err := json.Unmarshal([]byte(data), &bmcIdMap) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| return &bmcIdMap, nil | ||
| } | ||
|
|
||
| // The map data is in a file. Get the path from what comes | ||
| // after the '@' and process it. | ||
| path := data[1:] | ||
|
|
||
| // Read in the contents of the map file, since we are going to | ||
| // do that no matter what type it is... | ||
| input, err := os.ReadFile(path) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("error reading BMC ID mapping file '%s': %v", path, err) | ||
| } | ||
|
|
||
| // Decode the file based on the appropriate format. | ||
| switch util.DataFormatFromFileExt(path, format) { | ||
| case util.FORMAT_JSON: | ||
| // Read in JSON file | ||
| err := json.Unmarshal(input, &bmcIdMap) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| case util.FORMAT_YAML: | ||
| // Read in YAML file | ||
| err := yaml.Unmarshal(input, &bmcIdMap) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| } | ||
| return &bmcIdMap, nil | ||
| } | ||
|
|
||
| // Generate a BMC ID string associated with 'selector' in the provided | ||
| // 'BMCIdMap'. If there is no map, then return the selector string | ||
| // itself. If the map is present but the host is not present in the | ||
| // map, then log a warning and return an empty string indicating that | ||
| // the BMC ID was not composed. | ||
| func getBMCId(bmcIdMap *BMCIdMap, selector string) (string) { | ||
| if bmcIdMap == nil { | ||
| return selector | ||
| } | ||
| // Go does not error out on string map references that do not | ||
| // match the selector, it simply produces an empty | ||
| // string. Recognize that case and log it, then return an | ||
| // empty string. | ||
| bmcId := bmcIdMap.IdMap[selector] | ||
| if bmcId == "" { | ||
| log.Warn().Msgf("no mapping found from host selector '%v' to a BMC ID", selector) | ||
| return "" | ||
| } | ||
| return bmcId | ||
| } | ||
|
davidallendj marked this conversation as resolved.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| // Package magellan implements the core routines for the tools. | ||
| package magellan | ||
|
|
||
| import "github.com/rs/zerolog/log" | ||
|
|
||
| // This file is the top-level of the BMC ID Mapping infrastructure. It | ||
| // defines the interface into all BMC ID Mappers, the structure of the | ||
| // parameters for ID Mapping, and a function for picking a BMC ID | ||
| // Mapper to use. | ||
| // | ||
| // Implementations of specific ID mappers are found in files with the | ||
| // prefix 'idmap_' in this directory. To extend the BMC ID Mapping | ||
| // capability, create a new mapper in its own file, and then add the | ||
| // mapper selection logic for your new mapper to pickIDMapper() here. | ||
|
|
||
| // The structure passed into the GetMappedID() function as the key | ||
| // options for a mapper. Currently only contains the IPv4 address of | ||
| // the BMC in question. | ||
| type idMapperKeys struct { | ||
| IPv4Addr string | ||
| } | ||
|
|
||
| type idMapper interface { | ||
| initialize()(idMapper, error) | ||
| getMappedID(keys *idMapperKeys)(string) | ||
| } | ||
|
|
||
| // Select the correct BMC ID Mapper based on the parameters to | ||
| // 'collect'. | ||
| func pickIDMapper(params *CollectParams)(idMapper) { | ||
| // If the parameters contain a BMC ID Map (user defined | ||
| // mapping of a key to a BMC ID) then we use the userProvidedMapper | ||
| // implementaiton of an ID Mapper. Until other BMC ID schemes | ||
| // are implemented, the other case is simply to use the | ||
| // generated XNAME mapper, generatedXNAMEMapper. | ||
| var ( | ||
| mapper idMapper | ||
| mapperName string | ||
| err error | ||
| ) | ||
|
|
||
| if params.BMCIDMap != "" { | ||
| // Always use the user provided mapper if a user | ||
| // provided map is present. | ||
| mapperName = "userProvidedMapper" | ||
| mapper = userProvidedMapper { | ||
| IDMapStr: params.BMCIDMap, | ||
| IDMapFormat: params.Format, | ||
| } | ||
| } else { | ||
| // Currently the only other mapper is the generated | ||
| // XNAMEs mapper, since no user provided mapper was | ||
| // offered, use that instead. | ||
| mapperName = "generatedXNAMEMapper" | ||
| mapper = generatedXNAMEMapper{} | ||
| } | ||
| mapper, err = mapper.initialize() | ||
| if err != nil { | ||
| log.Error().Err(err).Str("Mapper Name", mapperName).Msg("failed to initialized BMC ID Mapper") | ||
| } | ||
| return mapper | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
REVIEWERS: I went through and made the use of "ID" in symbols consistently same case: either "id" or "ID" for all of my symbols in hopes of making the names easier to predict and use. Hence this one change here.