palo_alto 0.2.7 → 0.2.9

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.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PaloAlto
4
- VERSION = '0.2.7'
4
+ VERSION = '0.2.9'
5
5
  end
data/lib/palo_alto.rb CHANGED
@@ -74,30 +74,35 @@ module PaloAlto
74
74
 
75
75
  module Helpers
76
76
  class Rest
77
+ @http_clients = {} # will include [http_client, lock]
78
+ @global_lock = Mutex.new
79
+
77
80
  def self.make_request(opts)
78
81
  options = {}
79
- options[:verify_ssl] = OpenSSL::SSL::VERIFY_PEER
80
- options[:timeout] = 60
82
+ options[:verify_ssl] ||= OpenSSL::SSL::VERIFY_PEER
81
83
 
82
- headers = {}
83
- headers['User-Agent'] = 'ruby-keystone-client'
84
- headers['Accept'] = 'application/xml'
85
- headers['Content-Type'] = 'application/x-www-form-urlencoded'
84
+ headers = {
85
+ 'User-Agent': 'ruby-keystone-client',
86
+ 'Accept': 'application/xml',
87
+ 'Content-Type': 'application/x-www-form-urlencoded'
88
+ }
86
89
 
87
90
  # merge in settings from method caller
88
91
  options = options.merge(opts)
89
92
  options[:headers].merge!(headers)
90
93
 
91
- thread = Thread.current
92
- unless thread[:http]
93
- thread[:http] = Net::HTTP.new(options[:host], options[:port])
94
- thread[:http].use_ssl = true
95
- thread[:http].verify_mode = options[:verify_ssl]
96
- thread[:http].read_timeout = thread[:http].open_timeout = options[:timeout]
97
- thread[:http].set_debug_output($stdout) if options[:debug].include?(:http)
98
- end
94
+ http_client = lock = nil
99
95
 
100
- thread[:http].start unless thread[:http].started?
96
+ @global_lock.synchronize do
97
+ unless (http_client, lock = @http_clients[options[:host]])
98
+ http_client = Net::HTTP.new(options[:host], 443)
99
+ http_client.use_ssl = true
100
+ http_client.verify_mode = options[:verify_ssl]
101
+ http_client.read_timeout = http_client.open_timeout = (options[:timeout] || 60)
102
+ http_client.set_debug_output(options[:debug].include?(:http) ? $stdout : nil)
103
+ @http_clients[options[:host]] = [http_client, (lock = Mutex.new)]
104
+ end
105
+ end
101
106
 
102
107
  payload = options[:payload]
103
108
  post_req = Net::HTTP::Post.new('/api/', options[:headers])
@@ -109,7 +114,11 @@ module PaloAlto
109
114
  post_req.set_form_data(payload)
110
115
  end
111
116
 
112
- response = thread[:http].request(post_req)
117
+ response = lock.synchronize do
118
+ http_client.start unless http_client.started?
119
+
120
+ http_client.request(post_req)
121
+ end
113
122
 
114
123
  case response.code
115
124
  when '200'
@@ -159,7 +168,7 @@ module PaloAlto
159
168
  end
160
169
 
161
170
  class XML
162
- attr_accessor :host, :port, :username, :password, :auth_key, :verify_ssl, :debug
171
+ attr_accessor :host, :username, :password, :auth_key, :verify_ssl, :debug, :timeout
163
172
 
164
173
  def execute(payload)
165
174
  retried = false
@@ -167,10 +176,10 @@ module PaloAlto
167
176
  # configure options for the request
168
177
  options = {}
169
178
  options[:host] = host
170
- options[:port] = port
171
179
  options[:verify_ssl] = verify_ssl
172
180
  options[:payload] = payload
173
181
  options[:debug] = debug
182
+ options[:timeout] = timeout || 180
174
183
  options[:headers] = if payload[:type] == 'keygen'
175
184
  {}
176
185
  else
@@ -206,27 +215,25 @@ module PaloAlto
206
215
  'Commit lock is not currently held by',
207
216
  'You already own a config lock for scope '
208
217
  ]
