cisco_node_utils 1.10.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -0
  3. data/CHANGELOG.md +25 -0
  4. data/lib/cisco_node_utils/bgp.rb +1 -1
  5. data/lib/cisco_node_utils/cisco_cmn_utils.rb +11 -3
  6. data/lib/cisco_node_utils/client/nxapi/client.rb +40 -6
  7. data/lib/cisco_node_utils/cmd_ref/acl.yaml +1 -1
  8. data/lib/cisco_node_utils/cmd_ref/banner.yaml +5 -1
  9. data/lib/cisco_node_utils/cmd_ref/feature.yaml +8 -1
  10. data/lib/cisco_node_utils/cmd_ref/interface_ospf.yaml +1 -1
  11. data/lib/cisco_node_utils/cmd_ref/interface_service_vni.yaml +5 -0
  12. data/lib/cisco_node_utils/cmd_ref/inventory.yaml +1 -1
  13. data/lib/cisco_node_utils/cmd_ref/ospf.yaml +7 -0
  14. data/lib/cisco_node_utils/cmd_ref/route_map.yaml +1 -1
  15. data/lib/cisco_node_utils/cmd_ref/vtp.yaml +1 -1
  16. data/lib/cisco_node_utils/cmd_ref/vxlan_vtep.yaml +30 -0
  17. data/lib/cisco_node_utils/cmd_ref/vxlan_vtep_vni.yaml +9 -2
  18. data/lib/cisco_node_utils/command_reference.rb +2 -2
  19. data/lib/cisco_node_utils/dhcp_relay_global.rb +1 -5
  20. data/lib/cisco_node_utils/feature.rb +30 -4
  21. data/lib/cisco_node_utils/interface.rb +3 -3
  22. data/lib/cisco_node_utils/interface_service_vni.rb +1 -1
  23. data/lib/cisco_node_utils/node.rb +11 -22
  24. data/lib/cisco_node_utils/node_util.rb +1 -1
  25. data/lib/cisco_node_utils/radius_global.rb +3 -3
  26. data/lib/cisco_node_utils/radius_server.rb +1 -2
  27. data/lib/cisco_node_utils/route_map.rb +1 -1
  28. data/lib/cisco_node_utils/router_ospf_vrf.rb +49 -5
  29. data/lib/cisco_node_utils/tacacs_global.rb +1 -2
  30. data/lib/cisco_node_utils/tacacs_server.rb +1 -2
  31. data/lib/cisco_node_utils/tacacs_server_host.rb +1 -2
  32. data/lib/cisco_node_utils/version.rb +1 -1
  33. data/lib/cisco_node_utils/vlan.rb +1 -1
  34. data/lib/cisco_node_utils/vxlan_vtep.rb +89 -4
  35. data/lib/cisco_node_utils/vxlan_vtep_vni.rb +32 -1
  36. data/spec/schema.yaml +2 -0
  37. data/tests/basetest.rb +40 -4
  38. data/tests/ciscotest.rb +15 -5
  39. data/tests/cmd_config.yaml +0 -2
  40. data/tests/test_acl.rb +1 -1
  41. data/tests/test_bgp_af.rb +6 -0
  42. data/tests/test_feature.rb +30 -4
  43. data/tests/test_interface.rb +5 -7
  44. data/tests/test_interface_ospf.rb +5 -1
  45. data/tests/test_interface_private_vlan.rb +18 -1
  46. data/tests/test_interface_svi.rb +1 -1
  47. data/tests/test_interface_switchport.rb +4 -7
  48. data/tests/test_node_ext.rb +1 -1
  49. data/tests/test_nxapi.rb +18 -8
  50. data/tests/test_radius_global.rb +3 -2
  51. data/tests/test_route_map.rb +2 -4
  52. data/tests/test_router_bgp.rb +10 -14
  53. data/tests/test_router_ospf_vrf.rb +61 -0
  54. data/tests/test_snmpserver.rb +1 -1
  55. data/tests/test_tacacs_global.rb +4 -2
  56. data/tests/test_upgrade.rb +1 -1
  57. data/tests/test_vrf.rb +2 -0
  58. data/tests/test_vrf_af.rb +2 -0
  59. data/tests/test_vtp.rb +6 -4
  60. data/tests/test_vxlan_vtep.rb +93 -1
  61. data/tests/test_vxlan_vtep_vni.rb +35 -1
  62. data/tests/yum_package.yaml +5 -0
  63. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: db160cf1dedda53f077ad5e3c246a7106be834ea
