palo_alto 0.1.7 → 0.2.1

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,816 +1,838 @@
1
- # generated: 2021-10-19 00:56:02 +0200
1
+ # generated: 2021-11-23 22:28:47 +0100
2
+ # frozen_string_literal: true
3
+
2
4
  require 'openssl'
3
5
  require 'nokogiri'
4
6
 
5
7
  module PaloAlto
8
+ # https://github.com/teamcapybara/xpath - MIT license
9
+ module DSL
10
+ def relative(*expressions)
11
+ Expression.new(:relative, current, expressions)
12
+ end
6
13
 
7
- # https://github.com/teamcapybara/xpath - MIT license
8
- module DSL
9
- def relative(*expressions)
10
- Expression.new(:relative, current, expressions)
11
- end
14
+ def root(*expressions)
15
+ Expression.new(:root, current, expressions)
16
+ end
12
17
 
13
- def root(*expressions)
14
- Expression.new(:root, current, expressions)
15
- end
18
+ def current
19
+ Expression.new(:this_node)
20
+ end
16
21
 
17
- def current
18
- Expression.new(:this_node)
19
- end
22
+ def descendant(*expressions)
23
+ Expression.new(:descendant, current, expressions)
24
+ end
20
25
 
21
- def descendant(*expressions)
22
- Expression.new(:descendant, current, expressions)
23
- end
26
+ def child(*expressions)
27
+ Expression.new(:child, current, expressions)
28
+ end
24
29
 
25
- def child(*expressions)
26
- Expression.new(:child, current, expressions)
27
- end
30
+ def axis(name, *element_names)
31
+ Expression.new(:axis, current, name, element_names)
32
+ end
28
33
 
29
- def axis(name, *element_names)
30
- Expression.new(:axis, current, name, element_names)
31
- end
34
+ def anywhere(*expressions)
35
+ Expression.new(:anywhere, expressions)
36
+ end
32
37
 
33
- def anywhere(*expressions)
34
- Expression.new(:anywhere, expressions)
35
- end
38
+ def xpath_attr(expression)
39
+ Expression.new(:attribute, current, expression)
40
+ end
36
41
 
37
- def xpath_attr(expression)
38
- Expression.new(:attribute, current, expression)
39
- end
42
+ def text
43
+ Expression.new(:text, current)
44
+ end
40
45
 
41
- def text
42
- Expression.new(:text, current)
43
- end
46
+ def css(selector)
47
+ Expression.new(:css, current, Literal.new(selector))
48
+ end
44
49
 
45
- def css(selector)
46
- Expression.new(:css, current, Literal.new(selector))
47
- end
50
+ def function(name, *arguments)
51
+ Expression.new(:function, name, *arguments)
52
+ end
48
53
 
49
- def function(name, *arguments)
50
- Expression.new(:function, name, *arguments)
51
- end
54
+ def method(name, *arguments)
55
+ if name != :not
56
+ Expression.new(:function, name, current, *arguments)
57
+ else
58
+ Expression.new(:function, name, *arguments)
59
+ end
60
+ end
52
61
 
53
- def method(name, *arguments)
54
- if name!=:not
55
- Expression.new(:function, name, current, *arguments)
56
- else
57
- Expression.new(:function, name, *arguments)
58
- end
59
- end
62
+ def where(expression)
63
+ if expression
64
+ Expression.new(:where, current, expression)
65
+ else
66
+ current
67
+ end
68
+ end
69
+ # alias_method :[], :where
60
70
 
61
- def where(expression)
62
- if expression
63
- Expression.new(:where, current, expression)
64
- else
65
- current
66
- end
67
- end
68
- #alias_method :[], :where
71
+ def is(expression)
72
+ Expression.new(:is, current, expression)
73
+ end
69
74
 
70
- def is(expression)
71
- Expression.new(:is, current, expression)
72
- end
75
+ def binary_operator(name, rhs)
76
+ Expression.new(:binary_operator, name, current, rhs)
77
+ end
73
78
 
74
- def binary_operator(name, rhs)
75
- Expression.new(:binary_operator, name, current, rhs)
76
- end
79
+ def union(*expressions)
80
+ Union.new(*[self, expressions].flatten)
81
+ end
82
+ alias + union
77
83
 
78
- def union(*expressions)
79
- Union.new(*[self, expressions].flatten)
80
- end
81
- alias_method :+, :union
84
+ def last
85
+ function(:last)
86
+ end
82
87
 
83
- def last
84
- function(:last)
85
- end
88
+ def position
89
+ function(:position)
90
+ end
86
91
 
87
- def position
88
- function(:position)
89
- end
92
+ METHODS = [
93
+ # node set
94
+ :count, :id, :local_name, :namespace_uri,
95
+ # string
96
+ :string, :concat, :starts_with, :contains, :substring_before,
97
+ :substring_after, :substring, :string_length, :normalize_space,
98
+ :translate,
99
+ # boolean
100
+ :boolean, :not, :true, :false, :lang,
101
+ # number
102
+ :number, :sum, :floor, :ceiling, :round
103
+ ].freeze
90
104
 
91
- METHODS = [
92
- # node set
93
- :count, :id, :local_name, :namespace_uri,
94
- # string
95
- :string, :concat, :starts_with, :contains, :substring_before,
96
- :substring_after, :substring, :string_length, :normalize_space,
97
- :translate,
98
- # boolean
99
- :boolean, :not, :true, :false, :lang,
100
- # number
101
- :number, :sum, :floor, :ceiling, :round
102
- ].freeze
105
+ METHODS.each do |key|
106
+ name = key.to_s.tr('_', '-').to_sym
107
+ define_method key do |*args|
108
+ method(name, *args)
109
+ end
110
+ end
103
111
 
104
- METHODS.each do |key|
105
- name = key.to_s.tr('_', '-').to_sym
106
- define_method key do |*args|
107
- method(name, *args)
108
- end
109
- end
112
+ def qname
113
+ method(:name)
114
+ end
110
115
 
111
- def qname
112
- method(:name)
113
- end
116
+ alias inverse not
117
+ alias ~ not
118
+ alias ! not
119
+ alias normalize normalize_space
120
+ alias n normalize_space
114
121
 
