palo_alto 0.1.6 → 0.2.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.
@@ -1,812 +1,838 @@
1
- # generated: 2021-10-19 00:56:02 +0200
1
+ # generated: 2021-11-21 15:25:41 +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
- "#{left}#{name}#{right}".gsub('./@', '@')
272
- 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
273
273
 
274
- def root(current, element_names)
275
- element_names.any? ? "/#{element_names.join('/')}" : ''
276
- end
274
+ def this_node
275
+ '.'
276
+ end
277
277
 
278
- def relative(current, element_names)
279
- '.'
280
- end
278
+ def binary_operator(name, left, right)
279
+ "#{left}#{name}#{right}".gsub('./@', '@')
280
+ end
281
281
 
282
- def descendant(current, element_names)
283
- with_element_conditions("#{current}//", element_names)
284
- end
282
+ def parenthesis(arg)
283
+ "(#{arg})"
284
+ end
285
285
 
286
- def child(current, element_names)
287
- with_element_conditions("#{current}/", element_names)
288
- end
286
+ def root(_current, element_names)
287
+ element_names.any? ? "/#{element_names.join('/')}" : ''
288
+ end
289
289
 
290
- def axis(current, name, element_names)
291
- with_element_conditions("#{current}/#{name}::", element_names)
292
- end
290
+ def relative(_current, _element_names)
291
+ '.'
292
+ end
293
293
 
294
- def anywhere(element_names)
295
- with_element_conditions('//', element_names)
296
- end
294
+ def descendant(current, element_names)
295
+ with_element_conditions("#{current}//", element_names)
296
+ end
297
297
 
298
- def where(on, condition)
299
- "#{on}[#{condition}]"
300
- end
298
+ def child(current, element_names)
299
+ with_element_conditions("#{current}/", element_names)
300
+ end
301
301
 
302
- def attribute(current, name)
303
- if valid_xml_name?(name)
304
- "#{current}/@#{name}"
305
- else
306
- "#{current}/attribute::*[local-name(.) = #{string_literal(name)}]"
307
- end
308
- end
302
+ def axis(current, name, element_names)
303
+ with_element_conditions("#{current}/#{name}::", element_names)
304
+ end
309
305
 
310
- def is(one, two)
311
- if @type == :exact
312
- binary_operator('=', one, two)
313
- else
314
- function(:contains, one, two)
315
- end
316
- end
306
+ def anywhere(element_names)
307
+ with_element_conditions('//', element_names)
308
+ end
317
309
 
318
- def variable(name)
319
- "%{#{name}}"
320
- end
310
+ def where(on, condition)
311
+ "#{on}[#{condition}]"
312
+ end
321
313
 
322
- def text(current)
323
- "#{current}/text()"
324
- 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
325
321
 
326
- def literal(node)
327
- node
328
- 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
329
329
 
330
- def css(current, selector)
331
- paths = Nokogiri::CSS.xpath_for(selector).map do |xpath_selector|
332
- "#{current}#{xpath_selector}"
333
- end
334
- union(paths)
335
- end
330
+ def variable(name)
331
+ "%{#{name}}"
332
+ end
336
333
 
337
- def union(*expressions)
338
- expressions.join(' | ')
339
- end
334
+ def text(current)
335
+ "#{current}/text()"
336
+ end
340
337
 
341
- def function(name, *arguments)
342
- "#{name}(#{arguments.join(', ')})"
343
- end
338
+ def literal(node)
339
+ node
340
+ end
344
341
 
345
- 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
346
348
 
347
- def with_element_conditions(expression, element_names)
348
- if element_names.length == 1
349
- "#{expression}#{element_names.first}"
350
- elsif element_names.length > 1
351
- "#{expression}*[#{element_names.map { |e| "self::#{e}" }.join(' | ')}]"
352
- else
353
- "#{expression}*"
354
- end
355
- end
349
+ def union(*expressions)
350
+ expressions.join(' | ')
351
+ end
356
352
 
357
- def valid_xml_name?(name)
358
- name =~ /^[a-zA-Z_:][a-zA-Z0-9_:\.\-]*$/
359
- end
360
- end
361
- class Expression
362
- include PaloAlto::DSL
353
+ def function(name, *arguments)
354
+ "#{name}(#{arguments.join(', ')})"
355
+ end
363
356
 
364
- attr_accessor :expression, :arguments
365
- def initialize(expression, *arguments)
366
- @expression = expression
367
- @arguments = arguments
368
- end
357
+ private
369
358
 
370
- def current
371
- self
372
- 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
373
368
 