4
- data.tar.gz: 31eac56721204dbbf673355acaa1dd5591af3ed3
3
+ metadata.gz: 8500c855a9675c3c3ab5e581f06be1f67fb8074e
4
+ data.tar.gz: 0abf3dc4d719fa5282db36717571113f9ffdb617
5
5
  SHA512:
6
- metadata.gz: d6330230a4a619e0e497d5c79d5757bfe3141e53605550033fdcfcb9f4e8cfafd93e8aa2a457fd4989ff40c636001f6a070475736abf30c1cd72eb0a09126db5
7
- data.tar.gz: ac35c7431032dddce3c7fbc92c20028a6843fb25314e218925e1fa37610e6735e0a593e4aaa04ca2812182e20aa96a3d43205e436d5d2c655f850c828fddf78b
6
+ metadata.gz: 7ed3776cba64a9cbd4276a0c8034222a9d761f76f4a8b226e2af50fe8d1b1ac0c30d8cb698d1de1132e90435e7c20f6d05ea63216a379bb4da1913e5a6ee72b9
7
+ data.tar.gz: fc0a131d57d06626abdc777023b5a9637d15591997e8d88d05671f95a2efa8893b82c899fc4dc54e4f4407feac61befe7ba574a0c7438f3fe691cd1063605f60
@@ -7,6 +7,8 @@ rvm:
7
7
  - 2.2.2
8
8
  - 2.1.6
9
9
  - 2.0.0-p648 # specify non-clang version of ruby
10
+ before_install:
11
+ - gem install bundler -v '< 2'
10
12
 
11
13
  script:
12
14
  - bundle exec rake
@@ -1,6 +1,30 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ ## [v2.0.0]
5
+
6
+ ### New Cisco Resources
7
+
8
+ ### Added
9
+ * Extend nxapi client for https support
10
+ * `use_ssl` will be true when `transport` is `https`
11
+ * now makes use of `port` for custom nxapi ports
12
+ * Extend router_ospf_vrf with attribute:
13
+ * `redistribute`
14
+ * `reset_instance` method to node. Allows a single instance of nodeutils to reset the environment cache.
15
+ * Extend vxlan_vtep_vni with attribute:
16
+ * `suppress_arp_disable`
17
+ * Extend vxlan_vtep with attributes:
18
+ * `global_suppress_arp`
19
+ * `global_ingress_replication_bgp`
20
+ * `global_mcast_group_l2`
21
+ * `global_mcast_group_l3`
22
+
23
+ ### Removed
24
+ * Removed cache in `node_util.node`, which gave every inheriting class it's own cache.
25
+
26
+ ### Changed
27
+
4
28
  ## [v1.10.0]
5
29
 
6
30
  ### New Cisco Resources
@@ -587,6 +611,7 @@ Cisco::Environment.add_env('default', env)
587
611
  [git-flow]: https://github.com/petervanderdoes/gitflow-avh
588
612
  [SimpleCov]: https://github.com/colszowka/simplecov
589
613
 
614
+ [v2.0.0]: https://github.com/cisco/cisco-network-node-utils/compare/v1.10.0...v2.0.0
590
615
  [v1.10.0]: https://github.com/cisco/cisco-network-node-utils/compare/v1.9.0...v1.10.0
591
616
  [v1.9.0]: https://github.com/cisco/cisco-network-node-utils/compare/v1.8.0...v1.9.0
592
617
  [v1.8.0]: https://github.com/cisco/cisco-network-node-utils/compare/v1.7.0...v1.8.0
@@ -827,7 +827,7 @@ module Cisco
827
827
  # explicit values when removing the rd command. These restrictions are
828
828
  # not not needed in I3 and newer images.
829
829
  Feature.nv_overlay_evpn_enable if
830
- Utils.nexus_i2_image || node.product_id[/N7/]
830
+ Utils.nexus_i2_image || node.product_id[/N[567]/]
831
831
 
832
832
  if rd == default_route_distinguisher