115
- alias_method :inverse, :not
116
- alias_method :~, :not
117
- alias_method :!, :not
118
- alias_method :normalize, :normalize_space
119
- alias_method :n, :normalize_space
122
+ OPERATORS = [
123
+ %i[equals = ==],
124
+ %i[or or |],
125
+ %i[and and &],
126
+ %i[not_equals != !=],
127
+ %i[lte <= <=],
128
+ %i[lt < <],
129
+ %i[gte >= >=],
130
+ %i[gt > >],
131
+ %i[plus +],
132
+ %i[minus -],
133
+ %i[multiply * *],
134
+ %i[divide div /],
135
+ %i[mod mod %]
136
+ ].freeze
120
137
 
121
- OPERATORS = [
122
- %i[equals = ==],
123
- %i[or or |],
124
- %i[and and &],
125
- %i[not_equals != !=],
126
- %i[lte <= <=],
127
- %i[lt < <],
128
- %i[gte >= >=],
129
- %i[gt > >],
130
- %i[plus +],
131
- %i[minus -],
132
- %i[multiply * *],
133
- %i[divide div /],
134
- %i[mod mod %]
135
- ].freeze
138
+ OPERATORS.each do |(name, operator, alias_name)|
139
+ define_method name do |rhs|
140
+ binary_operator(operator, rhs)
141
+ end
142
+ alias_method alias_name, name if alias_name
143
+ end
136
144
 
137
- OPERATORS.each do |(name, operator, alias_name)|
138
- define_method name do |rhs|
139
- binary_operator(operator, rhs)
140
- end
141
- alias_method alias_name, name if alias_name
142
- end
145
+ AXES = %i[
146
+ ancestor ancestor_or_self attribute descendant_or_self
147
+ following following_sibling namespace parent preceding
148
+ preceding_sibling self
149
+ ].freeze
143
150
 
144
- AXES = %i[
145
- ancestor ancestor_or_self attribute descendant_or_self
146
- following following_sibling namespace parent preceding
147
- preceding_sibling self
148
- ].freeze
151
+ AXES.each do |key|
152
+ name = key.to_s.tr('_', '-').to_sym
153
+ define_method key do |*element_names|
154
+ axis(name, *element_names)
155
+ end
156
+ end
149
157
 
150
- AXES.each do |key|
151
- name = key.to_s.tr('_', '-').to_sym
152
- define_method key do |*element_names|
153
- axis(name, *element_names)
154
- end
155
- end
158
+ alias self_axis self
156
159
 
157
- alias_method :self_axis, :self
160
+ def ends_with(suffix)
161
+ function(:substring, current,
162
+ function(:'string-length', current).minus(function(:'string-length', suffix)).plus(1)) == suffix
163
+ end
158
164
 
159
- def ends_with(suffix)
160
- function(:substring, current, function(:'string-length', current).minus(function(:'string-length', suffix)).plus(1)) == suffix
161
- end
165
+ def contains_word(word)
166
+ function(:concat, ' ', current.normalize_space, ' ').contains(" #{word} ")
167
+ end
162
168
 
163
- def contains_word(word)
164
- function(:concat, ' ', current.normalize_space, ' ').contains(" #{word} ")
165
- end
169
+ UPPERCASE_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ'
170
+ LOWERCASE_LETTERS = 'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ'
166
171
 
167
- UPPERCASE_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ'
168
- LOWERCASE_LETTERS = 'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ'
172
+ def lowercase
173
+ method(:translate, UPPERCASE_LETTERS, LOWERCASE_LETTERS)
174
+ end
169
175
 
170
- def lowercase
171
- method(:translate, UPPERCASE_LETTERS, LOWERCASE_LETTERS)
172
- end
176
+ def parenthesis(arg)
177
+ Expression.new(:parenthesis, arg)
178
+ end
173
179
 
174
- def uppercase
175
- method(:translate, LOWERCASE_LETTERS, UPPERCASE_LETTERS)
176
- end
180
+ def uppercase
181
+ method(:translate, LOWERCASE_LETTERS, UPPERCASE_LETTERS)
182
+ end
177
183
 
178
- def one_of(*expressions)
179
- expressions.map { |e| current.equals(e) }.reduce(:or)
180
- end
184
+ def one_of(*expressions)
185
+ expressions.map { |e| current.equals(e) }.reduce(:or)
186
+ end
181
187
 
182
- def next_sibling(*expressions)
183
- axis(:'following-sibling')[1].axis(:self, *expressions)
184
- end
188
+ def next_sibling(*expressions)
189
+ axis(:'following-sibling')[1].axis(:self, *expressions)
190
+ end
185
191
 
186
- def previous_sibling(*expressions)
187
- axis(:'preceding-sibling')[1].axis(:self, *expressions)
188
- end
189
- end
192
+ def previous_sibling(*expressions)
193
+ axis(:'preceding-sibling')[1].axis(:self, *expressions)
194
+ end
195
+ end
190
196
 
191
- extend PaloAlto::DSL
192
- include PaloAlto::DSL
197
+ extend PaloAlto::DSL
198
+ include PaloAlto::DSL
193
199
 
194
- def self.generate
195
- yield(self)
196
- end
200
+ def self.generate
201
+ yield(self)
202
+ end
197
203
 
198
- class Union
199
- include Enumerable
204
+ class Union
205
+ include Enumerable
200
206
 
201
- attr_reader :expressions
202
- alias_method :arguments, :expressions
207
+ attr_reader :expressions
208
+ alias arguments expressions
203
209
 
204
- def initialize(*expressions)
205
- @expressions = expressions
206
- end
210
+ def initialize(*expressions)
211
+ @expressions = expressions
212
+ end
207
213
 
208
- def expression
209
- :union
210
- end
214
+ def expression
215
+ :union
216
+ end
211
217
 
212
- def each(&block)
213
- arguments.each(&block)
214
- end
218
+ def each(&block)
219
+ arguments.each(&block)
220
+ end
215
221
 
216
- def method_missing(*args) # rubocop:disable Style/MethodMissingSuper, Style/MissingRespondToMissing
217
- PaloAlto::Union.new(*arguments.map { |e| e.send(*args) })
218
- end
222
+ def method_missing(*args) # rubocop:disable Style/MissingRespondToMissing
223
+ PaloAlto::Union.new(*arguments.map { |e| e.send(*args) })
224
+ end
219
225
 
220
- def to_xpath(type = nil)
221
- Renderer.render(self, type)
222
- end
223
- end
226
+ def to_xpath(type = nil)
227
+ Renderer.render(self, type)
228
+ end
229
+ end
224
230
 
225
- class Literal
226
- attr_reader :value
227
- def initialize(value)
228
- @value = value
229
- end
230
- end
231
- class Renderer
232
- def self.render(node, type)
233
- new(type).render(node)
234
- end
231
+ class Literal
232
+ attr_reader :value
235
233
 