374
- def to_xpath(type = nil)
375
- Renderer.render(self, type)
376
- end
377
- end
369
+ def valid_xml_name?(name)
370
+ name =~ /^[a-zA-Z_:][a-zA-Z0-9_:.\-]*$/
371
+ end
372
+ end
378
373
 
374
+ class Expression
375
+ include PaloAlto::DSL
379
376
 
380
- class XML
381
- class ConfigClass < Expression
382
- attr_reader :api_attributes, :subclasses
383
- attr_accessor :parent_instance
377
+ attr_accessor :expression, :arguments
384
378
 
385
- def initialize(parent_instance:, create_children: false)
386
- @parent_instance = parent_instance
387
- @subclasses = {}
388
- @values = {}
389
- @create_children = create_children
390
- @external_values = {} # data we received and don't need to set again
391
- @api_attributes={}
379
+ def initialize(expression, *arguments)
380
+ @expression = expression
381
+ @arguments = arguments
382
+ end
392
383
 
393
- @expression = :child
394
- unless self.is_a?(ArrayConfigClass) # for ArrayConfigClass, it will be set externally after the constructor
395
- xpath_argument = @parent_instance
396
- @arguments = [ xpath_argument, [_section] ]
397
- end
398
- end
384
+ def current
385
+ self
386
+ end
399
387
 
400
- class << self
401
- attr_accessor :props
402
- end
388
+ def to_xpath(type = nil)
389
+ Renderer.render(self, type)
390
+ end
391
+ end
403
392
 
404
- def create!
405
- @create_children = true
406
- self
407
- end
393
+ class XML
394
+ class ConfigClass < Expression
395
+ attr_reader :api_attributes, :subclasses, :parent_instance
396
+ attr_accessor :parent_instance, :force_relative
408
397
 
409
- attr_reader :parent_instance
410
- 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 = {}
411
405
 
412
- def inspect
413
- self.to_s[0..-1] + ' ' + self.values(full_tree: false).map{|k,v| "#{k}: #{v.inspect}"}.join(", ") + ">"
414
- 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
415
412
 
416
- def get_all
417
- raise(InvalidCommandException, "please use 'get' here") if self.class.superclass != ArrayConfigClass
418
- payload = {
419
- type: "config",
420
- action: "get",
421
- xpath: self.to_xpath
422
- }
413
+ class << self
414
+ attr_accessor :props
415
+ end
423
416
 
424
- data = XML.execute(payload)
425
- start_time=Time.now
426
- result = self.parent_instance.dup.create!.clear!.external_set(data.xpath('//response/result').first)
427
- if XML.debug.include?(:statistics)
428
- warn "Elapsed for parsing #{result.length} results: #{Time.now-start_time} seconds"
429
- end
430
- result
431
- end
417
+ def create!
418
+ @create_children = true
419
+ self
420
+ end
432
421
 
433
- def clear!
434
- @subclasses = {}
435
- @values = {}
436
- self
437
- end
422
+ def inspect
423
+ to_s[0..-1] + ' ' + values(full_tree: false).map { |k, v| "#{k}: #{v.inspect}" }.join(', ') + '>'
424
+ end
438
425
 
439
- def get(ignore_empty_result: false, xpath: self.to_xpath, return_only: false)
440
- if self.class.superclass == ArrayConfigClass && !@selector
441
- raise(InvalidCommandException, "Please use 'get_all' here")
442
- end
426
+ def get_all
427
+ raise(InvalidCommandException, "please use 'get' here") if self.class.superclass != ArrayConfigClass
443
428
 
444
- payload = {
445
- type: 'config',
446
- action: 'get',
447
- xpath: xpath
448
- }
429
+ payload = {
430
+ type: 'config',
431
+ action: 'get',
432
+ xpath: to_xpath
433
+ }
449
434
 
450
- data = XML.execute(payload)
451
- 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
452
443
 
453
- if data.xpath('//response/result/*').length != 1
454
- if ignore_empty_result==false
455
- raise(ObjectNotPresentException, "empty result: #{payload.inspect}")
456
- end
457
- end
444
+ def clear!
445
+ @subclasses = {}
446
+ @values = {}
447
+ self
448
+ end
458
449
 
459
- if return_only
460
- data.xpath('//response/result/*')
461
- else
462
- @create_children=true
463
- n = data.xpath('//response/result/*')
464
- if n.any?
465
- clear!
466
- 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
467
454
 
