Skip to content
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

(NETDEV-29) Enhance ntp_config and ntp_server #542

Merged
merged 1 commit into from
May 4, 2017
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
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,38 @@ Changelog
* Extend interface_channel_group with attributes:
* `channel_group_mode`

* Extend ntp_config with attributes:
* `authenticate`
* `trusted_key`

* Extend ntp_server with attributes:
* `key`
* `maxpoll`
* `minpoll`
* `source_interface`
* `vrf`

* Added ntp_auth_key with attributes:
* `algorithm`
* `key`
* `mode`
* `password`

* Extend upgrade with attributes:
* `package`

### Changed
* ntp_server initialize now uses options hash
* Prior to this release ntp_server accepted positional arguments for id and
prefer. New behavior is to pass attributes as a hash.

Example:
```
options = { 'name' => id, 'key' => '999', 'prefer' => 'true',
'minpoll' => '5', 'maxpoll' => '8', 'vrf' => 'red' }
Cisco::NtpServer.new(options, true)
```

* Modified upgrade to support additional URI

* Modified upgrade attribute to drop version check
Expand Down
10 changes: 10 additions & 0 deletions lib/cisco_node_utils/cmd_ref/ntp_auth_key.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# ntp_auth_key
---
key:
multiple: true
default_value: []
nexus:
get_command: "show running-config all | include 'ntp authentication-key'"
# Returns <key>, <algorithm>, <password>, <mode>
get_value: '/^ntp authentication-key (\d+) (\w+) (\S+) (\d)/'
set_value: '<state> ntp authentication-key <key> <algorithm> <password> <mode>'
13 changes: 13 additions & 0 deletions lib/cisco_node_utils/cmd_ref/ntp_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
_template:
get_command: "show running-config ntp"

authenticate:
kind: boolean
default_value: false
nexus:
get_value: '/^ntp authenticate$/'
set_value: "<state> ntp authenticate"

source_interface:
default_value: ~
nexus:
Expand All @@ -12,3 +19,9 @@ source_interface:
context: ["ntp"]
get_value: '/source\s+(.*)$/'
set_value: '<state> source <source_interface>'

trusted_key:
multiple:
nexus:
get_value: '/^ntp trusted-key\s+(\d+)$/'
set_value: "<state> ntp trusted-key <key>"
12 changes: 10 additions & 2 deletions lib/cisco_node_utils/cmd_ref/ntp_server.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ _template:
context: ["ntp"]
get_command: "show running-config ntp"

key:
multiple: true
default_value: []
nexus:
get_command: "show running-config all | include 'ntp server(.*)(key)'"
get_value: '/ntp server (\S+)/'

prefer:
multiple: true
default_value: []
Expand All @@ -19,8 +26,9 @@ server:
default_value: []
nexus:
get_command: "show running-config all | include 'ntp server'"
get_value: '/ntp server (\S+)/'
set_value: '<state> ntp server <ip> <prefer>'
# Returns <ip>, <prefer>, <vrf>, <key>, <minpoll>, <maxpoll>
get_value: '/^(?:ntp server )([^\s]+) (prefer )?(?:(?:use-vrf )([^\s]+))?(?:(?: key )(\d+))?(?:(?: minpoll )(\d+))?(?:(?: maxpoll )(\d+))?/'
set_value: '<state> ntp server <ip> <prefer> <vrf> <key> <minpoll> <maxpoll>'
ios_xr:
get_value: '/server (?:ipv6 )?(\S+)/'
set_value: '<state> server <ip> <prefer>'
67 changes: 67 additions & 0 deletions lib/cisco_node_utils/ntp_auth_key.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# NTP Authentication key provider class
#
# Rick Sherman et al., April 2017
#
# Copyright (c) 2014-2017 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.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require_relative 'node'

module Cisco
# NtpAuthKey - node utility class for NTP authentication-key management
class NtpAuthKey < NodeUtil
attr_reader :algorithm, :mode, :password

