palo_alto 0.1.3 → 0.1.7
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/config.rb +53 -36
- data/lib/palo_alto/version.rb +1 -1
- data/lib/palo_alto.rb +116 -4
- 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: f3f5565d4ace0fcd1e96290bcd2b5e2d1ffa726b53fd7fe691497f7a2c137d42
|
4
|
+
data.tar.gz: 9e8e63ab0508abf76cc5fdf13e6827067aa42100f6beb996ef16b1256dd96f5b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 59e3ee0f6f425554cf6dd10ac49310cdc4ebba3ec24ad9cf3914f7e5a6c465a386ccfe8cae77041691ddbc157c281c66aaee84b49f617057bcd750cd81e7c0e3
|
7
|
+
data.tar.gz: ad822a803c73d950cfdf0e428c41ee47b7fc3c3dd8b3fb631cecf2cf19c4b07e31d120fe0468cf25bed0ad250b859e7ee3d6ce7467a7c9adf7254a9697d7e1fa
|
data/lib/palo_alto/config.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# generated: 2021-
|
1
|
+
# generated: 2021-10-19 00:56:02 +0200
|
2
2
|
require 'openssl'
|
3
3
|
require 'nokogiri'
|
4
4
|
|
@@ -268,7 +268,11 @@ module PaloAlto
|
|
268
268
|
end
|
269
269
|
|
270
270
|
def binary_operator(name, left, right)
|
271
|
-
|
271
|
+
if %w(and or).include?(name)
|
272
|
+
"(#{left} #{name} #{right})".gsub('./@', '@')
|
273
|
+
else
|
274
|
+
"#{left}#{name}#{right}".gsub('./@', '@')
|
275
|
+
end
|
272
276
|
end
|
273
277
|
|
274
278
|
def root(current, element_names)
|
@@ -425,7 +429,7 @@ module PaloAlto
|
|
425
429
|
start_time=Time.now
|
426
430
|
result = self.parent_instance.dup.create!.clear!.external_set(data.xpath('//response/result').first)
|
427
431
|
if XML.debug.include?(:statistics)
|
428
|
-
|
432
|
+
warn "Elapsed for parsing #{result.length} results: #{Time.now-start_time} seconds"
|
429
433
|
end
|
430
434
|
result
|
431
435
|
end
|
@@ -436,7 +440,7 @@ module PaloAlto
|
|
436
440
|
self
|
437
441
|
end
|
438
442
|
|
439
|
-
def get(ignore_empty_result: false, xpath: self.to_xpath)
|
443
|
+
def get(ignore_empty_result: false, xpath: self.to_xpath, return_only: false)
|
440
444
|
if self.class.superclass == ArrayConfigClass && !@selector
|
441
445
|
raise(InvalidCommandException, "Please use 'get_all' here")
|
442
446
|
end
|
@@ -454,23 +458,28 @@ module PaloAlto
|
|
454
458
|
if ignore_empty_result==false
|
455
459
|
raise(ObjectNotPresentException, "empty result: #{payload.inspect}")
|
456
460
|
end
|
461
|
+
end
|
462
|
+
|
463
|
+
if return_only
|
464
|
+
data.xpath('//response/result/*')
|
457
465
|
else
|
458
|
-
#self.parent_instance.dup.create!.clear!.external_set(data.xpath('//response/result').first).first
|
459
466
|
@create_children=true
|
460
467
|
n = data.xpath('//response/result/*')
|
468
|
+
if n.any?
|
469
|
+
clear!
|
470
|
+
external_set(n.first)
|
461
471
|
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
472
|
+
if is_a?(ArrayConfigClass)
|
473
|
+
primary_key = get_primary_key(n.first.attribute_nodes, self.class.props)
|
474
|
+
set_array_class_attributes(n.first, primary_key) # primary key, api_attributes
|
475
|
+
end
|
476
|
+
end
|
477
|
+
self
|
478
|
+
end.tap do
|
479
|
+
if XML.debug.include?(:statistics)
|
480
|
+
warn "Elapsed for parsing: #{Time.now-start_time} seconds"
|
468
481
|
end
|
469
482
|
end
|
470
|
-
if XML.debug.include?(:statistics)
|
471
|
-
puts "Elapsed for parsing: #{Time.now-start_time} seconds"
|
472
|
-
end
|
473
|
-
self
|
474
483
|
end
|
475
484
|
|
476
485
|
def get_primary_key(attribute_nodes, props)
|
@@ -526,9 +535,9 @@ module PaloAlto
|
|
526
535
|
when 'bool'
|
527
536
|
return true if ['yes', true].include?(value)
|
528
537
|
return false if ['no', false].include?(value)
|
529
|
-
raise ArgumentError,
|
538
|
+
raise ArgumentError, "Not bool: #{value.inspect}"
|
530
539
|
when 'string', 'ipdiscontmask', 'iprangespec', 'ipspec', 'rangelistspec'
|
531
|
-
raise(ArgumentError,
|
540
|
+
raise(ArgumentError, "Not string: #{value.inspect}") unless value.is_a?(String)
|
532
541
|
if prop_arr['regex']
|
533
542
|
raise ArgumentError, "Not matching regex: #{value.inspect} (#{prop_arr["regex"].inspect})" unless value.match(prop_arr["regex"])
|
534
543
|
end
|
@@ -662,28 +671,34 @@ module PaloAlto
|
|
662
671
|
elsif @external_values.has_key?(prop)
|
663
672
|
return @external_values[prop]
|
664
673
|
elsif my_prop.has_key?("default") && include_defaults
|
665
|
-
return
|
674
|
+
return enforce_types(my_prop, my_prop['default'])
|
666
675
|
else
|
667
676
|
return nil
|
668
677
|
end
|
669
678
|
end
|
670
679
|
|
671
|
-
def
|
672
|
-
|
680
|
+
def enforce_types(prop_arr, values)
|
681
|
+
return if values.nil?
|
673
682
|
|
674
|
-
if has_multiple_values? &&
|
675
|
-
|
683
|
+
if has_multiple_values? && values.is_a?(String)
|
684
|
+
values = values.split(/\s+/)
|
676
685
|
end
|
677
686
|
|
678
|
-
if
|
679
|
-
|
680
|
-
elsif
|
681
|
-
|
687
|
+
if values.is_a?(Array) && has_multiple_values?
|
688
|
+
values.map{|v| enforce_type(prop_arr, v)}
|
689
|
+
elsif !has_multiple_values?
|
690
|
+
enforce_type(prop_arr, values)
|
682
691
|
else
|
683
|
-
|
692
|
+
raise(ArgumentError, 'Needs to be Array but is not, or vice versa')
|
684
693
|
end
|
685
694
|
end
|
686
695
|
|
696
|
+
def prop_set(prop, value)
|
697
|
+
my_prop = self.class.props[prop] or raise(InternalErrorException, "Unknown attribute for #{self.class}: #{prop}")
|
698
|
+
|
699
|
+
@values[prop] = enforce_types(my_prop, value)
|
700
|
+
end
|
701
|
+
|
687
702
|
def to_xml(changed_only:, full_tree:, include_root: )
|
688
703
|
builder = Nokogiri::XML::Builder.new{|xml|
|
689
704
|
xml.send(self._section, (self.selector rescue nil)) {
|
@@ -768,23 +783,25 @@ module PaloAlto
|
|
768
783
|
|
769
784
|
def set_xpath_from_selector(selector: @selector)
|
770
785
|
xpath = self.parent_instance.child(_section)
|
771
|
-
k,v=selector.first
|
786
|
+
k, v = selector.first
|
772
787
|
obj = xpath.where(PaloAlto.xpath_attr(k.to_sym) == v)
|
773
788
|
|
774
789
|
@expression = obj.expression
|
775
790
|
@arguments = obj.arguments
|
776
791
|
end
|
777
792
|
|
778
|
-
def rename!(new_name)
|
793
|
+
def rename!(new_name, internal_only: false)
|
779
794
|
# https://docs.paloaltonetworks.com/pan-os/10-1/pan-os-panorama-api/pan-os-xml-api-request-types/configuration-api/rename-configuration.html
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
795
|
+
unless internal_only
|
796
|
+
payload = {
|
797
|
+
type: 'config',
|
798
|
+
action: 'rename',
|
799
|
+
xpath: self.to_xpath,
|
800
|
+
newname: new_name
|
801
|
+
}
|
786
802
|
|
787
|
-
|
803
|
+
result = XML.execute(payload)
|
804
|
+
end
|
788
805
|
|
789
806
|
# now update also the internal value to the new name
|
790
807
|
self.selector.transform_values!{new_name}
|
data/lib/palo_alto/version.rb
CHANGED
data/lib/palo_alto.rb
CHANGED
@@ -197,7 +197,11 @@ module PaloAlto
|
|
197
197
|
begin
|
198
198
|
Helpers::Rest.execute(payload, headers: {'X-PAN-KEY': self.auth_key})
|
199
199
|
rescue TemporaryException => e
|
200
|
-
|
200
|
+
dont_continue_at = [
|
201
|
+
'Partial revert is not allowed. Full system commit must be completed.',
|
202
|
+
'Config for scope '
|
203
|
+
]
|
204
|
+
unless retried || dont_continue_at.any? { |x| e.message.start_with?(x) }
|
201
205
|
if XML.debug.include?(:warnings)
|
202
206
|
warn "Got error #{e.inspect}; retrying"
|
203
207
|
end
|
@@ -213,12 +217,15 @@ module PaloAlto
|
|
213
217
|
end
|
214
218
|
end
|
215
219
|
|
216
|
-
def commit!(all: false)
|
220
|
+
def commit!(all: false, device_groups: nil, wait_for_completion: true)
|
221
|
+
return nil if device_groups.is_a?(Array) && device_groups.empty?
|
222
|
+
|
217
223
|
op = if all
|
218
224
|
'commit'
|
219
225
|
else
|
220
226
|
{ commit: { partial: [
|
221
227
|
{ 'admin': [XML.username] },
|
228
|
+
device_groups ? {'device-group': device_groups } : nil,
|
222
229
|
'no-template',
|
223
230
|
'no-template-stack',
|
224
231
|
'no-log-collector',
|
@@ -227,9 +234,102 @@ module PaloAlto
|
|
227
234
|
'no-wildfire-appliance-cluster',
|
228
235
|
{ 'device-and-network': 'excluded' },
|
229
236
|
{ 'shared-object': 'excluded' }
|
230
|
-
] } }
|
237
|
+
].compact } }
|
231
238
|
end
|
232
|
-
Op.new.execute(op)
|
239
|
+
Op.new.execute(op).tap do |result|
|
240
|
+
if wait_for_completion
|
241
|
+
job_id = result.at_xpath('response/result/job')&.text
|
242
|
+
wait_for_job_completion(job_id) if job_id
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def full_commit_required?
|
248
|
+
result = Op.new.execute({check: 'full-commit-required'})
|
249
|
+
return true unless result.at_xpath('response/result').text == 'no'
|
250
|
+
|
251
|
+
false
|
252
|
+
end
|
253
|
+
|
254
|
+
def primary_active?
|
255
|
+
cmd = {show: {'high-availability': 'state'}}
|
256
|
+
state = Op.new.execute(cmd)
|
257
|
+
state.at_xpath("response/result/local-info/state").text == "primary-active"
|
258
|
+
end
|
259
|
+
|
260
|
+
# area: config, commit
|
261
|
+
def show_locks(area:)
|
262
|
+
cmd = {show: "#{area}-locks"}
|
263
|
+
ret = Op.new.execute(cmd)
|
264
|
+
ret.xpath("response/result/#{area}-locks/entry").map do |lock|
|
265
|
+
comment = lock.at_xpath('comment').inner_text
|
266
|
+
location = lock.at_xpath('name').inner_text
|
267
|
+
{
|
268
|
+
name: lock.attribute('name').value,
|
269
|
+
location: location == 'shared' ? nil : location,
|
270
|
+
type: lock.at_xpath('type').inner_text,
|
271
|
+
comment: comment == '(null)' ? nil : comment
|
272
|
+
}
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
# will execute block if given and unlock afterwards. returns false if lock could not be aquired
|
277
|
+
def lock(area:, comment: nil, type: nil, location: nil)
|
278
|
+
if block_given?
|
279
|
+
if lock(area: area, comment: comment, type: type, location: location)
|
280
|
+
begin
|
281
|
+
return yield
|
282
|
+
ensure
|
283
|
+
unlock(area: area, type: type, location: location)
|
284
|
+
end
|
285
|
+
else
|
286
|
+
return false
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
begin
|
291
|
+
cmd = {request: {"#{area}-lock": {add: {comment: comment || '(null)' }}}}
|
292
|
+
Op.new.execute(cmd, get_extra_argument(type: type, location: location))
|
293
|
+
true
|
294
|
+
rescue PaloAlto::InternalErrorException
|
295
|
+
false
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def unlock(area:, type: nil, location: nil)
|
300
|
+
begin
|
301
|
+
cmd = {request: {"#{area}-lock": 'remove'}}
|
302
|
+
Op.new.execute(cmd, get_extra_argument(type: type, location: location))
|
303
|
+
rescue PaloAlto::InternalErrorException
|
304
|
+
return false
|
305
|
+
end
|
306
|
+
true
|
307
|
+
end
|
308
|
+
|
309
|
+
def remove_all_locks
|
310
|
+
%w(config commit).each do |area|
|
311
|
+
show_locks(area: area).each {|lock|
|
312
|
+
unlock(area: area, type: lock[:type], location: lock[:location])
|
313
|
+
}
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
def check_for_changes(usernames: [XML.username])
|
318
|
+
result = Op.new.execute({show: {config: {list: {'change-summary': {partial: {admin: usernames}}}}}})
|
319
|
+
result.xpath('response/result/summary/device-group/member').map(&:inner_text)
|
320
|
+
end
|
321
|
+
|
322
|
+
def wait_for_job_completion(job_id, wait: 5, timeout: 300)
|
323
|
+
cmd = {show: {jobs: {id: job_id}}}
|
324
|
+
start = Time.now
|
325
|
+
begin
|
326
|
+
result = Op.new.execute(cmd)
|
327
|
+
unless result.at_xpath('response/result/job/status')&.text=='ACT'
|
328
|
+
return result
|
329
|
+
end
|
330
|
+
sleep wait
|
331
|
+
end while start+timeout > Time.now
|
332
|
+
return false
|
233
333
|
end
|
234
334
|
|
235
335
|
def revert!(all: false)
|
@@ -284,5 +384,17 @@ module PaloAlto
|
|
284
384
|
xml_data = Helpers::Rest.execute(payload)
|
285
385
|
self.auth_key = xml_data.xpath('//response/result/key')[0].content
|
286
386
|
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
|
+
|
287
399
|
end
|
288
400
|
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.7
|
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-
|
11
|
+
date: 2021-10-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|