468
- if is_a?(ArrayConfigClass)
469
- primary_key = get_primary_key(n.first.attribute_nodes, self.class.props)
470
- set_array_class_attributes(n.first, primary_key) # primary key, api_attributes
471
- end
472
- end
473
- self
474
- end.tap do
475
- if XML.debug.include?(:statistics)
476
- warn "Elapsed for parsing: #{Time.now-start_time} seconds"
477
- end
478
- end
479
- end
455
+ payload = {
456
+ type: 'config',
457
+ action: 'get',
458
+ xpath: xpath
459
+ }
480
460
 
481
- def get_primary_key(attribute_nodes, props)
482
- primary_key_attr = attribute_nodes.find{|attr|
483
- props.keys.find{|k| k=="@#{attr.name}"}
484
- }
485
- Hash[primary_key_attr.name.to_sym, primary_key_attr.value]
486
- end
461
+ data = XML.execute(payload)
462
+ start_time = Time.now
487
463
 
488
- def set_array_class_attributes(child, primary_key)
489
- @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
490
467
 
491
- # save also the other attributes like loc and uuid, if set
492
- child.attribute_nodes.each{|attr|
493
- next if attr.name.to_sym == primary_key.keys.first
494
- api_attributes[attr.name] = attr.value
495
- }
496
- 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)
497
476
 
498
- def external_set(data)
499
- data.element_children.map{|child|
500
- child.name.match(/\A[a-zA-Z0-9_-]*\z/) or raise 'invalid character'
501
- if prop = self.class.props[child.name]
502
- if has_multiple_values?
503
- @external_values[child.name]||=[]
504
- @external_values[child.name] << enforce_type(prop, child.text)
505
- else
506
- @external_values[child.name] = enforce_type(prop, child.text)
507
- 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
508
487
 
509
- elsif new_class=eval('self.class::' + child.name.capitalize.gsub(/-(.)/) {|e| $1.upcase}) rescue false # check for class name in camelcase format
510
- if new_class.superclass == ConfigClass
511
- subclass = self.send(child.name.gsub('-','_'))
512
- elsif new_class.superclass == ArrayConfigClass
513
- 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
514
494
 
515
- 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 })
516
497
 
517
- subclass.set_array_class_attributes(child, primary_key) # primary key, api_attributes
518
- else
519
- raise
520
- end
521
- subclass.external_set(child)
522
- else
523
- raise "unknown key: #{child.name}"
524
- end
525
- subclass
526
- }
527
- 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
528
501
 
529
- def enforce_type(prop_arr, value, value_type: prop_arr['type'])
530
- case value_type
531
- when 'bool'
532
- return true if ['yes', true].include?(value)
533
- return false if ['no', false].include?(value)
534
- raise ArgumentError, "Not bool: #{value.inspect}"
535
- when 'string', 'ipdiscontmask', 'iprangespec', 'ipspec', 'rangelistspec'
536
- raise(ArgumentError, "Not string: #{value.inspect}") unless value.is_a?(String)
537
- if prop_arr['regex']
538
- raise ArgumentError, "Not matching regex: #{value.inspect} (#{prop_arr["regex"].inspect})" unless value.match(prop_arr["regex"])
539
- end
540
- if prop_arr['maxlen']
541
- raise ArgumentError, 'Too long' if value.length > prop_arr['maxlen'].to_i
542
- end
543
- return value
544
- when 'enum'
545
- 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'
546
- return value if accepted_values.include?(value)
547
- raise ArgumentError, "not allowed: #{value.inspect} (not within #{accepted_values.inspect})"
548
- when 'float'
549
- return Float(value)
550
- when 'rangedint'
551
- number = Integer(value)
552
- return number if number >= prop_arr['min'].to_i && number <= prop_arr['max'].to_i
553
- raise ArgumentError, "not in range #{prop_arr['min']}..#{prop_arr['max']}: #{number}"
554
- when 'multiple'
555
- prop_arr['multi-types'].keys.each{|key|
556
- return enforce_type(prop_arr['multi-types'][key], value, value_type: key) rescue false
557
- }
558
- raise(ArgumentError, "Nothing matching found for #{value.inspect} (#{prop_arr.inspect})")
559
- end
560
- end
502
+ api_attributes[attr.name] = attr.value
503
+ end
504
+ end
561
505
 
562
- def xml_builder(xml, full_tree: false, changed_only: true)
563
- 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
564
512
 