236
- def initialize(type)
237
- @type = type
238
- end
234
+ def initialize(value)
235
+ @value = value
236
+ end
237
+ end
239
238
 
240
- def render(node)
241
- arguments = node.arguments.map { |argument| convert_argument(argument) }
242
- send(node.expression, *arguments)
243
- end
239
+ class Renderer
240
+ def self.render(node, type)
241
+ new(type).render(node)
242
+ end
244
243
 
245
- def convert_argument(argument)
246
- case argument
247
- when Expression, Union then render(argument)
248
- when Array then argument.map { |element| convert_argument(element) }
249
- when String then string_literal(argument)
250
- when Literal then argument.value
251
- else argument.to_s
252
- end
253
- end
244
+ def initialize(type)
245
+ @type = type
246
+ end
254
247
 
255
- def string_literal(string)
256
- if string.include?("'")
257
- string = string.split("'", -1).map do |substr|
258
- "'#{substr}'"
259
- end.join(%q(,"'",))
260
- "concat(#{string})"
261
- else
262
- "'#{string}'"
263
- end
264
- end
248
+ def render(node)
249
+ arguments = node.arguments.map { |argument| convert_argument(argument) }
250
+ send(node.expression, *arguments)
251
+ end
265
252
 
266
- def this_node
267
- '.'
268
- end
253
+ def convert_argument(argument)
254
+ case argument
255
+ when Expression, Union then render(argument)
256
+ when Array then argument.map { |element| convert_argument(element) }
257
+ when String then string_literal(argument)
258
+ when Literal then argument.value
259
+ else argument.to_s
260
+ end
261
+ end
269
262
 
270
- def binary_operator(name, left, right)
271
- if %w(and or).include?(name)
272
- "(#{left} #{name} #{right})".gsub('./@', '@')
273
- else
274
- "#{left}#{name}#{right}".gsub('./@', '@')
275
- end
276
- end
263
+ def string_literal(string)
264
+ if string.include?("'")
265
+ string = string.split("'", -1).map do |substr|
266
+ "'#{substr}'"
267
+ end.join(%q(,"'",))
268
+ "concat(#{string})"
269
+ else
270
+ "'#{string}'"
271
+ end
272
+ end
277
273
 
278
- def root(current, element_names)
279
- element_names.any? ? "/#{element_names.join('/')}" : ''
280
- end
274
+ def this_node
275
+ '.'
276
+ end
281
277
 
282
- def relative(current, element_names)
283
- '.'
284
- end
278
+ def binary_operator(name, left, right)
279
+ "#{left}#{name}#{right}".gsub('./@', '@')
280
+ end
285
281
 
286
- def descendant(current, element_names)
287
- with_element_conditions("#{current}//", element_names)
288
- end
282
+ def parenthesis(arg)
283
+ "(#{arg})"
284
+ end
289
285
 
290
- def child(current, element_names)
291
- with_element_conditions("#{current}/", element_names)
292
- end
286
+ def root(_current, element_names)
287
+ element_names.any? ? "/#{element_names.join('/')}" : ''
288
+ end
293
289
 
294
- def axis(current, name, element_names)
295
- with_element_conditions("#{current}/#{name}::", element_names)
296
- end
290
+ def relative(_current, _element_names)
291
+ '.'
292
+ end
297
293
 
298
- def anywhere(element_names)
299
- with_element_conditions('//', element_names)
300
- end
294
+ def descendant(current, element_names)
295
+ with_element_conditions("#{current}//", element_names)
296
+ end
301
297
 
302
- def where(on, condition)
303
- "#{on}[#{condition}]"
304
- end
298
+ def child(current, element_names)
299
+ with_element_conditions("#{current}/", element_names)
300
+ end
305
301
 
306
- def attribute(current, name)
307
- if valid_xml_name?(name)
308
- "#{current}/@#{name}"
309
- else
310
- "#{current}/attribute::*[local-name(.) = #{string_literal(name)}]"
311
- end
312
- end
302
+ def axis(current, name, element_names)
303
+ with_element_conditions("#{current}/#{name}::", element_names)
304
+ end
313
305
 
314
- def is(one, two)
315
- if @type == :exact
316
- binary_operator('=', one, two)
317
- else
318
- function(:contains, one, two)
319
- end
320
- end
306
+ def anywhere(element_names)
307
+ with_element_conditions('//', element_names)
308
+ end
321
309
 
322
- def variable(name)
323
- "%{#{name}}"
324
- end
310
+ def where(on, condition)
311
+ "#{on}[#{condition}]"
312
+ end
325
313
 
326
- def text(current)
327
- "#{current}/text()"
328
- end
314
+ def attribute(current, name)
315
+ if valid_xml_name?(name)
316
+ "#{current}/@#{name}"
317
+ else
318
+ "#{current}/attribute::*[local-name(.) = #{string_literal(name)}]"
319
+ end
320
+ end
329
321
 
330
- def literal(node)
331
- node
332
- end
322
+ def is(one, two)
323
+ if @type == :exact
324
+ binary_operator('=', one, two)
325
+ else
326
+ function(:contains, one, two)
327
+ end
328
+ end
333
329
 
334
- def css(current, selector)
335
- paths = Nokogiri::CSS.xpath_for(selector).map do |xpath_selector|
336
- "#{current}#{xpath_selector}"
337
- end
338
- union(paths)
339
- end
330
+ def variable(name)
331
+ "%{#{name}}"
332
+ end
340
333
 
341
- def union(*expressions)
342
- expressions.join(' | ')
343
- end
334
+ def text(current)
335
+ "#{current}/text()"
336
+ end
344
337
 
345
- def function(name, *arguments)
346
- "#{name}(#{arguments.join(', ')})"
347
- end
338
+ def literal(node)
339
+ node
340
+ end
348
341
 
349
- private
342
+ def css(current, selector)
343
+ paths = Nokogiri::CSS.xpath_for(selector).map do |xpath_selector|
344
+ "#{current}#{xpath_selector}"
345
+ end
346
+ union(paths)
347
+ end
350
348
 
351
- def with_element_conditions(expression, element_names)
352
- if element_names.length == 1
353
- "#{expression}#{element_names.first}"
354
- elsif element_names.length > 1
355
- "#{expression}*[#{element_names.map { |e| "self::#{e}" }.join(' | ')}]"
356
- else
357
- "#{expression}*"
358
- end
359
- end
349
+ def union(*expressions)
350
+ expressions.join(' | ')
351
+ end
360
352
 
