Skip to content

Commit

Permalink
Allow using regexp for model_map and group_map keys (ytti#3362)
Browse files Browse the repository at this point in the history
* Allow using regexp for model_map and group_map keys

Use case is that the source returns string which has unrelated and variant data
but the actual model is included somewhere in this data

For example source could have space separated list of tags and one of these
tags could be model name. Eg 'procurve switch'.

Closes ytti#3360

* stop normalising config keys into string
* comment and document regexp maps

---------

Co-authored-by: Robert Cheramy <r.cheramy@netze-bw.de>
  • Loading branch information
ytti and robertcheramy authored Jan 15, 2025
1 parent 6afc21d commit c7f0bdc
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
### Added
- junos: add unit test (@systeembeheerder)
- apc_aos: support for scp (@robertcheramy)
- config: allow model_map and group_map keys to be regexp. Fixes #3360 (@ytti)

### Changed
- sonicos: accept policy message. Fixes #3339 (@Steve-M-C, @robertcheramy)
Expand Down
16 changes: 14 additions & 2 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,16 @@ input:

## Advanced Configuration

Below is an advanced example configuration. You will be able to (optionally) override options per device. The router.db format used is `hostname:model:username:password:enable_password`. Hostname and model will be the only required options, all others override the global configuration sections.
Below is an advanced example configuration.

You will be able to (optionally) override options per device.
The router.db format used is `hostname:model:username:password:enable_password`.
Hostname and model will be the only required options, all others override the
global configuration sections.

Custom model names can be mapped to an oxidized model name with a string or
a regular expression.


```yaml
---
Expand Down Expand Up @@ -226,6 +235,7 @@ source:
model_map:
cisco: ios
juniper: junos
!ruby/regexp /procurve/: procurve
```

## Advanced Group Configuration
Expand Down Expand Up @@ -268,14 +278,16 @@ groups:
ssh_keys: "~/.ssh/id_rsa_bar_vyatta"
```

For mapping multiple group values to a common name
For mapping multiple group values to a common name, you can use strings and
regular expressions:

```yaml
group_map:
alias1: groupA
alias2: groupA
alias3: groupB
alias4: groupB
!ruby/regexp /specialgroup/: groupS
aliasN: groupZ
# ...
```
Expand Down
2 changes: 1 addition & 1 deletion lib/oxidized/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def self.load(cmd_opts = {})
cfgfile = cmd_opts[:config_file] || 'config'
# configuration file with full path as a class instance variable
@configfile = File.join(usrdir, cfgfile)
asetus = Asetus.new(name: 'oxidized', load: false, key_to_s: true, usrdir: usrdir, cfgfile: cfgfile)
asetus = Asetus.new(name: 'oxidized', load: false, usrdir: usrdir, cfgfile: cfgfile)
Oxidized.asetus = asetus

asetus.default.username = 'username'
Expand Down
34 changes: 32 additions & 2 deletions lib/oxidized/source/source.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,42 @@ def initialize
@group_map = Oxidized.config.group_map || {}
end

# common code of #map_model and #map_group
def map_value(map_hash, original_value)
map_hash.each do |key, new_value|
mthd = key.instance_of?(Regexp) ? :match : :eql?
return new_value if original_value.send(mthd, key)
end
original_value
end

# search a match for model in the configuration and returns it.
# If no match is found, return model
#
# model can be matched against a string or a regexp:
#
# model_map:
# cisco: ios
# juniper: junos
# !ruby/regexp /procurve/: procurve
def map_model(model)
@model_map.has_key?(model) ? @model_map[model] : model
map_value(@model_map, model)
end

# search a match for group in the configuration and returns it.
# If no match is found, return group
#
# group can be matched against a string or a regexp:
#
# group_map:
# alias1: groupA
# alias2: groupA
# alias3: groupB
# alias4: groupB
# !ruby/regexp /specialgroup/: groupS
# aliasN: groupZ
def map_group(group)
@group_map.has_key?(group) ? @group_map[group] : group
map_value(@group_map, group)
end

def node_var_interpolate(var)
Expand Down
32 changes: 32 additions & 0 deletions spec/source/source_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
require_relative '../spec_helper'
require 'oxidized/source/source'

describe Oxidized::Source do
describe '#map_model' do
before(:each) do
Asetus.any_instance.expects(:load)
Asetus.any_instance.expects(:create).returns(false)

# Set :home_dir to make sure the OXIDIZED_HOME environment variable is not used
Oxidized::Config.load({ home_dir: '/cfg_path/' })
yaml = %(
juniper: junos
!ruby/regexp /procurve/: procurve
)
Oxidized.config.model_map = YAML.unsafe_load(yaml)
@source = Oxidized::Source::Source.new
end

it 'returns map value for existing string key' do
_(@source.map_model('juniper')).must_equal 'junos'
end

it 'returns its argument for non-existing string key' do
_(@source.map_model('ios')).must_equal 'ios'
end

it 'returns map value for existing regexp key' do
_(@source.map_model('foo procurve1234 bar')).must_equal 'procurve'
end
end
end

0 comments on commit c7f0bdc

Please sign in to comment.