565
- keys.map{|k|
566
- next if k.start_with?('@')
567
- v=prop_get(k, include_defaults: false)
568
- next unless v
569
- Array(v).each{|val|
570
- val='yes' if val==true
571
- val='no' if val==false
572
- xml.method_missing(k, val) # somehow .send does not work with k==:system
573
- }
574
- }
575
- if full_tree
576
- @subclasses.each{|k,subclass|
577
- if subclass.is_a?(Hash)
578
- subclass.each{|k2, subclass2|
579
- xml.send(k, k2){|xml|
580
- subclass2.xml_builder(xml, full_tree: full_tree, changed_only: changed_only)
581
- }
582
- }
583
- else
584
- xml.method_missing(k){|xml| # somehow .send does not work with k==:system
585
- subclass.xml_builder(xml, full_tree: full_tree, changed_only: changed_only)
586
- }
587
- end
588
- }
589
- end
590
- return xml
591
- 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
592
523
 
593
- def array_class_setter(*args, klass:, section:, &block)
594
- # either we have a selector or a block
595
- 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)
596
529
 
597
- entry = klass.new(parent_instance: self, create_children: @create_children)
598
- if block
599
- obj = self.child(section.to_sym).where(PaloAlto.instance_eval(&block))
600
- entry.expression = obj.expression
601
- entry.arguments = obj.arguments
602
- entry
603
- else
604
- selector=args[0]
605
- @subclasses[section]||= {}
530
+ subclass = send(child.name, primary_key) # create subclass
606
531
 
607
- entry.instance_variable_get('@external_values').merge!({"@#{selector.keys.first}" => selector.values.first})
608
- entry.selector = selector
609
- 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
610
543
 
611
- if @create_children
612
- @subclasses[section][selector] ||= entry
613
- else
614
- entry
615
- end
616
- end
617
- 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)
618
549
 
619
- def values(full_tree: true, include_defaults: true)
620
- h={}
621
- self.class.props.keys.map{|k|
622
- prop = prop_get(k, include_defaults: include_defaults)
623
- h[k] = prop if prop
624
- }
625
- if full_tree
626
- @subclasses.each{|k,subclass|
627
- if subclass.is_a?(Hash)
628
- h[k]||={}
629
- subclass.each{|k2, subclass2|
630
- h[k][k2]=subclass2.values(full_tree: true, include_defaults: include_defaults)
631
- }
632
- else
633
- h[k]=subclass.values(full_tree: true, include_defaults: include_defaults)
634
- end
635
- }
636
- end
637
- return h
638
- 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)
639
553
 
640
- def set_values(h, external: false)
641
- if h.is_a?(PaloAlto::XML::ConfigClass)
642
- h=h.values(include_defaults: false)
643
- end
644
- raise(ArgumentError, 'needs to be a Hash') unless h.is_a?(Hash)
645
- clear!
646
- create!
647
- h.each{|k,v|
648
- if v.is_a?(Hash)
649
- self.send(k.to_s.gsub('-','_')).set_values(v, external: external)
650
- else
651
- if external
652
- @external_values[k]=v
653
- else
654
- self.prop_set(k,v)
655
- end
656
- end
657
- }
658
- self
659
- 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)
660
559
 
661
- def prop_get(prop, include_defaults: true)
662
- my_prop = self.class.props[prop]
663
- if @values.has_key?(prop)
664
- return @values[prop]
665
- elsif @external_values.has_key?(prop) && @external_values[prop].is_a?(Array)
666
- return @values[prop] = @external_values[prop].dup
667
- elsif @external_values.has_key?(prop)
668
- return @external_values[prop]
669
- elsif my_prop.has_key?("default") && include_defaults
670
- return enforce_types(my_prop, my_prop['default'])
671
- else
672
- return nil
673
- end
674
- 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)
675
568
 
676
- def enforce_types(prop_arr, values)
677
- 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
678
575
 
679
- if has_multiple_values? && values.is_a?(String)
680
- values = values.split(/\s+/)
681
- 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
682
586
 
683
- if values.is_a?(Array) && has_multiple_values?
684
- values.map{|v| enforce_type(prop_arr, v)}
685
- elsif !has_multiple_values?
686
- enforce_type(prop_arr, values)
687
- else
688
- raise(ArgumentError, 'Needs to be Array but is not, or vice versa')
689
- end
690
- end
587
+ def xml_builder(xml, full_tree: false, changed_only: true)
588
+ keys = changed_only ? @values.keys : self.class.props.keys
691
589
 
692
- def prop_set(prop, value)
693
- 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?('@')
694
592
 
695
- @values[prop] = enforce_types(my_prop, value)
696
- end
593
+ v = prop_get(k, include_defaults: false)
594
+ next unless v
697
595
 