361
- def valid_xml_name?(name)
362
- name =~ /^[a-zA-Z_:][a-zA-Z0-9_:\.\-]*$/
363
- end
364
- end
365
- class Expression
366
- include PaloAlto::DSL
353
+ def function(name, *arguments)
354
+ "#{name}(#{arguments.join(', ')})"
355
+ end
367
356
 
368
- attr_accessor :expression, :arguments
369
- def initialize(expression, *arguments)
370
- @expression = expression
371
- @arguments = arguments
372
- end
357
+ private
373
358
 
374
- def current
375
- self
376
- end
359
+ def with_element_conditions(expression, element_names)
360
+ if element_names.length == 1
361
+ "#{expression}#{element_names.first}"
362
+ elsif element_names.length > 1
363
+ "#{expression}*[#{element_names.map { |e| "self::#{e}" }.join(' | ')}]"
364
+ else
365
+ "#{expression}*"
366
+ end
367
+ end
377
368
 
378
- def to_xpath(type = nil)
379
- Renderer.render(self, type)
380
- end
381
- end
369
+ def valid_xml_name?(name)
370
+ name =~ /^[a-zA-Z_:][a-zA-Z0-9_:.\-]*$/
371
+ end
372
+ end
382
373
 
374
+ class Expression
375
+ include PaloAlto::DSL
383
376
 
384
- class XML
385
- class ConfigClass < Expression
386
- attr_reader :api_attributes, :subclasses
387
- attr_accessor :parent_instance
377
+ attr_accessor :expression, :arguments
388
378
 
389
- def initialize(parent_instance:, create_children: false)
390
- @parent_instance = parent_instance
391
- @subclasses = {}
392
- @values = {}
393
- @create_children = create_children
394
- @external_values = {} # data we received and don't need to set again
395
- @api_attributes={}
379
+ def initialize(expression, *arguments)
380
+ @expression = expression
381
+ @arguments = arguments
382
+ end
396
383
 
397
- @expression = :child
398
- unless self.is_a?(ArrayConfigClass) # for ArrayConfigClass, it will be set externally after the constructor
399
- xpath_argument = @parent_instance
400
- @arguments = [ xpath_argument, [_section] ]
401
- end
402
- end
384
+ def current
385
+ self
386
+ end
403
387
 
404
- class << self
405
- attr_accessor :props
406
- end
388
+ def to_xpath(type = nil)
389
+ Renderer.render(self, type)
390
+ end
391
+ end
407
392
 
408
- def create!
409
- @create_children = true
410
- self
411
- end
393
+ class XML
394
+ class ConfigClass < Expression
395
+ attr_reader :api_attributes, :subclasses, :parent_instance
396
+ attr_accessor :parent_instance, :force_relative
412
397
 
413
- attr_reader :parent_instance
414
- attr_accessor :force_relative
398
+ def initialize(parent_instance:, create_children: false)
399
+ @parent_instance = parent_instance
400
+ @subclasses = {}
401
+ @values = {}
402
+ @create_children = create_children
403
+ @external_values = {} # data we received and don't need to set again
404
+ @api_attributes = {}
415
405
 
416
- def inspect
417
- self.to_s[0..-1] + ' ' + self.values(full_tree: false).map{|k,v| "#{k}: #{v.inspect}"}.join(", ") + ">"
418
- end
406
+ @expression = :child
407
+ unless is_a?(ArrayConfigClass) # for ArrayConfigClass, it will be set externally after the constructor
408
+ xpath_argument = @parent_instance
409
+ @arguments = [xpath_argument, [_section]]
410
+ end
411
+ end
419
412
 
420
- def get_all
421
- raise(InvalidCommandException, "please use 'get' here") if self.class.superclass != ArrayConfigClass
422
- payload = {
423
- type: "config",
424
- action: "get",
425
- xpath: self.to_xpath
426
- }
413
+ class << self
414
+ attr_accessor :props
415
+ end
427
416
 
428
- data = XML.execute(payload)
429
- start_time=Time.now
430
- result = self.parent_instance.dup.create!.clear!.external_set(data.xpath('//response/result').first)
431
- if XML.debug.include?(:statistics)
432
- warn "Elapsed for parsing #{result.length} results: #{Time.now-start_time} seconds"
433
- end
434
- result
435
- end
417
+ def create!
418
+ @create_children = true
419
+ self
420
+ end
436
421
 
437
- def clear!
438
- @subclasses = {}
439
- @values = {}
440
- self
441
- end
422
+ def inspect
423
+ to_s[0..-1] + ' ' + values(full_tree: false).map { |k, v| "#{k}: #{v.inspect}" }.join(', ') + '>'
424
+ end
442
425
 
443
- def get(ignore_empty_result: false, xpath: self.to_xpath, return_only: false)
444
- if self.class.superclass == ArrayConfigClass && !@selector
445
- raise(InvalidCommandException, "Please use 'get_all' here")
446
- end
426
+ def get_all
427
+ raise(InvalidCommandException, "please use 'get' here") if self.class.superclass != ArrayConfigClass
447
428
 
448
- payload = {
449
- type: 'config',
450
- action: 'get',
451
- xpath: xpath
452
- }
429
+ payload = {
430
+ type: 'config',
431
+ action: 'get',
432
+ xpath: to_xpath
433
+ }
453
434
 
454
- data = XML.execute(payload)
455
- start_time=Time.now
435
+ data = XML.execute(payload)
436
+ start_time = Time.now
437
+ result = parent_instance.dup.create!.clear!.external_set(data.xpath('//response/result').first)
438
+ if XML.debug.include?(:statistics)
439
+ warn "Elapsed for parsing #{result.length} results: #{Time.now - start_time} seconds"
440
+ end
441
+ result
442
+ end
456
443
 
457
- if data.xpath('//response/result/*').length != 1
458
- if ignore_empty_result==false
459
- raise(ObjectNotPresentException, "empty result: #{payload.inspect}")
460
- end
461
- end
444
+ def clear!
445
+ @subclasses = {}
446
+ @values = {}
447
+ self
448
+ end
462
449
 
463
- if return_only
464
- data.xpath('//response/result/*')
465
- else
466
- @create_children=true
467
- n = data.xpath('//response/result/*')
468
- if n.any?
469
- clear!
470
- external_set(n.first)
450
+ def get(ignore_empty_result: false, xpath: to_xpath, return_only: false)
451
+ if self.class.superclass == ArrayConfigClass && !@selector
452
+ raise(InvalidCommandException, "Please use 'get_all' here")
453
+ end
471
454
 
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"
481
- end
482
- end
483
- end
455
+ payload = {
456
+ type: 'config',
457
+ action: 'get',
458
+ xpath: xpath
459
+ }
484
460
 