209
- if retried || dont_retry_at.any? { |x| e.message.start_with?(x) }
210
- raise e
211
- else
212
- warn "Got error #{e.inspect}; retrying" if debug.include?(:warnings)
213
- retried = true
214
- get_auth_key if e.is_a?(SessionTimedOutException)
215
- retry
216
- end
218
+ raise e if retried || dont_retry_at.any? { |x| e.message.start_with?(x) }
219
+
220
+ warn "Got error #{e.inspect}; retrying" if debug.include?(:warnings)
221
+ retried = true
222
+ get_auth_key if e.is_a?(SessionTimedOutException)
223
+ retry
217
224
  end
218
225
  end
219
226
 
220
- def commit!(all: false, device_groups: nil, wait_for_completion: true)
221
- return nil if device_groups.is_a?(Array) && device_groups.empty?
227
+ def commit!(all: false, device_groups: nil, templates: nil, wait_for_completion: true, wait: 5, timeout: 480)
228
+ return nil if device_groups.is_a?(Array) && device_groups.empty? && templates.is_a?(Array) && templates.empty?
222
229
 
223
230
  cmd = if all
224
231
  'commit'
225
232
  else
226
233
  { commit: { partial: [
227
234
  { 'admin': [username] },
228
- device_groups ? { 'device-group': device_groups } : nil,
229
- 'no-template',
235
+ device_groups ? ( device_groups.empty? ? 'no-device-group' : { 'device-group': device_groups } ) : nil,
236
+ templates ? ( templates.empty? ? 'no-template' : { 'template': templates } ) : nil,
230
237
  'no-template-stack',
231
238
  'no-log-collector',
232
239
  'no-log-collector-group',
@@ -238,10 +245,11 @@ module PaloAlto
238
245
  end
239
246
  result = op.execute(cmd)
240
247
 
241
- return result unless wait_for_completion
242
-
243
248
  job_id = result.at_xpath('response/result/job')&.text
244
- wait_for_job_completion(job_id) if job_id
249
+
250
+ return result unless job_id && wait_for_completion
251
+
252
+ wait_for_job_completion(job_id, wait: wait, timeout: timeout) if job_id
245
253
  end
246
254
 
247
255
  def full_commit_required?
@@ -329,7 +337,7 @@ module PaloAlto
329
337
  }
330
338
  end
331
339
 
332
- def wait_for_job_completion(job_id, wait: 5, timeout: 300)
340
+ def wait_for_job_completion(job_id, wait: 5, timeout: 480)
333
341
  cmd = { show: { jobs: { id: job_id } } }
334
342
  start = Time.now
335
343
  loop do
@@ -343,7 +351,8 @@ module PaloAlto
343
351
  false
344
352
  end
345
353
 
346
- def revert!(all: false)
354
+ # wait: how long revert is retried (every 10 seconds)
355
+ def revert!(all: false, wait: 60)
347
356
  cmd = if all
348
357
  { revert: 'config' }
349
358
  else
@@ -359,16 +368,25 @@ module PaloAlto
359
368
  { 'shared-object': 'excluded' }
360
369
  ] } } }
361
370
  end
362
- op.execute(cmd)
371
+
372
+ waited = 0
373
+ begin
374
+ op.execute(cmd)
375
+ rescue StandardError => e
376
+ puts 'Revert failed; waiting and retrying'
377
+ sleep 10
378
+ waited += 1
379
+ retry while waited < wait
380
+ raise e
381
+ end
363
382
  end
364
383
 
365
- def initialize(host:, port:, username:, password:, debug: [])
366
- self.host = host
367
- self.port = port
368
- self.username = username
369
- self.password = password
370
- self.verify_ssl = OpenSSL::SSL::VERIFY_NONE
371
- self.debug = debug
384
+ def initialize(host:, username:, password:, verify_ssl: OpenSSL::SSL::VERIFY_NONE, debug: [])
385
+ self.host = host
386
+ self.username = username
387
+ self.password = password
388
+ self.verify_ssl = verify_ssl
389
+ self.debug = debug
372
390
 
373
391
  @subclasses = {}
374
392
 
@@ -377,7 +395,6 @@ module PaloAlto
377
395
  @arguments = [Expression.new(:this_node), []]
378
396
 
379
397
  # attempt to obtain the auth_key
380
- # raise 'Exception attempting to obtain the auth_key' if (self.class.auth_key = get_auth_key).nil?
381
398
  get_auth_key
382
399
  end
383
400
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: palo_alto
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.7
4
+ version: 0.2.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastian Roesner
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-01-19 00:00:00.000000000 Z
11
+ date: 2022-05-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri