Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ Changelog
* `facility`
* Extend interface with attributes:
* `ipv6_redirects`
* Added ability to specify environment at run time

Example:
```ruby
env = { host: '192.168.1.1', port: nil, username: 'admin', password: 'admin123', cookie: nil }
Cisco::Environment.add_env('default', env)
```

### Changed

Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@ An example configuration file (illustrating each of the above scenarios) is prov

*For security purposes, it is highly recommended that access to this file be restricted to only the owning user (`chmod 0600`).*

Configuration may also be specified at runtime and can be used in the absence of configuration files or to override them.

Example:
```ruby
env = { host: '192.168.1.1', port: nil, username: 'admin', password: 'admin123', cookie: nil }
Cisco::Environment.add_env('default', env)
```

## <a name="documentation">Documentation</a>

### Client
Expand Down Expand Up @@ -151,12 +159,18 @@ client2 = Cisco::Client.create('n9k')
# Warning: Make sure to exclude devices using the 'no_proxy' environment variable
# to ensure successful remote connections.

# Add runtime configuration for remote device and connect
env = { host: '192.168.1.1', port: nil, username: 'admin', password: 'admin123', cookie: nil }
Cisco::Environment.add_env('remote', env)
client3 = Cisco::Client.create('remote')

# Use connections to get and set device state.
client1.set(values: 'feature vtp')
client1.set(values: 'vtp domain mycompany.com')
puts client1.get(command: 'show vtp status | inc Domain')

puts client2.get(command: 'show version')
puts client3.get(command: 'show version')
```

#### High-level Node API
Expand Down
2 changes: 1 addition & 1 deletion ext/mkrf_conf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
os == 'ios_xr' || deps << Gem::Dependency.new('net_http_unix',
'~> 0.2', '>= 0.2.1')
# NX-OS doesn't need gRPC
os == 'nexus' || deps << Gem::Dependency.new('grpc', '~> 0.12')
os == 'nexus' || deps << Gem::Dependency.new('grpc', '~> 1.14.1')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you testing XR in your environment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are not testing / using this code w/ XR at all (to my knowledge)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok.. just wondering why the version bump? We have considered removing support for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When using Puppet Device it installs both gems. This is basically a temporary fix to unblock agentless. I agree we should probably remove the gRPC / XR stuff in the future.


deps.each do |dep|
installed = dep.matching_specs
Expand Down
9 changes: 8 additions & 1 deletion lib/cisco_node_utils/environment.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# August 2018
# March 2016, Glenn F. Matthews
#
# Copyright (c) 2016 Cisco and/or its affiliates.
# Copyright (c) 2016-2018 Cisco and/or its affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -90,6 +91,12 @@ def self.data_from_file(path)
{}
end

def self.add_env(env_name, env_hash)
fail ArgumentError, 'empty environment name' if env_name.empty?
fail TypeError, 'invalid environment hash' unless env_hash.is_a?(Hash)
@environments[env_name] = env_hash
end

def self.strings_to_symbols(hash)
Hash[hash.map { |k, v| [k.to_sym, v] }]
end
Expand Down
107 changes: 107 additions & 0 deletions spec/environment_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,37 @@ class << Cisco::Environment
end
end

describe '.add_env' do
it 'rejects empty environment name' do
expect { described_class.add_env('', {}) }.to \
raise_error(ArgumentError, 'empty environment name')
end

it 'rejects incorrectly typed environment hash' do
expect { described_class.add_env('default', 'hash') }.to \
raise_error(TypeError, 'invalid environment hash')
end

context 'environment can be loaded by funcion' do
expected = {
host: '192.168.1.1',
port: nil,
username: 'admin',
password: 'admin',
cookie: nil,
}
it 'can be loaded explicitly by name' do
described_class.add_env('test', expected)
expect(Cisco::Environment.environment('test')).to eq(expected)
end

it 'can be default' do
described_class.add_env('default', expected)
expect(Cisco::Environment.environment).to eq(expected)
end
end
end

describe '.environments' do
before(:each) do
allow(Cisco::Environment).to receive(:data_from_file).and_return({})
Expand Down Expand Up @@ -162,6 +193,82 @@ class << Cisco::Environment
},
)
end

it 'loaded file can be overridden by add_env' do
expect(Cisco::Environment).to receive(:data_from_file).with(
'/etc/cisco_node_utils.yaml').and_return(global_config)
expect(Cisco::Environment).to receive(:data_from_file).with(
'~/cisco_node_utils.yaml').and_return(user_config)
expect(Cisco::Environment.environments).to eq(
'default' => {
host: '127.0.0.1', # global config
port: 57_799, # user overrides global
username: 'user', # user config
password: nil, # auto-populated with nil
cookie: nil,
},
'global' => { # global config
host: nil,
port: nil,
username: 'global',
password: 'global',
cookie: nil,
},
'user' => { # user config
host: nil,
port: nil,
username: 'user',
password: 'user',
cookie: nil,
},
)
added_env = {
host: '192.168.1.1',
port: nil,
username: 'admin',
password: 'admin',
cookie: nil,
}
overide_defult = {
host: '192.168.2.2',
port: nil,
username: 'overridden',
password: 'overridden',
cookie: nil,
}
described_class.add_env('added', added_env)
described_class.add_env('default', overide_defult)
expect(Cisco::Environment.environments).to eq(
'added' => { # added by method
host: '192.168.1.1',
port: nil,
username: 'admin',
password: 'admin',
cookie: nil,
},
'default' => {
host: '192.168.2.2', # method overrides files
port: nil, # method overrides files
username: 'overridden', # method overrides files
password: 'overridden', # method overrides files
cookie: nil, # auto-popuplated with nil
},
'global' => { # global config
host: nil,
port: nil,
username: 'global',
password: 'global',
cookie: nil,
},
'user' => { # user config
host: nil,
port: nil,
username: 'user',
password: 'user',
cookie: nil,
},
)
end
end

context '.environment' do
Expand Down