485
- def get_primary_key(attribute_nodes, props)
486
- primary_key_attr = attribute_nodes.find{|attr|
487
- props.keys.find{|k| k=="@#{attr.name}"}
488
- }
489
- Hash[primary_key_attr.name.to_sym, primary_key_attr.value]
490
- end
461
+ data = XML.execute(payload)
462
+ start_time = Time.now
491
463
 
492
- def set_array_class_attributes(child, primary_key)
493
- @external_values.merge!({ '@' + primary_key.keys.first.to_s => primary_key.values.first})
464
+ if data.xpath('//response/result/*').length != 1 && (ignore_empty_result == false)
465
+ raise(ObjectNotPresentException, "empty result: #{payload.inspect}")
466
+ end
494
467
 
495
- # save also the other attributes like loc and uuid, if set
496
- child.attribute_nodes.each{|attr|
497
- next if attr.name.to_sym == primary_key.keys.first
498
- api_attributes[attr.name] = attr.value
499
- }
500
- end
468
+ if return_only
469
+ data.xpath('//response/result/*')
470
+ else
471
+ @create_children = true
472
+ n = data.xpath('//response/result/*')
473
+ if n.any?
474
+ clear!
475
+ external_set(n.first)
501
476
 
502
- def external_set(data)
503
- data.element_children.map{|child|
504
- child.name.match(/\A[a-zA-Z0-9_-]*\z/) or raise 'invalid character'
505
- if prop = self.class.props[child.name]
506
- if has_multiple_values?
507
- @external_values[child.name]||=[]
508
- @external_values[child.name] << enforce_type(prop, child.text)
509
- else
510
- @external_values[child.name] = enforce_type(prop, child.text)
511
- end
477
+ if is_a?(ArrayConfigClass)
478
+ primary_key = get_primary_key(n.first.attribute_nodes, self.class.props)
479
+ set_array_class_attributes(n.first, primary_key) # primary key, api_attributes
480
+ end
481
+ end
482
+ self
483
+ end.tap do
484
+ warn "Elapsed for parsing: #{Time.now - start_time} seconds" if XML.debug.include?(:statistics)
485
+ end
486
+ end
512
487
 
513
- elsif new_class=eval('self.class::' + child.name.capitalize.gsub(/-(.)/) {|e| $1.upcase}) rescue false # check for class name in camelcase format
514
- if new_class.superclass == ConfigClass
515
- subclass = self.send(child.name.gsub('-','_'))
516
- elsif new_class.superclass == ArrayConfigClass
517
- primary_key = get_primary_key(child.attribute_nodes, new_class.props)
488
+ def get_primary_key(attribute_nodes, props)
489
+ primary_key_attr = attribute_nodes.find do |attr|
490
+ props.keys.find { |k| k == "@#{attr.name}" }
491
+ end
492
+ Hash[primary_key_attr.name.to_sym, primary_key_attr.value]
493
+ end
518
494
 
519
- subclass = self.send(child.name, primary_key) # create subclass
495
+ def set_array_class_attributes(child, primary_key)
496
+ @external_values.merge!({ "@#{primary_key.keys.first}" => primary_key.values.first })
520
497
 
521
- subclass.set_array_class_attributes(child, primary_key) # primary key, api_attributes
522
- else
523
- raise
524
- end
525
- subclass.external_set(child)
526
- else
527
- raise "unknown key: #{child.name}"
528
- end
529
- subclass
530
- }
531
- end
498
+ # save also the other attributes like loc and uuid, if set
499
+ child.attribute_nodes.each do |attr|
500
+ next if attr.name.to_sym == primary_key.keys.first
532
501
 
533
- def enforce_type(prop_arr, value, value_type: prop_arr['type'])
534
- case value_type
535
- when 'bool'
536
- return true if ['yes', true].include?(value)
537
- return false if ['no', false].include?(value)
538
- raise ArgumentError, "Not bool: #{value.inspect}"
539
- when 'string', 'ipdiscontmask', 'iprangespec', 'ipspec', 'rangelistspec'
540
- raise(ArgumentError, "Not string: #{value.inspect}") unless value.is_a?(String)
541
- if prop_arr['regex']
542
- raise ArgumentError, "Not matching regex: #{value.inspect} (#{prop_arr["regex"].inspect})" unless value.match(prop_arr["regex"])
543
- end
544
- if prop_arr['maxlen']
545
- raise ArgumentError, 'Too long' if value.length > prop_arr['maxlen'].to_i
546
- end
547
- return value
548
- when 'enum'
549
- accepted_values = prop_arr.is_a?(Hash) ? prop_arr['enum'].map{|x| x['value']} : prop_arr.map{|x| x['value']} # is an array if part of value_type 'multiple'
550
- return value if accepted_values.include?(value)
551
- raise ArgumentError, "not allowed: #{value.inspect} (not within #{accepted_values.inspect})"
552
- when 'float'
553
- return Float(value)
554
- when 'rangedint'
555
- number = Integer(value)
556
- return number if number >= prop_arr['min'].to_i && number <= prop_arr['max'].to_i
557
- raise ArgumentError, "not in range #{prop_arr['min']}..#{prop_arr['max']}: #{number}"
558
- when 'multiple'
559
- prop_arr['multi-types'].keys.each{|key|
560
- return enforce_type(prop_arr['multi-types'][key], value, value_type: key) rescue false
561
- }
562
- raise(ArgumentError, "Nothing matching found for #{value.inspect} (#{prop_arr.inspect})")
563
- end
564
- end
502
+ api_attributes[attr.name] = attr.value
503
+ end
504
+ end
565
505
 
566
- def xml_builder(xml, full_tree: false, changed_only: true)
567
- keys = changed_only ? @values.keys : self.class.props.keys
506
+ def get_class_from_child_str(child)
507
+ # check for class name in camelcase format
508
+ self.class.const_get(child.name.capitalize.gsub(/-(.)/) { Regexp.last_match(1).upcase })
509
+ rescue NameError
510
+ raise "Child not found: #{child.name}"
511
+ end
568
512
 
