diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a9e70f6..6a2bdf12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ Changelog ### New Cisco Resources ### Added +* Extend nxapi client for https support + * `use_ssl` will be true when `transport` is `https` + * now makes use of `port` for custom nxapi ports * Extend router_ospf_vrf with attribute: * `redistribute` * `reset_instance` method to node. Allows a single instance of nodeutils to reset the environment cache. diff --git a/lib/cisco_node_utils/client/nxapi/client.rb b/lib/cisco_node_utils/client/nxapi/client.rb index b2a63957..1df28a55 100644 --- a/lib/cisco_node_utils/client/nxapi/client.rb +++ b/lib/cisco_node_utils/client/nxapi/client.rb @@ -2,7 +2,7 @@ # # November 2014, Glenn F. Matthews # -# Copyright (c) 2014-2016 Cisco and/or its affiliates. +# Copyright (c) 2014-2019 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. @@ -60,7 +60,11 @@ def initialize(**kwargs) else # Remote connection. This is primarily expected # when running e.g. from a Unix server as part of Minitest. - @http = Net::HTTP.new(@host) + @transport = kwargs[:transport] || 'http' + @verify_mode = kwargs[:verify_mode] || 'none' + @port.nil? ? @port = '' : @port = ":#{@port}" + uri = URI.parse("#{@transport}://#{@host}#{@port}") + @http = Net::HTTP.new(uri.host, uri.port) end # The default read time out is 60 seconds, which may be too short for # scaled configuration to apply. Change it to 300 seconds, which is @@ -205,14 +209,18 @@ def req(type, command_or_list) request = build_http_request(type, command) # send the request and get the response - debug("Sending HTTP request to NX-API at #{@http.address}:\n" \ + debug("Sending #{@transport} request to NX-API at #{@http.address}:\n" \ "#{request.to_hash}\n#{request.body}") read_timeout_check(request) tries = 2 begin - # Explicitly use http to avoid EOFError - # http://stackoverflow.com/a/23080693 - @http.use_ssl = false + if @transport == 'https' + debug('Setting use_ssl to true') + @http.use_ssl = true + @http.verify_mode = handle_verify_mode(@verify_mode) + else + @http.use_ssl = false + end response = @http.request(request) rescue Errno::ECONNREFUSED, Errno::ECONNRESET emsg = 'Connection refused or reset. Is the NX-API feature enabled?' @@ -268,6 +276,32 @@ def build_http_request(type, command_string) end private :build_http_request + # Returns the OpenSSL verify mode based on the verify_mode arguments + # + # @raise if verify_mode param is not `peer`, `client-once`, `fail-no-peer` + # or `none` + # + # @param String verify mode to use + # + # @return OpenSSL::SSL verification mode + def handle_verify_mode(verify_mode) + case verify_mode + when 'peer' + OpenSSL::SSL::VERIFY_PEER + when 'client-once' + OpenSSL::SSL::VERIFY_CLIENT_ONCE + when 'fail-no-peer' + OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT + when 'none' + OpenSSL::SSL::VERIFY_NONE + else + fail "#{verify_mode} is not a valid mode, " \ + 'valid modes are: "none", "peer", ' \ + '"client-once", "fail-no-peer"' + end + end + private :handle_verify_mode + def handle_http_response(response) debug("HTTP Response: #{response.message}\n#{response.body}") case response diff --git a/tests/basetest.rb b/tests/basetest.rb index 4a0a67af..bc29fa68 100644 --- a/tests/basetest.rb +++ b/tests/basetest.rb @@ -85,6 +85,38 @@ def password self.class.password end + def self.telnet_port + Cisco::Environment.environment[:telnet_port] || 23 + end + + def telnet_port + self.class.telnet_port + end + + def self.port + Cisco::Environment.environment[:port] || address.split(':')[1] + end + + def port + self.class.port + end + + def self.transport + Cisco::Environment.environment[:transport] || 'http' + end + + def transport + self.class.transport + end + + def self.verify_mode + Cisco::Environment.environment[:verify_mode] || 'none' + end + + def verify_mode + self.class.verify_mode + end + def setup # Hack - populate environment from user-entered values from basetest.rb if Cisco::Environment.environments.empty? @@ -92,13 +124,17 @@ class << Cisco::Environment attr_writer :environments end Cisco::Environment.environments['default'] = { - host: address.split(':')[0], - port: address.split(':')[1], - username: username, - password: password, + host: address.split(':')[0], + port: port, + telnet_port: telnet_port, + transport: transport, + verify_mode: verify_mode, + username: username, + password: password, } end @device = Net::Telnet.new('Host' => address.split(':')[0], + 'Port' => telnet_port, 'Timeout' => 240, # NX-OS has a space after '#', IOS XR does not 'Prompt' => /[$%#>] *\z/n,