833
833
  return if route_distinguisher.empty?
@@ -113,6 +113,14 @@ module Cisco
113
113
  return true if Platform.chassis['pid'][ver_regexp]
114
114
  end
115
115
 
116
+ def self.fretta?
117
+ require_relative 'platform'
118
+ Platform.slots.each do |_x, row|
119
+ return true if row['pid'][/-R/]
120
+ end
121
+ false
122
+ end
123
+
116
124
  # Helper utility method for ip/prefix format networks.
117
125
  # For ip/prefix format '1.1.1.1/24' or '2000:123:38::34/64',
118
126
  # we need to mask the address using the prefix length so that they
@@ -362,9 +370,9 @@ module Cisco
362
370
  end # merge_range
363
371
 
364
372
  def self.add_quotes(value)
365
- return value if image_version?(/7.3/)
366
- value = "\"#{value}\"" unless
367
- value.start_with?('"') && value.end_with?('"')
373
+ return value if image_version?(/7.3.[0-1]/) || value.nil?
374
+ value = "'#{value}'" unless
375
+ value.start_with?('"', "'") && value.end_with?('"', "'")
368
376
  value
369
377
  end # add_quotes
370
378
 
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # November 2014, Glenn F. Matthews
4
4
  #
5
- # Copyright (c) 2014-2016 Cisco and/or its affiliates.
5
+ # Copyright (c) 2014-2019 Cisco and/or its affiliates.
6
6
  #
7
7
  # Licensed under the Apache License, Version 2.0 (the "License");
8
8
  # you may not use this file except in compliance with the License.
@@ -60,7 +60,11 @@ class Cisco::Client::NXAPI < Cisco::Client
60
60
  else
61
61
  # Remote connection. This is primarily expected
62
62
  # when running e.g. from a Unix server as part of Minitest.
63
- @http = Net::HTTP.new(@host)
63
+ @transport = kwargs[:transport] || 'http'
64
+ @verify_mode = kwargs[:verify_mode] || 'none'
65
+ @port.nil? ? @port = '' : @port = ":#{@port}"
66
+ uri = URI.parse("#{@transport}://#{@host}#{@port}")
67
+ @http = Net::HTTP.new(uri.host, uri.port)
64
68
  end
65
69
  # The default read time out is 60 seconds, which may be too short for
66
70
  # scaled configuration to apply. Change it to 300 seconds, which is
@@ -205,14 +209,18 @@ class Cisco::Client::NXAPI < Cisco::Client
205
209
  request = build_http_request(type, command)
206
210
 
207
211
  # send the request and get the response