569
- keys.map{|k|
570
- next if k.start_with?('@')
571
- v=prop_get(k, include_defaults: false)
572
- next unless v
573
- Array(v).each{|val|
574
- val='yes' if val==true
575
- val='no' if val==false
576
- xml.method_missing(k, val) # somehow .send does not work with k==:system
577
- }
578
- }
579
- if full_tree
580
- @subclasses.each{|k,subclass|
581
- if subclass.is_a?(Hash)
582
- subclass.each{|k2, subclass2|
583
- xml.send(k, k2){|xml|
584
- subclass2.xml_builder(xml, full_tree: full_tree, changed_only: changed_only)
585
- }
586
- }
587
- else
588
- xml.method_missing(k){|xml| # somehow .send does not work with k==:system
589
- subclass.xml_builder(xml, full_tree: full_tree, changed_only: changed_only)
590
- }
591
- end
592
- }
593
- end
594
- return xml
595
- end
513
+ def external_set(data)
514
+ data.element_children.map do |child|
515
+ child.name.match(/\A[a-zA-Z0-9_-]*\z/) or raise 'invalid character'
516
+ if prop = self.class.props[child.name]
517
+ if has_multiple_values?
518
+ @external_values[child.name] ||= []
519
+ @external_values[child.name] << enforce_type(prop, child.text)
520
+ else
521
+ @external_values[child.name] = enforce_type(prop, child.text)
522
+ end
596
523
 
597
- def array_class_setter(*args, klass:, section:, &block)
598
- # either we have a selector or a block
599
- raise(ArgumentError, "wrong number of arguments (expected one argument or block)") unless (args.length==1 && !block) || (args.empty? && block)
524
+ elsif (new_class = get_class_from_child_str(child))
525
+ if new_class.superclass == ConfigClass
526
+ subclass = send(child.name.gsub('-', '_'))
527
+ elsif new_class.superclass == ArrayConfigClass
528
+ primary_key = get_primary_key(child.attribute_nodes, new_class.props)
600
529
 
601
- entry = klass.new(parent_instance: self, create_children: @create_children)
602
- if block
603
- obj = self.child(section.to_sym).where(PaloAlto.instance_eval(&block))
604
- entry.expression = obj.expression
605
- entry.arguments = obj.arguments
606
- entry
607
- else
608
- selector=args[0]
609
- @subclasses[section]||= {}
530
+ subclass = send(child.name, primary_key) # create subclass
610
531
 
611
- entry.instance_variable_get('@external_values').merge!({"@#{selector.keys.first}" => selector.values.first})
612
- entry.selector = selector
613
- entry.set_xpath_from_selector
532
+ subclass.set_array_class_attributes(child, primary_key) # primary key, api_attributes
533
+ else
534
+ raise
535
+ end
536
+ subclass.external_set(child)
537
+ else
538
+ raise "unknown key: #{child.name}"
539
+ end
540
+ subclass
541
+ end
542
+ end
614
543
 
615
- if @create_children
616
- @subclasses[section][selector] ||= entry
617
- else
618
- entry
619
- end
620
- end
621
- end
544
+ def enforce_type(prop_arr, value, value_type: prop_arr['type'])
545
+ case value_type
546
+ when 'bool'
547
+ return true if ['yes', true].include?(value)
548
+ return false if ['no', false].include?(value)
622
549
 
623
- def values(full_tree: true, include_defaults: true)
624
- h={}
625
- self.class.props.keys.map{|k|
626
- prop = prop_get(k, include_defaults: include_defaults)
627
- h[k] = prop if prop
628
- }
629
- if full_tree
630
- @subclasses.each{|k,subclass|
631
- if subclass.is_a?(Hash)
632
- h[k]||={}
633
- subclass.each{|k2, subclass2|
634
- h[k][k2]=subclass2.values(full_tree: true, include_defaults: include_defaults)
635
- }
636
- else
637
- h[k]=subclass.values(full_tree: true, include_defaults: include_defaults)
638
- end
639
- }
640
- end
641
- return h
642
- end
550
+ raise ArgumentError, "Not bool: #{value.inspect}"
551
+ when 'string', 'ipdiscontmask', 'iprangespec', 'ipspec', 'rangelistspec'
552
+ raise(ArgumentError, "Not string: #{value.inspect}") unless value.is_a?(String)
643
553
 
644
- def set_values(h, external: false)
645
- if h.is_a?(PaloAlto::XML::ConfigClass)
646
- h=h.values(include_defaults: false)
647
- end
648
- raise(ArgumentError, 'needs to be a Hash') unless h.is_a?(Hash)
649
- clear!
650
- create!
651
- h.each{|k,v|
652
- if v.is_a?(Hash)
653
- self.send(k.to_s.gsub('-','_')).set_values(v, external: external)
654
- else
655
- if external
656
- @external_values[k]=v
657
- else
658
- self.prop_set(k,v)
659
- end
660
- end
661
- }
662
- self
663
- end
554
+ if prop_arr['regex'] && !value.match(prop_arr['regex']) && !value.match(prop_arr['regex'])
555
+ raise ArgumentError,
556
+ "Not matching regex: #{value.inspect} (#{prop_arr['regex'].inspect})"
557
+ end
558
+ raise ArgumentError, 'Too long' if prop_arr['maxlen'] && (value.length > prop_arr['maxlen'].to_i)
664
559
 
665
- def prop_get(prop, include_defaults: true)
666
- my_prop = self.class.props[prop]
667
- if @values.has_key?(prop)
668
- return @values[prop]
669
- elsif @external_values.has_key?(prop) && @external_values[prop].is_a?(Array)
670
- return @values[prop] = @external_values[prop].dup
671
- elsif @external_values.has_key?(prop)
672
- return @external_values[prop]
673
- elsif my_prop.has_key?("default") && include_defaults
674
- return enforce_types(my_prop, my_prop['default'])
675
- else
676
- return nil
677
- end
678
- end
560
+ value
561
+ when 'enum'
562
+ accepted_values = if prop_arr.is_a?(Hash)
563
+ prop_arr['enum'].map { |x| x['value'] }
564
+ else
565
+ prop_arr.map { |x| x['value'] } # is an array if part of value_type 'multiple'
566
+ end
567
+ return value if accepted_values.include?(value)
679
568
 
680
- def enforce_types(prop_arr, values)
681
- return if values.nil?
569
+ raise ArgumentError, "not allowed: #{value.inspect} (not within #{accepted_values.inspect})"
570
+ when 'float'
571
+ Float(value)
572
+ when 'rangedint'
573
+ number = Integer(value)
574
+ return number if number >= prop_arr['min'].to_i && number <= prop_arr['max'].to_i
682
575
 
