palo_alto 0.1.7 → 0.1.8
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.
- checksums.yaml +4 -4
- data/lib/palo_alto/version.rb +1 -1
- data/lib/palo_alto.rb +85 -73
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa30215e631895511ecb3645281eb160db2df58f0a6f6351d2d88069d80d1adc
|
4
|
+
data.tar.gz: e9acd3ba580ac92ec84546fc626ab52d9b7cfdd27591bb7b702082d3ddb1e791
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c556ea99594a4c09967e3271a0250d9864856ef42e8f89e518fe28b4054aeffc40160f5a1c298ebf5c77937c10d25a6bb5443eef64d0c03708bf9283c5647203
|
7
|
+
data.tar.gz: cc4a72eeea889757961e407712a9067cf54ee1fad39b394d3e29e230dbc8f306e9f53df2966ed576298135b9afb8496a77e4f372dd63c4d30a493653ca5b5136
|
data/lib/palo_alto/version.rb
CHANGED
data/lib/palo_alto.rb
CHANGED
@@ -71,13 +71,13 @@ module PaloAlto
|
|
71
71
|
|
72
72
|
class SessionTimedOutException < TemporaryException
|
73
73
|
end
|
74
|
-
|
74
|
+
|
75
75
|
module Helpers
|
76
76
|
class Rest
|
77
77
|
def self.make_request(opts)
|
78
|
-
options
|
79
|
-
options[:verify_ssl]
|
80
|
-
options[:timeout]
|
78
|
+
options = {}
|
79
|
+
options[:verify_ssl] = OpenSSL::SSL::VERIFY_PEER
|
80
|
+
options[:timeout] = 60
|
81
81
|
|
82
82
|
headers = {}
|
83
83
|
headers['User-Agent'] = 'ruby-keystone-client'
|
@@ -101,22 +101,23 @@ module PaloAlto
|
|
101
101
|
|
102
102
|
response = thread[:http].post('/api/', URI.encode_www_form(options[:payload]), options[:headers])
|
103
103
|
|
104
|
-
|
104
|
+
case response.code
|
105
|
+
when '200'
|
105
106
|
return response.body
|
106
|
-
|
107
|
+
when '400', '403'
|
107
108
|
begin
|
108
109
|
data = Nokogiri::XML.parse(response.body)
|
109
110
|
message = data.xpath('//response/response/msg').text
|
110
111
|
code = response.code.to_i
|
111
|
-
rescue
|
112
|
+
rescue StandardError
|
112
113
|
raise ConnectionErrorException, "#{response.code} #{response.message}"
|
113
114
|
end
|
114
115
|
raise_error(code, message)
|
115
116
|
else
|
116
117
|
raise ConnectionErrorException, "#{response.code} #{response.message}"
|
117
118
|
end
|
118
|
-
nil
|
119
119
|
|
120
|
+
nil
|
120
121
|
rescue Net::OpenTimeout, Errno::ECONNREFUSED => e
|
121
122
|
raise ConnectionErrorException, e.message
|
122
123
|
end
|
@@ -141,7 +142,7 @@ module PaloAlto
|
|
141
142
|
when 19..20 then SuccessException
|
142
143
|
when 22 then SessionTimedOutException
|
143
144
|
else InternalErrorException
|
144
|
-
|
145
|
+
end
|
145
146
|
raise error, message
|
146
147
|
end
|
147
148
|
|
@@ -155,36 +156,27 @@ module PaloAlto
|
|
155
156
|
options[:payload] = payload
|
156
157
|
options[:headers] = headers
|
157
158
|
|
158
|
-
if XML.debug.include?(:sent)
|
159
|
-
warn "sent: (#{Time.now}\n#{options.pretty_inspect}\n"
|
160
|
-
end
|
159
|
+
warn "sent: (#{Time.now}\n#{options.pretty_inspect}\n" if XML.debug.include?(:sent)
|
161
160
|
|
162
161
|
start_time = Time.now
|
163
162
|
text = Helpers::Rest.make_request(options)
|
164
163
|
if XML.debug.include?(:statistics)
|
165
|
-
warn "Elapsed for API call #{payload[:type]}/#{payload[:action]||'(unknown action)'}: #{Time.now-start_time} seconds"
|
164
|
+
warn "Elapsed for API call #{payload[:type]}/#{payload[:action] || '(unknown action)'}: #{Time.now - start_time} seconds"
|
166
165
|
end
|
167
166
|
|
168
|
-
if XML.debug.include?(:received)
|
169
|
-
warn "received: #{Time.now}\n#{text}\n"
|
170
|
-
end
|
167
|
+
warn "received: #{Time.now}\n#{text}\n" if XML.debug.include?(:received)
|
171
168
|
|
172
169
|
data = Nokogiri::XML.parse(text)
|
173
170
|
unless data.xpath('//response/@status').to_s == 'success'
|
174
|
-
if XML.debug.include?(:sent_on_error)
|
175
|
-
|
176
|
-
end
|
177
|
-
if XML.debug.include?(:received_on_error)
|
178
|
-
warn "received:\n#{text.inspect}\n"
|
179
|
-
end
|
171
|
+
warn "sent:\n#{options.inspect}\n" if XML.debug.include?(:sent_on_error)
|
172
|
+
warn "received:\n#{text.inspect}\n" if XML.debug.include?(:received_on_error)
|
180
173
|
code = data.at_xpath('//response/@code')&.value.to_i # sometimes there is no code :( e.g. for 'op' errors
|
181
174
|
message = data.xpath('/response/msg/line').map(&:text).map(&:strip).join("\n")
|
182
175
|
raise_error(code, message)
|
183
176
|
end
|
184
177
|
|
185
|
-
|
178
|
+
data
|
186
179
|
end
|
187
|
-
|
188
180
|
end
|
189
181
|
end
|
190
182
|
|
@@ -195,23 +187,21 @@ module PaloAlto
|
|
195
187
|
def execute(payload)
|
196
188
|
retried = false
|
197
189
|
begin
|
198
|
-
Helpers::Rest.execute(payload, headers: {'X-PAN-KEY':
|
190
|
+
Helpers::Rest.execute(payload, headers: { 'X-PAN-KEY': auth_key })
|
199
191
|
rescue TemporaryException => e
|
200
192
|
dont_continue_at = [
|
201
193
|
'Partial revert is not allowed. Full system commit must be completed.',
|
202
|
-
'Config for scope '
|
194
|
+
'Config for scope ',
|
195
|
+
'Config is not currently locked for scope ',
|
196
|
+
'Commit lock is not currently held by'
|
203
197
|
]
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
198
|
+
if retried || dont_continue_at.any? { |x| e.message.start_with?(x) }
|
199
|
+
raise e
|
200
|
+
else
|
201
|
+
warn "Got error #{e.inspect}; retrying" if XML.debug.include?(:warnings)
|
208
202
|
retried = true
|
209
|
-
if e.is_a?(SessionTimedOutException)
|
210
|
-
get_auth_key
|
211
|
-
end
|
203
|
+
get_auth_key if e.is_a?(SessionTimedOutException)
|
212
204
|
retry
|
213
|
-
else
|
214
|
-
raise e
|
215
205
|
end
|
216
206
|
end
|
217
207
|
end
|
@@ -225,7 +215,7 @@ module PaloAlto
|
|
225
215
|
else
|
226
216
|
{ commit: { partial: [
|
227
217
|
{ 'admin': [XML.username] },
|
228
|
-
device_groups ? {'device-group': device_groups } : nil,
|
218
|
+
device_groups ? { 'device-group': device_groups } : nil,
|
229
219
|
'no-template',
|
230
220
|
'no-template-stack',
|
231
221
|
'no-log-collector',
|
@@ -245,21 +235,21 @@ module PaloAlto
|
|
245
235
|
end
|
246
236
|
|
247
237
|
def full_commit_required?
|
248
|
-
result = Op.new.execute({check: 'full-commit-required'})
|
238
|
+
result = Op.new.execute({ check: 'full-commit-required' })
|
249
239
|
return true unless result.at_xpath('response/result').text == 'no'
|
250
240
|
|
251
241
|
false
|
252
242
|
end
|
253
243
|
|
254
244
|
def primary_active?
|
255
|
-
cmd = {show: {'high-availability': 'state'}}
|
245
|
+
cmd = { show: { 'high-availability': 'state' } }
|
256
246
|
state = Op.new.execute(cmd)
|
257
|
-
state.at_xpath(
|
247
|
+
state.at_xpath('response/result/local-info/state').text == 'primary-active'
|
258
248
|
end
|
259
249
|
|
260
250
|
# area: config, commit
|
261
251
|
def show_locks(area:)
|
262
|
-
cmd = {show: "#{area}-locks"}
|
252
|
+
cmd = { show: "#{area}-locks" }
|
263
253
|
ret = Op.new.execute(cmd)
|
264
254
|
ret.xpath("response/result/#{area}-locks/entry").map do |lock|
|
265
255
|
comment = lock.at_xpath('comment').inner_text
|
@@ -273,6 +263,18 @@ module PaloAlto
|
|
273
263
|
end
|
274
264
|
end
|
275
265
|
|
266
|
+
def execute_with_type(cmd, type:, location:)
|
267
|
+
if type == 'tpl'
|
268
|
+
run_with_template_scope(location) { Op.new.execute(cmd) }
|
269
|
+
elsif type == 'dg'
|
270
|
+
Op.new.execute(cmd, { vsys: location })
|
271
|
+
elsif !type || type == 'shared'
|
272
|
+
Op.new.execute(cmd)
|
273
|
+
else
|
274
|
+
raise(ArgumentError, "invalid type: #{type.inspect}")
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
276
278
|
# will execute block if given and unlock afterwards. returns false if lock could not be aquired
|
277
279
|
def lock(area:, comment: nil, type: nil, location: nil)
|
278
280
|
if block_given?
|
@@ -288,18 +290,22 @@ module PaloAlto
|
|
288
290
|
end
|
289
291
|
|
290
292
|
begin
|
291
|
-
cmd = {request: {"#{area}-lock": {add: {comment: comment || '(null)' }}}}
|
292
|
-
|
293
|
+
cmd = { request: { "#{area}-lock": { add: { comment: comment || '(null)' } } } }
|
294
|
+
execute_with_type(cmd, type: type, location: location)
|
293
295
|
true
|
294
296
|
rescue PaloAlto::InternalErrorException
|
295
297
|
false
|
296
298
|
end
|
297
299
|
end
|
298
300
|
|
299
|
-
def unlock(area:, type: nil, location: nil)
|
301
|
+
def unlock(area:, type: nil, location: nil, name: nil)
|
300
302
|
begin
|
301
|
-
cmd =
|
302
|
-
|
303
|
+
cmd = if name
|
304
|
+
{ request: { "#{area}-lock": { remove: { admin: name } } } }
|
305
|
+
else
|
306
|
+
{ request: { "#{area}-lock": 'remove' } }
|
307
|
+
end
|
308
|
+
execute_with_type(cmd, type: type, location: location)
|
303
309
|
rescue PaloAlto::InternalErrorException
|
304
310
|
return false
|
305
311
|
end
|
@@ -307,29 +313,48 @@ module PaloAlto
|
|
307
313
|
end
|
308
314
|
|
309
315
|
def remove_all_locks
|
310
|
-
%w
|
311
|
-
show_locks(area: area).each
|
312
|
-
unlock(area: area, type: lock[:type], location: lock[:location])
|
313
|
-
|
316
|
+
%w[config commit].each do |area|
|
317
|
+
show_locks(area: area).each do |lock|
|
318
|
+
unlock(area: area, type: lock[:type], location: lock[:location], name: area=='commit' ? lock[:name] : nil )
|
319
|
+
end
|
314
320
|
end
|
315
321
|
end
|
316
322
|
|
323
|
+
def run_with_template_scope(name)
|
324
|
+
if block_given?
|
325
|
+
run_with_template_scope(name)
|
326
|
+
begin
|
327
|
+
return yield
|
328
|
+
ensure
|
329
|
+
run_with_template_scope(nil)
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
cmd = if name
|
334
|
+
{ set: { system: { setting: { target: { template: { name: name } } } } } }
|
335
|
+
else
|
336
|
+
{ set: { system: { setting: { target: 'none' } } } }
|
337
|
+
end
|
338
|
+
|
339
|
+
Op.new.execute(cmd)
|
340
|
+
end
|
341
|
+
|
317
342
|
def check_for_changes(usernames: [XML.username])
|
318
|
-
result = Op.new.execute({show: {config: {list: {'change-summary': {partial: {admin: usernames}}}}}})
|
343
|
+
result = Op.new.execute({ show: { config: { list: { 'change-summary': { partial: { admin: usernames } } } } } })
|
319
344
|
result.xpath('response/result/summary/device-group/member').map(&:inner_text)
|
320
345
|
end
|
321
346
|
|
322
347
|
def wait_for_job_completion(job_id, wait: 5, timeout: 300)
|
323
|
-
cmd = {show: {jobs: {id: job_id}}}
|
348
|
+
cmd = { show: { jobs: { id: job_id } } }
|
324
349
|
start = Time.now
|
325
|
-
|
350
|
+
loop do
|
326
351
|
result = Op.new.execute(cmd)
|
327
|
-
unless result.at_xpath('response/result/job/status')&.text=='ACT'
|
328
|
-
|
329
|
-
end
|
352
|
+
return result unless result.at_xpath('response/result/job/status')&.text == 'ACT'
|
353
|
+
|
330
354
|
sleep wait
|
331
|
-
|
332
|
-
|
355
|
+
break unless start + timeout > Time.now
|
356
|
+
end
|
357
|
+
false
|
333
358
|
end
|
334
359
|
|
335
360
|
def revert!(all: false)
|
@@ -366,7 +391,7 @@ module PaloAlto
|
|
366
391
|
@arguments = [Expression.new(:this_node), []]
|
367
392
|
|
368
393
|
# attempt to obtain the auth_key
|
369
|
-
#raise 'Exception attempting to obtain the auth_key' if (self.class.auth_key = get_auth_key).nil?
|
394
|
+
# raise 'Exception attempting to obtain the auth_key' if (self.class.auth_key = get_auth_key).nil?
|
370
395
|
self.class.get_auth_key
|
371
396
|
|
372
397
|
self
|
@@ -374,27 +399,14 @@ module PaloAlto
|
|
374
399
|
|
375
400
|
# Perform a query to the API endpoint for an auth_key based on the credentials provided
|
376
401
|
def self.get_auth_key
|
377
|
-
|
378
402
|
# establish the required options for the key request
|
379
403
|
payload = { type: 'keygen',
|
380
|
-
user:
|
381
|
-
password:
|
404
|
+
user: username,
|
405
|
+
password: password }
|
382
406
|
|
383
407
|
# get and parse the response for the key
|
384
408
|
xml_data = Helpers::Rest.execute(payload)
|
385
409
|
self.auth_key = xml_data.xpath('//response/result/key')[0].content
|
386
410
|
end
|
387
|
-
|
388
|
-
private
|
389
|
-
|
390
|
-
# used to limit an op command to a specifc dg/template
|
391
|
-
def get_extra_argument(type:, location:)
|
392
|
-
case type
|
393
|
-
when 'dg' then {vsys: location}
|
394
|
-
when 'tpl' then raise
|
395
|
-
else {}
|
396
|
-
end
|
397
|
-
end
|
398
|
-
|
399
411
|
end
|
400
412
|
end
|
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.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sebastian Roesner
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-10-
|
11
|
+
date: 2021-10-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|