def initialize(opts, instantiate=true)
@algorithm = opts['algorithm'].nil? ? 'md5' : opts['algorithm']
@key = opts['name']
@mode = opts['mode'].nil? ? '7' : opts['mode']
@password = opts['password']

create if instantiate
end

def self.ntpkeys
keys = %w(name algorithm password mode)
hash = {}
ntp_auth_key_list = config_get('ntp_auth_key', 'key')
return hash if ntp_auth_key_list.empty?

ntp_auth_key_list.each do |id|
hash[id[0]] = NtpAuthKey.new(Hash[keys.zip(id)], false)
end

hash
end

def ==(other)
name == other.name
end

def create
config_set('ntp_auth_key', 'key', state: '', key: @key,
algorithm: @algorithm, password: @password, mode: @mode)
end

def destroy
# There appears to be a bug in NXOS that requires the password be passed
config_set('ntp_auth_key', 'key', state: 'no', key: @key,
algorithm: @algorithm, password: @password, mode: @mode)
end

def name
@key
end
end # class
end # module
20 changes: 19 additions & 1 deletion lib/cisco_node_utils/ntp_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#
# Jonathan Tripathy et al., September 2015
#
# Copyright (c) 2014-2016 Cisco and/or its affiliates.
# Copyright (c) 2014-2017 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 @@ -41,6 +41,24 @@ def ==(other)
name == other.name
end

def authenticate
config_get('ntp_config', 'authenticate')
end

def authenticate=(enable)
state = (enable ? '' : 'no')
config_set('ntp_config', 'authenticate', state: state)
end

def trusted_key
config_get('ntp_config', 'trusted_key')
end

def trusted_key_set(state, key)
state = (state ? '' : 'no')
config_set('ntp_config', 'trusted_key', state: state, key: key)
end

def source_interface
source_interface = config_get('ntp_config', 'source_interface')
source_interface = source_interface.downcase \
Expand Down
55 changes: 28 additions & 27 deletions lib/cisco_node_utils/ntp_server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#
# Jonathan Tripathy et al., September 2015
#
# Copyright (c) 2014-2016 Cisco and/or its affiliates.
# Copyright (c) 2014-2017 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 All @@ -18,43 +18,43 @@

require_relative 'node'
require_relative 'interface'
require 'resolv'

module Cisco
# NtpServer - node utility class for NTP Server configuration management
class NtpServer < NodeUtil
def initialize(ntpserver_id, prefer, instantiate=true)
@ntpserver_id = ntpserver_id.to_s
@ntpserver_prefer = prefer
attr_reader :key, :maxpoll, :minpoll, :prefer, :vrf

unless @ntpserver_id =~ /^[a-zA-Z0-9\.\:]*$/
fail ArgumentError,
'Invalid value (IPv4/IPv6 address contains invalid characters)'
end
def initialize(opts, instantiate=true)
@ntpserver_id = opts['name']
@key = opts['key']
@minpoll = opts['minpoll']
@maxpoll = opts['maxpoll']
@prefer = opts['prefer'].nil? ? false : true
@vrf = opts['vrf'].nil? ? 'default' : opts['vrf']