208
- debug("Sending HTTP request to NX-API at #{@http.address}:\n" \
212
+ debug("Sending #{@transport} request to NX-API at #{@http.address}:\n" \
209
213
  "#{request.to_hash}\n#{request.body}")
210
214
  read_timeout_check(request)
211
215
  tries = 2
212
216
  begin
213
- # Explicitly use http to avoid EOFError
214
- # http://stackoverflow.com/a/23080693
215
- @http.use_ssl = false
217
+ if @transport == 'https'
218
+ debug('Setting use_ssl to true')
219
+ @http.use_ssl = true
220
+ @http.verify_mode = handle_verify_mode(@verify_mode)
221
+ else
222
+ @http.use_ssl = false
223
+ end
216
224
  response = @http.request(request)
217
225
  rescue Errno::ECONNREFUSED, Errno::ECONNRESET
218
226
  emsg = 'Connection refused or reset. Is the NX-API feature enabled?'
@@ -268,6 +276,32 @@ class Cisco::Client::NXAPI < Cisco::Client
268
276
  end
269
277
  private :build_http_request
270
278
 
279
+ # Returns the OpenSSL verify mode based on the verify_mode arguments
280
+ #
281
+ # @raise if verify_mode param is not `peer`, `client-once`, `fail-no-peer`
282
+ # or `none`
283
+ #
284
+ # @param String verify mode to use
285
+ #
286
+ # @return OpenSSL::SSL verification mode
287
+ def handle_verify_mode(verify_mode)
288
+ case verify_mode
289
+ when 'peer'
290
+ OpenSSL::SSL::VERIFY_PEER
291
+ when 'client-once'
292
+ OpenSSL::SSL::VERIFY_CLIENT_ONCE
293
+ when 'fail-no-peer'
294
+ OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
295
+ when 'none'
296
+ OpenSSL::SSL::VERIFY_NONE
297
+ else
298
+ fail "#{verify_mode} is not a valid mode, " \
299
+ 'valid modes are: "none", "peer", ' \
300
+ '"client-once", "fail-no-peer"'
301
+ end
302
+ end
303
+ private :handle_verify_mode
304
+
271
305
  def handle_http_response(response)
272
306
  debug("HTTP Response: #{response.message}\n#{response.body}")
273
307
  case response
@@ -36,7 +36,7 @@ all_acls:
36
36
 
37
37
  fragments:
38
38
  # Note: The ACL 'fragments' keyword is independent of ACE 'fragments'
39
- _exclude: [N5k, N6k]
39
+ _exclude: [N5k, N6k, N3k-F, N9k-F]
40
40
  get_value: '/fragments (\S+)$/'
41
41
  set_value: '<state> fragments <action>'
42
42
  default_value: ~
@@ -1,7 +1,11 @@
1
1
  # banner
2
2
  ---
3
3
  motd:
4
- default_value: "User Access Verification\n"
4
+ N5k: &N6000
5
+ default_value: "Nexus 6000 Switch\n"
6
+ N6k: *N6000
7
+ else:
8
+ default_value: "User Access Verification\n"
5
9
  get_command: 'show banner motd'
6
10
  get_value: '/^.*$/m'
7
11
  set_value: '<state> banner motd <motd>'
@@ -31,8 +31,14 @@ fabric_forwarding:
31
31
  get_value: '/^feature fabric forwarding$/'
32
32
  set_value: "feature fabric forwarding"
33
33
 
34
+ fabricpath:
35
+ _exclude: [N3k, N3k-F, N9k-F, N9k]
36
+ get_command: "show feature-set"
37
+ get_value: '/^fabricpath[\s\d]+(\w+)/'
38
+ set_value: "<state> feature-set fabricpath"
39
+
34
40
  fex:
35
- _exclude: [C3064, C3132, N5k, N6k, N3k-F, N9k-F]
41
+ _exclude: [C3048, C3064, C3132, N5k, N6k, N3k-F, N9k-F]
36
42
  get_command: "show feature-set"
37
43
  get_value: '/^fex[\s\d]+(\w+)/'
38
44
  set_value: "<state> feature-set fex"
@@ -113,6 +119,7 @@ vni:
113
119
  set_value: 'feature vn-segment-vlan-based'
114
120
 
115
121
  vtp:
122
+ _exclude: [N3k-F, N9k-F]
116
123
  kind: boolean
117
124
  get_value: '/^feature vtp$/'
118
125
  set_value: "<state> feature vtp"
@@ -21,7 +21,7 @@ bfd:
21
21
  # no config at all so need to grab the optional
22
22
  # match to get the whole config for checking
23
23
  # the mode
24
- get_value: '/^\s*ip ospf bfd *(?:\S+)?$/'
24
+ get_value: '/^\s*ip ospf bfd *(?:\S*)$/'
25
25
  set_value: '%s ip ospf bfd %s'
26
26
  default_value: ~
27
27
 
@@ -11,6 +11,11 @@ _template:
11
11
  - 'interface <name>'
12
12
  - 'service instance <sid> vni'
13
13
 
14
+ all_interfaces:
15
+ multiple:
16
+ get_context: ~
17
+ get_value: '/^interface (.*)/'
18
+
14
19
  all_service_vni_ids:
15
20
  multiple:
16
21
  get_context:
@@ -41,5 +41,5 @@ versionid:
41
41
  nexus:
42
42
  get_value: ["name \"Chassis\"", "vendorid"]
43
43
  N5k: &vendorid5k
44
- get_value: ["name Chassis", "serialnum"]
44
+ get_value: ["name Chassis", "vendorid"]
45
45
  N6k: *vendorid5k
@@ -39,6 +39,13 @@ process_initialized:
39
39
  get_command: "show ip ospf stat"
40
40
  get_value: '/^No SAP is registered/' # Ospf is not initialized when seen
41
41
 
42
+ redistribute:
43
+ # no support yet for redistribute maximum-prefix
44
+ multiple: true
45
+ get_value: '/^redistribute (\S+ ?\S+?) route-map (\S+)$/'
46
+ set_value: '<state> redistribute <protocol> route-map <route_map>'
47
+ default_value: []
48
+
42
49
  router:
43
50
  multiple: true
44
51
  get_command: "show running ospf"
@@ -361,7 +361,7 @@ set_distance_local:
361
361
 
362
362
  # there is more than one space before delete on some platforms
363
363
  set_extcomm_list:
364
- get_value: '/^set extcomm-list (\S+)(?:\s+)? delete$/'
364
+ get_value: '/^set extcomm-list (\S+)\s+delete$/'
365
365
  set_value: "<state> set extcomm-list <list> delete"
366
366
  default_value: false
367
367
 
@@ -1,6 +1,6 @@
1
1
  # vtp
2
2
  ---
3
- _exclude: [ios_xr]
3
+ _exclude: [ios_xr, N3k-F, N9k-F]
4
4
 
5
5
  # VTP behaves differently across the various Nexus platforms and as a
6
6
  # result it's not currently possible to use a single 'show running'
@@ -12,6 +12,36 @@ all_interfaces:
12
12
  get_context: ~
13
13
  get_value: '/^interface (.*)$/'
14
14
 
15
+ global_ingress_replication_bgp:
16
+ _exclude: [N3k-F, N5k, N6k, N7k, N9k-F]
17
+ os_version: 'N9k:9.2'
18
+ kind: boolean
19
+ get_value: '/^global ingress-replication protocol bgp$/'
20
+ set_value: '<state> global ingress-replication protocol bgp'
21
+ default_value: false
22
+
23
+ global_mcast_group_l2:
24
+ _exclude: [N3k-F, N5k, N6k, N7k]
25
+ os_version: 'N9k, N9k-F:9.2'
26
+ get_value: '/^global mcast-group (\S+) L2$/'
27
+ set_value: '<state> global mcast-group <ip> L2'
28
+ default_value: ~
29
+
30
+ global_mcast_group_l3:
31
+ _exclude: [N3k-F, N5k, N6k, N7k, N9k-F]
32
+ os_version: 'N9k:9.2'
33
+ get_value: '/^global mcast-group (\S+) L3$/'
34
+ set_value: '<state> global mcast-group <ip> L3'
35
+ default_value: ~
36
+
37
+ global_suppress_arp:
38
+ _exclude: [N3k-F, N5k, N6k, N7k]
39
+ os_version: 'N9k, N9k-F:9.2'
40
+ kind: boolean
41
+ get_value: '/^global suppress-arp$/'
42
+ set_value: '<state> global suppress-arp'
43
+ default_value: false
44
+
15
45
  host_reachability:
16
46
  get_value: '/^host-reachability protocol (\S+)/'
17
47
  set_value: '<state> host-reachability protocol <proto>'
@@ -16,7 +16,7 @@ all_vnis:
16
16
  get_value: '/^member vni (\d+|\d+-\d+) ?(associate-vrf)?$/'
17
17
 
18
18
  ingress_replication:
19
- _exclude: [N5k, N6k, N7k]
19
+ _exclude: [N3k-F, N5k, N6k, N7k, N9k-F]
20
20
  kind: string
21
21
  get_value: '/^ingress-replication protocol (\S+)$/'
22
22
  set_value: '<state> ingress-replication protocol <protocol>'
@@ -35,7 +35,7 @@ multisite_ingress_replication:
35
35
  default_value: false
36
36
 
37
37
  peer_list:
38
- _exclude: [N5k, N6k, N7k]
38
+ _exclude: [N3k-F, N5k, N6k, N7k, N9k-F]
39
39
  multiple:
40
40
  get_context:
41
41
  - '/^interface <name>$/i'
@@ -55,6 +55,13 @@ suppress_arp:
55
55
  set_value: '<state> suppress-arp'
56
56
  default_value: false
57
57
 
58
+ suppress_arp_disable:
59
+ _exclude: [N3k-F, N5k, N6k, N7k]
60
+ os_version: 'N9k, N9k-F:9.2'
61
+ get_value: '/^suppress-arp disable$/'
62
+ set_value: '<state> suppress-arp disable'
63
+ default_value: ~
64
+
58
65
  suppress_uuc:
59
66
  _exclude: [N3k-F, N9k-F, N9k]
60
67
  os_version: 'N7k:8.1.1'
@@ -437,8 +437,8 @@ module Cisco
437
437
  puts "DEBUG: #{text}" if @@debug
438
438
  end
439
439
 
440
- KNOWN_PLATFORMS = %w(C3064 C3132 C3172 N35 N3k N3k-F N5k N6k N7k N9k N9k-F
441
- XRv9k)
440
+ KNOWN_PLATFORMS = %w(C3048 C3064 C3132 C3172 N35 N3k N3k-F N5k N6k N7k N9k
441
+ N9k-F XRv9k)
442
442
 
443
443
  def self.platform_to_filter(platform)
444
444
  if KNOWN_PLATFORMS.include?(platform)
@@ -172,7 +172,6 @@ module Cisco
172
172
 
173
173
  def ipv4_src_intf
174
174
  intf = config_get('dhcp_relay_global', 'ipv4_src_intf')
175
- # Normalize by downcasing and removing white space
176
175
  intf = intf.downcase.delete(' ') if intf
177
176
  intf
178
177
  end
@@ -207,10 +206,7 @@ module Cisco
207
206
  def ipv4_sub_option_circuit_id_string
208
207
  str = config_get('dhcp_relay_global', 'ipv4_sub_option_circuit_id_string')
209
208
  # Normalize by removing white space and add quotes
210
- if str
211
- str.strip!
212
- str = Utils.add_quotes(str)
213
- end
209
+ str.strip! if str.kind_of?(String)
214
210
  str
215
211
  end
216
212
 
@@ -80,6 +80,27 @@ module Cisco
80
80
  config_get('feature', 'fabric')
81
81
  end
82
82
 
83
+ # ---------------------------
84
+ def self.fabricpath_enable
85
+ # install feature-set and enable it
86
+ return if fabricpath_enabled?
87
+ config_set('feature', 'fabricpath', state: 'install') unless
88
+ fabricpath_installed?
89
+ config_set('feature', 'fabricpath', state: '')
90
+ end
91
+
92
+ def self.fabricpath_enabled?
93
+ config_get('feature', 'fabricpath') =~ /^enabled/
94
+ end
95
+
96
+ def self.fabricpath_installed?
97
+ config_get('feature', 'fabricpath') !~ /^uninstalled/
98
+ end
99
+
100
+ def self.fabricpath_supported?
101
+ config_get('feature', 'fabricpath')
102
+ end
103
+
83
104
  # ---------------------------
84
105
  def self.fabric_forwarding_enable
85
106
  return if fabric_forwarding_enabled?
@@ -183,7 +204,8 @@ module Cisco
183
204
  def self.nv_overlay_enable
184
205
  # Note: vdc platforms restrict this feature to F3 or newer linecards
185
206
  return if nv_overlay_enabled?
186
- config_set('feature', 'nv_overlay', state: '')
207
+ result = config_set('feature', 'nv_overlay', state: '')
208
+ cli_error_check(result)
187
209
  sleep 1
188
210
  end
189
211
 
@@ -311,14 +333,18 @@ module Cisco
311
333
  # instead just displays a STDOUT error message; thus NXAPI does not detect
312
334
  # the failure and we must catch it by inspecting the "body" hash entry
313
335
  # returned by NXAPI. This cli behavior is unlikely to change soon.
336
+ patterns = [
337
+ 'Hardware is not capable of supporting',
338
+ 'is unsupported on this node',
339
+ 'Feature NOT supported on this Platform',
340
+ ]
314
341
  fail result[2]['body'] if
315
342
  result[2].is_a?(Hash) &&
316
- /Hardware is not capable of supporting/.match(result[2]['body'].to_s)
343
+ result[2]['body'].to_s[Regexp.union(patterns)]
317
344
 
318
345
  # Some test environments get result as a string instead of a hash
319
346
  fail result if
320
- result.is_a?(String) &&
321
- /Hardware is not capable of supporting/.match(result)
347
+ result.is_a?(String) && result[Regexp.union(patterns)]
322
348
  end
323
349
 
324
350
  # ---------------------------