683
- if has_multiple_values? && values.is_a?(String)
684
- values = values.split(/\s+/)
685
- end
576
+ raise ArgumentError, "not in range #{prop_arr['min']}..#{prop_arr['max']}: #{number}"
577
+ when 'multiple'
578
+ prop_arr['multi-types'].each_key do |key|
579
+ return enforce_type(prop_arr['multi-types'][key], value, value_type: key)
580
+ rescue StandardError
581
+ false
582
+ end
583
+ raise(ArgumentError, "Nothing matching found for #{value.inspect} (#{prop_arr.inspect})")
584
+ end
585
+ end
686
586
 
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)
691
- else
692
- raise(ArgumentError, 'Needs to be Array but is not, or vice versa')
693
- end
694
- end
587
+ def xml_builder(xml, full_tree: false, changed_only: true)
588
+ keys = changed_only ? @values.keys : self.class.props.keys
695
589
 
696
- def prop_set(prop, value)
697
- my_prop = self.class.props[prop] or raise(InternalErrorException, "Unknown attribute for #{self.class}: #{prop}")
590
+ keys.map do |k|
591
+ next if k.start_with?('@')
698
592
 
699
- @values[prop] = enforce_types(my_prop, value)
700
- end
593
+ v = prop_get(k, include_defaults: false)
594
+ next unless v
701
595
 
702
- def to_xml(changed_only:, full_tree:, include_root: )
703
- builder = Nokogiri::XML::Builder.new{|xml|
704
- xml.send(self._section, (self.selector rescue nil)) {
705
- self.xml_builder(xml, changed_only: changed_only, full_tree: full_tree)
706
- }
707
- }
708
- if include_root
709
- builder.doc.root.to_xml
710
- else
711
- builder.doc.root.children.map(&:to_xml).join("\n")
712
- end
713
- end
596
+ Array(v).each do |val|
597
+ val = 'yes' if val == true
598
+ val = 'no' if val == false
599
+ xml.method_missing(k, val) # somehow .send does not work with k==:system
600
+ end
601
+ end
602
+ if full_tree
603
+ @subclasses.each do |k, subclass|
604
+ if subclass.is_a?(Hash)
605
+ subclass.each do |k2, subclass2|
606
+ xml.public_send(k, k2) do |xml2|
607
+ subclass2.xml_builder(xml2, full_tree: full_tree, changed_only: changed_only)
608
+ end
609
+ end
610
+ else
611
+ xml.public_send(k) do |xml2|
612
+ subclass.xml_builder(xml2, full_tree: full_tree, changed_only: changed_only)
613
+ end
614
+ end
615
+ end
616
+ end
617
+ xml
618
+ end
714
619
 
715
- def push!
716
- xml_str = self.to_xml(changed_only: false, full_tree: true, include_root: true)
620
+ def array_class_setter(*args, klass:, section:, &block)
621
+ # either we have a selector or a block
622
+ unless (args.length == 1 && !block) || (args.empty? && block)
623
+ raise(ArgumentError,
624
+ 'wrong number of arguments (expected one argument or block)')
625
+ end
717
626
 
718
- payload = {
719
- type: 'config',
720
- action: 'edit',
721
- xpath: self.to_xpath,
722
- element: xml_str
723
- }
724
- XML.execute(payload)
725
- end
627
+ entry = klass.new(parent_instance: self, create_children: @create_children)
628
+ if block
629
+ obj = child(section.to_sym).where(PaloAlto.instance_eval(&block))
630
+ entry.expression = obj.expression
631
+ entry.arguments = obj.arguments
632
+ entry
633
+ else
634
+ selector = args[0]
635
+ @subclasses[section] ||= {}
726
636
 
727
- def delete_child(name)
728
- @subclasses.delete(name) && true || false
729
- end
637
+ entry.instance_variable_get('@external_values').merge!({ "@#{selector.keys.first}" => selector.values.first })
638
+ entry.selector = selector
639
+ entry.set_xpath_from_selector
730
640
 
731
- def delete!
732
- payload = {
733
- type: 'config',
734
- action: 'delete',
735
- xpath: self.to_xpath
736
- }
737
- XML.execute(payload)
738
- end
641
+ if @create_children
642
+ @subclasses[section][selector] ||= entry
643
+ else
644
+ entry
645
+ end
646
+ end
647
+ end
739
648
 
740
- def multimove!(dst:, members:, all_errors: false)
741
- source = self.to_xpath
649
+ def values(full_tree: true, include_defaults: true)
650
+ h = {}
651
+ self.class.props.keys.map do |k|
652
+ prop = prop_get(k, include_defaults: include_defaults)
653
+ h[k] = prop if prop
654
+ end
655
+ if full_tree
656
+ @subclasses.each do |k, subclass|
657
+ if subclass.is_a?(Hash)
658
+ h[k] ||= {}
659
+ subclass.each do |k2, subclass2|
660
+ h[k][k2] = subclass2.values(full_tree: true, include_defaults: include_defaults)
661
+ end
662
+ else
663
+ h[k] = subclass.values(full_tree: true, include_defaults: include_defaults)
664
+ end
665
+ end
666
+ end
667
+ h
668
+ end
742
669
 
743
- builder = Nokogiri::XML::Builder.new{|xml|
744
- xml.root {
745
- xml.send('selected-list') {
746
- xml.source(xpath: source) {
747
- members.each{|member| xml.member member}
748
- }
749
- }
750
- xml.send('all-errors', all_errors ? 'yes' : 'no')
751
- }
752
- }
670
+ def set_values(h, external: false)
671
+ h = h.values(include_defaults: false) if h.is_a?(PaloAlto::XML::ConfigClass)
672
+ raise(ArgumentError, 'needs to be a Hash') unless h.is_a?(Hash)
753
673
 
754
- element = builder.doc.root.children.map(&:to_xml).join("\n")
674
+ clear!
675
+ create!
676
+ h.each do |k, v|
677
+ if v.is_a?(Hash)
678
+ send(k.to_s.gsub('-', '_')).set_values(v, external: external)
679
+ elsif external
680
+ @external_values[k] = v
681
+ else
682
+ prop_set(k, v)
683
+ end
684
+ end
685
+ self
686
+ end
755
687
 