begin
IPAddr.new(@ntpserver_id)
rescue
raise ArgumentError,
'Invalid value (Name is not a valid single IPv4/IPv6 address)'
end
hostname_regex = /^(?=.{1,255}$)[0-9A-Za-z]
(?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?
(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\.?$/x

unless @ntpserver_prefer == true ||
@ntpserver_prefer == false ||
@ntpserver_prefer.nil?
fail ArgumentError, 'Invalid value(prefer must be true or false)'
unless @ntpserver_id =~ Resolv::AddressRegex ||
@ntpserver_id =~ hostname_regex
fail ArgumentError,
"Invalid value '#{@ntpserver_id}' \
(Must be valid IPv4/IPv6 address or hostname)"
end

create if instantiate
end

def self.ntpservers
keys = %w(name prefer vrf key minpoll maxpoll)
hash = {}
ntpservers_list = config_get('ntp_server', 'server')
return hash if ntpservers_list.empty?

preferred_servers = config_get('ntp_server', 'prefer')

ntpservers_list.each do |id|
hash[id] = NtpServer.new(id, preferred_servers.include?(id), false)
hash[id[0]] = NtpServer.new(Hash[keys.zip(id)], false)
end

hash
Expand All @@ -66,20 +66,21 @@ def ==(other)

def create
config_set('ntp_server', 'server', state: '', ip: @ntpserver_id,
prefer: @ntpserver_prefer ? 'prefer' : '')
prefer: (['true', true].include? @prefer) ? 'prefer' : '',
vrf: @vrf ? "use-vrf #{@vrf}" : '',
key: @key ? "key #{@key}" : '',
minpoll: @minpoll ? "minpoll #{@minpoll}" : '',
maxpoll: @maxpoll ? "maxpoll #{@maxpoll}" : '')
end

def destroy
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe you may be able to simplify the destroy method and only specify the @ntpserver_id. I did some quick testing and I was able to remove the config without specifying any of the other parameters.

config_set('ntp_server', state: 'no', ip: @ntpserver_id)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I get an exception without it

No value specified for 'prefer' in 'no ntp server 2.2.2.2 <prefer> <vrf> <key> <minpoll> <maxpoll>'

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, that's because the other properties need to get passed in as empty string. I suppose this is fine.

config_set('ntp_server', 'server',
state: 'no', ip: @ntpserver_id, prefer: '')
state: 'no', ip: @ntpserver_id, prefer: '', vrf: '',
key: '', minpoll: '', maxpoll: '')
end

def name
@ntpserver_id
end

def prefer
@ntpserver_prefer
end
end # class
end # module
77 changes: 77 additions & 0 deletions tests/test_ntp_auth_key.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#
# Minitest for NtpAuthKey class
#
# Copyright (c) 2014-2017 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.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require_relative 'ciscotest'
require_relative '../lib/cisco_node_utils/ntp_auth_key'

# TestNtpAuthKey - Minitest for NtpAuthKey node utility.
class TestNtpAuthKey < CiscoTestCase
def setup
# setup runs at the beginning of each test
super
no_ntpkey
end

def teardown
# teardown runs at the end of each test
no_ntpkey
super
end

def no_ntpkey
# Turn the feature off for a clean test.
config('no ntp authentication-key 111 md5 test 7',
'no ntp authentication-key 999 md5 test 7')
end

# TESTS

def test_create_defaults
id = '111'
options = { 'name' => id, 'password' => 'test' }
refute_includes(Cisco::NtpAuthKey.ntpkeys, id)

key = Cisco::NtpAuthKey.new(options, true)
assert_includes(Cisco::NtpAuthKey.ntpkeys, id)
assert_equal(key, Cisco::NtpAuthKey.ntpkeys[id])

assert_equal(id, Cisco::NtpAuthKey.ntpkeys[id].name)
assert_equal('md5', Cisco::NtpAuthKey.ntpkeys[id].algorithm)
assert_equal('7', Cisco::NtpAuthKey.ntpkeys[id].mode)

key.destroy
refute_includes(Cisco::NtpAuthKey.ntpkeys, id)
end

def test_create_options
id = '999'
options = { 'name' => id, 'password' => 'test', 'algorithm' => 'md5',
'mode' => '7' }
refute_includes(Cisco::NtpAuthKey.ntpkeys, id)

key = Cisco::NtpAuthKey.new(options, true)
assert_includes(Cisco::NtpAuthKey.ntpkeys, id)
assert_equal(key, Cisco::NtpAuthKey.ntpkeys[id])

assert_equal(id, Cisco::NtpAuthKey.ntpkeys[id].name)
assert_equal('md5', Cisco::NtpAuthKey.ntpkeys[id].algorithm)
assert_equal('7', Cisco::NtpAuthKey.ntpkeys[id].mode)

key.destroy
refute_includes(Cisco::NtpAuthKey.ntpkeys, id)
end
end
Loading