698
- def to_xml(changed_only:, full_tree:, include_root: )
699
- builder = Nokogiri::XML::Builder.new{|xml|
700
- xml.send(self._section, (self.selector rescue nil)) {
701
- self.xml_builder(xml, changed_only: changed_only, full_tree: full_tree)
702
- }
703
- }
704
- if include_root
705
- builder.doc.root.to_xml
706
- else
707
- builder.doc.root.children.map(&:to_xml).join("\n")
708
- end
709
- 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.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.method_missing(k) do |xml2| # somehow .send does not work with k==:system
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
710
619
 
711
- def push!
712
- 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
713
626
 
714
- payload = {
715
- type: 'config',
716
- action: 'edit',
717
- xpath: self.to_xpath,
718
- element: xml_str
719
- }
720
- XML.execute(payload)
721
- 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] ||= {}
722
636
 
723
- def delete_child(name)
724
- @subclasses.delete(name) && true || false
725
- 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
726
640
 
727
- def delete!
728
- payload = {
729
- type: 'config',
730
- action: 'delete',
731
- xpath: self.to_xpath
732
- }
733
- XML.execute(payload)
734
- end
641
+ if @create_children
642
+ @subclasses[section][selector] ||= entry
643
+ else
644
+ entry
645
+ end
646
+ end
647
+ end
735
648
 
736
- def multimove!(dst:, members:, all_errors: false)
737
- 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
738
669
 
739
- builder = Nokogiri::XML::Builder.new{|xml|
740
- xml.root {
741
- xml.send('selected-list') {
742
- xml.source(xpath: source) {
743
- members.each{|member| xml.member member}
744
- }
745
- }
746
- xml.send('all-errors', all_errors ? 'yes' : 'no')
747
- }
748
- }
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)
749
673
 
750
- 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
751
687
 
752
- payload = {
753
- type: 'config',
754
- action: 'multi-move',
755
- xpath: dst,
756
- element: element
757
- }
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
758
700
 
759
- XML.execute(payload)
760
- end
761
- end
701
+ def enforce_types(prop_arr, values)
702
+ return if values.nil?
762
703
 
763
- class ArrayConfigClass < ConfigClass
764
- attr_accessor :selector
704
+ values = values.split(/\s+/) if has_multiple_values? && values.is_a?(String)
765
705
 
766
- def move!(where:, dst: nil)
767
- payload = {
768
- type: 'config',
769
- action: 'move',
770
- xpath: self.to_xpath,
771
- where: where
772
- }
773
- if dst
774
- payload[:dst] = dst
775
- 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
776
714
 
777
- XML.execute(payload)
778
- end
715
+ def prop_set(prop, value)
716
+ my_prop = self.class.props[prop] or raise(InternalErrorException,
717
+ "Unknown attribute for #{self.class}: #{prop}")
779
718
 
780
- def set_xpath_from_selector(selector: @selector)
781
- xpath = self.parent_instance.child(_section)
782
- k, v = selector.first
783
- obj = xpath.where(PaloAlto.xpath_attr(k.to_sym) == v)
719
+ @values[prop] = enforce_types(my_prop, value)
720
+ end
784
721
 
785
- @expression = obj.expression
786
- @arguments = obj.arguments
787
- end
722
+ def to_xml(changed_only:, full_tree:, include_root:)
723
+ builder = Nokogiri::XML::Builder.new do |xml|
724
+ xml.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
788
738
 
789
- def rename!(new_name, internal_only: false)
790
- # https://docs.paloaltonetworks.com/pan-os/10-1/pan-os-panorama-api/pan-os-xml-api-request-types/configuration-api/rename-configuration.html
791
- unless internal_only
792
- payload = {
793
- type: 'config',
794
- action: 'rename',
795
- xpath: self.to_xpath,
796
- newname: new_name
797
- }
739
+ def push!
740
+ xml_str = to_xml(changed_only: false, full_tree: true, include_root: true)
798
741
 
799
- result = XML.execute(payload)
800
- end
742
+ payload = {
743
+ type: 'config',
744
+ action: 'edit',
745
+ xpath: to_xpath,
746
+ element: xml_str
747
+ }
748
+ XML.execute(payload)
749
+ end
801
750
 
802
- # now update also the internal value to the new name
803
- self.selector.transform_values!{new_name}
804
- @external_values["@#{self.selector.keys.first}"] = new_name
805
- set_xpath_from_selector()
806
- end
807
- 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.send('selected-list') do
770
+ xml.source(xpath: source) do
771
+ members.each { |member| xml.member member }
772
+ end
773
+ end
774
+ xml.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
808
834
 
809
- #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
810
836
  class Config < ConfigClass
811
837
  def has_multiple_values?
812
838
  false