756
- payload = {
757
- type: 'config',
758
- action: 'multi-move',
759
- xpath: dst,
760
- element: element
761
- }
688
+ def prop_get(prop, include_defaults: true)
689
+ my_prop = self.class.props[prop]
690
+ if @values.key?(prop)
691
+ @values[prop]
692
+ elsif @external_values.key?(prop) && @external_values[prop].is_a?(Array)
693
+ @values[prop] = @external_values[prop].dup
694
+ elsif @external_values.key?(prop)
695
+ @external_values[prop]
696
+ elsif my_prop.key?('default') && include_defaults
697
+ enforce_types(my_prop, my_prop['default'])
698
+ end
699
+ end
762
700
 
763
- XML.execute(payload)
764
- end
765
- end
701
+ def enforce_types(prop_arr, values)
702
+ return if values.nil?
766
703
 
767
- class ArrayConfigClass < ConfigClass
768
- attr_accessor :selector
704
+ values = values.split(/\s+/) if has_multiple_values? && values.is_a?(String)
769
705
 
770
- def move!(where:, dst: nil)
771
- payload = {
772
- type: 'config',
773
- action: 'move',
774
- xpath: self.to_xpath,
775
- where: where
776
- }
777
- if dst
778
- payload[:dst] = dst
779
- end
706
+ if values.is_a?(Array) && has_multiple_values?
707
+ values.map { |v| enforce_type(prop_arr, v) }
708
+ elsif !has_multiple_values?
709
+ enforce_type(prop_arr, values)
710
+ else
711
+ raise(ArgumentError, 'Needs to be Array but is not, or vice versa')
712
+ end
713
+ end
780
714
 
781
- XML.execute(payload)
782
- end
715
+ def prop_set(prop, value)
716
+ my_prop = self.class.props[prop] or raise(InternalErrorException,
717
+ "Unknown attribute for #{self.class}: #{prop}")
783
718
 
784
- def set_xpath_from_selector(selector: @selector)
785
- xpath = self.parent_instance.child(_section)
786
- k, v = selector.first
787
- obj = xpath.where(PaloAlto.xpath_attr(k.to_sym) == v)
719
+ @values[prop] = enforce_types(my_prop, value)
720
+ end
788
721
 
789
- @expression = obj.expression
790
- @arguments = obj.arguments
791
- end
722
+ def to_xml(changed_only:, full_tree:, include_root:)
723
+ builder = Nokogiri::XML::Builder.new do |xml|
724
+ xml.public_send(_section, begin
725
+ selector
726
+ rescue StandardError
727
+ nil
728
+ end) do
729
+ xml_builder(xml, changed_only: changed_only, full_tree: full_tree)
730
+ end
731
+ end
732
+ if include_root
733
+ builder.doc.root.to_xml
734
+ else
735
+ builder.doc.root.children.map(&:to_xml).join("\n")
736
+ end
737
+ end
792
738
 
793
- def rename!(new_name, internal_only: false)
794
- # https://docs.paloaltonetworks.com/pan-os/10-1/pan-os-panorama-api/pan-os-xml-api-request-types/configuration-api/rename-configuration.html
795
- unless internal_only
796
- payload = {
797
- type: 'config',
798
- action: 'rename',
799
- xpath: self.to_xpath,
800
- newname: new_name
801
- }
739
+ def push!
740
+ xml_str = to_xml(changed_only: false, full_tree: true, include_root: true)
802
741
 
803
- result = XML.execute(payload)
804
- end
742
+ payload = {
743
+ type: 'config',
744
+ action: 'edit',
745
+ xpath: to_xpath,
746
+ element: xml_str
747
+ }
748
+ XML.execute(payload)
749
+ end
805
750
 
806
- # now update also the internal value to the new name
807
- self.selector.transform_values!{new_name}
808
- @external_values["@#{self.selector.keys.first}"] = new_name
809
- set_xpath_from_selector()
810
- end
811
- end
751
+ def delete_child(name)
752
+ @subclasses.delete(name) && true || false
753
+ end
754
+
755
+ def delete!
756
+ payload = {
757
+ type: 'config',
758
+ action: 'delete',
759
+ xpath: to_xpath
760
+ }
761
+ XML.execute(payload)
762
+ end
763
+
764
+ def multimove!(dst:, members:, all_errors: false)
765
+ source = to_xpath
766
+
767
+ builder = Nokogiri::XML::Builder.new do |xml|
768
+ xml.root do
769
+ xml.public_send('selected-list') do
770
+ xml.source(xpath: source) do
771
+ members.each { |member| xml.member member }
772
+ end
773
+ end
774
+ xml.public_send('all-errors', all_errors ? 'yes' : 'no')
775
+ end
776
+ end
777
+
778
+ element = builder.doc.root.children.map(&:to_xml).join("\n")
779
+
780
+ payload = {
781
+ type: 'config',
782
+ action: 'multi-move',
783
+ xpath: dst,
784
+ element: element
785
+ }
786
+
787
+ XML.execute(payload)
788
+ end
789
+ end
790
+
791
+ class ArrayConfigClass < ConfigClass
792
+ attr_accessor :selector
793
+
794
+ def move!(where:, dst: nil)
795
+ payload = {
796
+ type: 'config',
797
+ action: 'move',
798
+ xpath: to_xpath,
799
+ where: where
800
+ }
801
+ payload[:dst] = dst if dst
802
+
803
+ XML.execute(payload)
804
+ end
805
+
806
+ def set_xpath_from_selector(selector: @selector)
807
+ xpath = parent_instance.child(_section)
808
+ k, v = selector.first
809
+ obj = xpath.where(PaloAlto.xpath_attr(k.to_sym) == v)
810
+
811
+ @expression = obj.expression
812
+ @arguments = obj.arguments
813
+ end
814
+
815
+ def rename!(new_name, internal_only: false)
816
+ # https://docs.paloaltonetworks.com/pan-os/10-1/pan-os-panorama-api/pan-os-xml-api-request-types/configuration-api/rename-configuration.html
817
+ unless internal_only
818
+ payload = {
819
+ type: 'config',
820
+ action: 'rename',
821
+ xpath: to_xpath,
822
+ newname: new_name
823
+ }
824
+
825
+ XML.execute(payload)
826
+ end
827
+
828
+ # now update also the internal value to the new name
829
+ selector.transform_values! { new_name }
830
+ @external_values["@#{selector.keys.first}"] = new_name
831
+ set_xpath_from_selector
832
+ end
833
+ end
812
834
 
813
- #no end of class Xml here as generated source will be added here
835
+ # no end of class Xml here as generated source will be added here
814
836
  class Config < ConfigClass
815
837
  def has_multiple_values?
816
838
  false