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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/lib/palo_alto/config.rb +701 -679
- data/lib/palo_alto/op.rb +71 -40
- data/lib/palo_alto/version.rb +1 -1
- data/lib/palo_alto.rb +82 -87
- metadata +3 -2
data/lib/palo_alto/config.rb
CHANGED
@@ -1,816 +1,838 @@
|
|
1
|
-
# generated: 2021-
|
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
|
-
|
8
|
-
|
9
|
-
|
10
|
-
Expression.new(:relative, current, expressions)
|
11
|
-
end
|
14
|
+
def root(*expressions)
|
15
|
+
Expression.new(:root, current, expressions)
|
16
|
+
end
|
12
17
|
|
13
|
-
|
14
|
-
|
15
|
-
|
18
|
+
def current
|
19
|
+
Expression.new(:this_node)
|
20
|
+
end
|
16
21
|
|
17
|
-
|
18
|
-
|
19
|
-
|
22
|
+
def descendant(*expressions)
|
23
|
+
Expression.new(:descendant, current, expressions)
|
24
|
+
end
|
20
25
|
|
21
|
-
|
22
|
-
|
23
|
-
|
26
|
+
def child(*expressions)
|
27
|
+
Expression.new(:child, current, expressions)
|
28
|
+
end
|
24
29
|
|
25
|
-
|
26
|
-
|
27
|
-
|
30
|
+
def axis(name, *element_names)
|
31
|
+
Expression.new(:axis, current, name, element_names)
|
32
|
+
end
|
28
33
|
|
29
|
-
|
30
|
-
|
31
|
-
|
34
|
+
def anywhere(*expressions)
|
35
|
+
Expression.new(:anywhere, expressions)
|
36
|
+
end
|
32
37
|
|
33
|
-
|
34
|
-
|
35
|
-
|
38
|
+
def xpath_attr(expression)
|
39
|
+
Expression.new(:attribute, current, expression)
|
40
|
+
end
|
36
41
|
|
37
|
-
|
38
|
-
|
39
|
-
|
42
|
+
def text
|
43
|
+
Expression.new(:text, current)
|
44
|
+
end
|
40
45
|
|
41
|
-
|
42
|
-
|
43
|
-
|
46
|
+
def css(selector)
|
47
|
+
Expression.new(:css, current, Literal.new(selector))
|
48
|
+
end
|
44
49
|
|
45
|
-
|
46
|
-
|
47
|
-
|
50
|
+
def function(name, *arguments)
|
51
|
+
Expression.new(:function, name, *arguments)
|
52
|
+
end
|
48
53
|
|
49
|
-
|
50
|
-
|
51
|
-
|
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
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
-
|
62
|
-
|
63
|
-
|
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
|
-
|
71
|
-
|
72
|
-
|
75
|
+
def binary_operator(name, rhs)
|
76
|
+
Expression.new(:binary_operator, name, current, rhs)
|
77
|
+
end
|
73
78
|
|
74
|
-
|
75
|
-
|
76
|
-
|
79
|
+
def union(*expressions)
|
80
|
+
Union.new(*[self, expressions].flatten)
|
81
|
+
end
|
82
|
+
alias + union
|
77
83
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
alias_method :+, :union
|
84
|
+
def last
|
85
|
+
function(:last)
|
86
|
+
end
|
82
87
|
|
83
|
-
|
84
|
-
|
85
|
-
|
88
|
+
def position
|
89
|
+
function(:position)
|
90
|
+
end
|
86
91
|
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
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
|
-
|
105
|
-
|
106
|
-
|
107
|
-
method(name, *args)
|
108
|
-
end
|
109
|
-
end
|
112
|
+
def qname
|
113
|
+
method(:name)
|
114
|
+
end
|
110
115
|
|
111
|
-
|
112
|
-
|
113
|
-
|
116
|
+
alias inverse not
|
117
|
+
alias ~ not
|
118
|
+
alias ! not
|
119
|
+
alias normalize normalize_space
|
120
|
+
alias n normalize_space
|
114
121
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
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
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
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
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
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
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
160
|
-
|
161
|
-
|
165
|
+
def contains_word(word)
|
166
|
+
function(:concat, ' ', current.normalize_space, ' ').contains(" #{word} ")
|
167
|
+
end
|
162
168
|
|
163
|
-
|
164
|
-
|
165
|
-
end
|
169
|
+
UPPERCASE_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ'
|
170
|
+
LOWERCASE_LETTERS = 'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ'
|
166
171
|
|
167
|
-
|
168
|
-
|
172
|
+
def lowercase
|
173
|
+
method(:translate, UPPERCASE_LETTERS, LOWERCASE_LETTERS)
|
174
|
+
end
|
169
175
|
|
170
|
-
|
171
|
-
|
172
|
-
|
176
|
+
def parenthesis(arg)
|
177
|
+
Expression.new(:parenthesis, arg)
|
178
|
+
end
|
173
179
|
|
174
|
-
|
175
|
-
|
176
|
-
|
180
|
+
def uppercase
|
181
|
+
method(:translate, LOWERCASE_LETTERS, UPPERCASE_LETTERS)
|
182
|
+
end
|
177
183
|
|
178
|
-
|
179
|
-
|
180
|
-
|
184
|
+
def one_of(*expressions)
|
185
|
+
expressions.map { |e| current.equals(e) }.reduce(:or)
|
186
|
+
end
|
181
187
|
|
182
|
-
|
183
|
-
|
184
|
-
|
188
|
+
def next_sibling(*expressions)
|
189
|
+
axis(:'following-sibling')[1].axis(:self, *expressions)
|
190
|
+
end
|
185
191
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
192
|
+
def previous_sibling(*expressions)
|
193
|
+
axis(:'preceding-sibling')[1].axis(:self, *expressions)
|
194
|
+
end
|
195
|
+
end
|
190
196
|
|
191
|
-
|
192
|
-
|
197
|
+
extend PaloAlto::DSL
|
198
|
+
include PaloAlto::DSL
|
193
199
|
|
194
|
-
|
195
|
-
|
196
|
-
|
200
|
+
def self.generate
|
201
|
+
yield(self)
|
202
|
+
end
|
197
203
|
|
198
|
-
|
199
|
-
|
204
|
+
class Union
|
205
|
+
include Enumerable
|
200
206
|
|
201
|
-
|
202
|
-
|
207
|
+
attr_reader :expressions
|
208
|
+
alias arguments expressions
|
203
209
|
|
204
|
-
|
205
|
-
|
206
|
-
|
210
|
+
def initialize(*expressions)
|
211
|
+
@expressions = expressions
|
212
|
+
end
|
207
213
|
|
208
|
-
|
209
|
-
|
210
|
-
|
214
|
+
def expression
|
215
|
+
:union
|
216
|
+
end
|
211
217
|
|
212
|
-
|
213
|
-
|
214
|
-
|
218
|
+
def each(&block)
|
219
|
+
arguments.each(&block)
|
220
|
+
end
|
215
221
|
|
216
|
-
|
217
|
-
|
218
|
-
|
222
|
+
def method_missing(*args) # rubocop:disable Style/MissingRespondToMissing
|
223
|
+
PaloAlto::Union.new(*arguments.map { |e| e.send(*args) })
|
224
|
+
end
|
219
225
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
226
|
+
def to_xpath(type = nil)
|
227
|
+
Renderer.render(self, type)
|
228
|
+
end
|
229
|
+
end
|
224
230
|
|
225
|
-
|
226
|
-
|
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
|
-
|
237
|
-
|
238
|
-
|
234
|
+
def initialize(value)
|
235
|
+
@value = value
|
236
|
+
end
|
237
|
+
end
|
239
238
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
239
|
+
class Renderer
|
240
|
+
def self.render(node, type)
|
241
|
+
new(type).render(node)
|
242
|
+
end
|
244
243
|
|
245
|
-
|
246
|
-
|
247
|
-
|
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
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
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
|
-
|
267
|
-
|
268
|
-
|
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
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
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
|
-
|
279
|
-
|
280
|
-
|
274
|
+
def this_node
|
275
|
+
'.'
|
276
|
+
end
|
281
277
|
|
282
|
-
|
283
|
-
|
284
|
-
|
278
|
+
def binary_operator(name, left, right)
|
279
|
+
"#{left}#{name}#{right}".gsub('./@', '@')
|
280
|
+
end
|
285
281
|
|
286
|
-
|
287
|
-
|
288
|
-
|
282
|
+
def parenthesis(arg)
|
283
|
+
"(#{arg})"
|
284
|
+
end
|
289
285
|
|
290
|
-
|
291
|
-
|
292
|
-
|
286
|
+
def root(_current, element_names)
|
287
|
+
element_names.any? ? "/#{element_names.join('/')}" : ''
|
288
|
+
end
|
293
289
|
|
294
|
-
|
295
|
-
|
296
|
-
|
290
|
+
def relative(_current, _element_names)
|
291
|
+
'.'
|
292
|
+
end
|
297
293
|
|
298
|
-
|
299
|
-
|
300
|
-
|
294
|
+
def descendant(current, element_names)
|
295
|
+
with_element_conditions("#{current}//", element_names)
|
296
|
+
end
|
301
297
|
|
302
|
-
|
303
|
-
|
304
|
-
|
298
|
+
def child(current, element_names)
|
299
|
+
with_element_conditions("#{current}/", element_names)
|
300
|
+
end
|
305
301
|
|
306
|
-
|
307
|
-
|
308
|
-
|
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
|
-
|
315
|
-
|
316
|
-
|
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
|
-
|
323
|
-
|
324
|
-
|
310
|
+
def where(on, condition)
|
311
|
+
"#{on}[#{condition}]"
|
312
|
+
end
|
325
313
|
|
326
|
-
|
327
|
-
|
328
|
-
|
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
|
-
|
331
|
-
|
332
|
-
|
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
|
-
|
335
|
-
|
336
|
-
|
337
|
-
end
|
338
|
-
union(paths)
|
339
|
-
end
|
330
|
+
def variable(name)
|
331
|
+
"%{#{name}}"
|
332
|
+
end
|
340
333
|
|
341
|
-
|
342
|
-
|
343
|
-
|
334
|
+
def text(current)
|
335
|
+
"#{current}/text()"
|
336
|
+
end
|
344
337
|
|
345
|
-
|
346
|
-
|
347
|
-
|
338
|
+
def literal(node)
|
339
|
+
node
|
340
|
+
end
|
348
341
|
|
349
|
-
|
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
|
-
|
352
|
-
|
353
|
-
|
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
|
-
|
362
|
-
|
363
|
-
|
364
|
-
end
|
365
|
-
class Expression
|
366
|
-
include PaloAlto::DSL
|
353
|
+
def function(name, *arguments)
|
354
|
+
"#{name}(#{arguments.join(', ')})"
|
355
|
+
end
|
367
356
|
|
368
|
-
|
369
|
-
def initialize(expression, *arguments)
|
370
|
-
@expression = expression
|
371
|
-
@arguments = arguments
|
372
|
-
end
|
357
|
+
private
|
373
358
|
|
374
|
-
|
375
|
-
|
376
|
-
|
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
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
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
|
-
|
385
|
-
class ConfigClass < Expression
|
386
|
-
attr_reader :api_attributes, :subclasses
|
387
|
-
attr_accessor :parent_instance
|
377
|
+
attr_accessor :expression, :arguments
|
388
378
|
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
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
|
-
|
398
|
-
|
399
|
-
|
400
|
-
@arguments = [ xpath_argument, [_section] ]
|
401
|
-
end
|
402
|
-
end
|
384
|
+
def current
|
385
|
+
self
|
386
|
+
end
|
403
387
|
|
404
|
-
|
405
|
-
|
406
|
-
|
388
|
+
def to_xpath(type = nil)
|
389
|
+
Renderer.render(self, type)
|
390
|
+
end
|
391
|
+
end
|
407
392
|
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
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
|
-
|
414
|
-
|
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
|
-
|
417
|
-
|
418
|
-
|
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
|
-
|
421
|
-
|
422
|
-
|
423
|
-
type: "config",
|
424
|
-
action: "get",
|
425
|
-
xpath: self.to_xpath
|
426
|
-
}
|
413
|
+
class << self
|
414
|
+
attr_accessor :props
|
415
|
+
end
|
427
416
|
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
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
|
-
|
438
|
-
|
439
|
-
|
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
|
-
|
444
|
-
|
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
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
429
|
+
payload = {
|
430
|
+
type: 'config',
|
431
|
+
action: 'get',
|
432
|
+
xpath: to_xpath
|
433
|
+
}
|
453
434
|
|
454
|
-
|
455
|
-
|
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
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
444
|
+
def clear!
|
445
|
+
@subclasses = {}
|
446
|
+
@values = {}
|
447
|
+
self
|
448
|
+
end
|
462
449
|
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
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
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
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
|
-
|
486
|
-
|
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
|
-
|
493
|
-
|
464
|
+
if data.xpath('//response/result/*').length != 1 && (ignore_empty_result == false)
|
465
|
+
raise(ObjectNotPresentException, "empty result: #{payload.inspect}")
|
466
|
+
end
|
494
467
|
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
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
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
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
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
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
|
-
|
495
|
+
def set_array_class_attributes(child, primary_key)
|
496
|
+
@external_values.merge!({ "@#{primary_key.keys.first}" => primary_key.values.first })
|
520
497
|
|
521
|
-
|
522
|
-
|
523
|
-
|
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
|
-
|
534
|
-
|
535
|
-
|
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
|
-
|
567
|
-
|
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
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
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
|
-
|
598
|
-
|
599
|
-
|
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
|
-
|
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
|
-
|
612
|
-
|
613
|
-
|
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
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
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
|
-
|
624
|
-
|
625
|
-
|
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
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
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
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
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
|
-
|
681
|
-
|
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
|
-
|
684
|
-
|
685
|
-
|
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
|
-
|
688
|
-
|
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
|
-
|
697
|
-
|
590
|
+
keys.map do |k|
|
591
|
+
next if k.start_with?('@')
|
698
592
|
|
699
|
-
|
700
|
-
|
593
|
+
v = prop_get(k, include_defaults: false)
|
594
|
+
next unless v
|
701
595
|
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
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
|
-
|
716
|
-
|
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
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
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
|
-
|
728
|
-
|
729
|
-
|
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
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
end
|
641
|
+
if @create_children
|
642
|
+
@subclasses[section][selector] ||= entry
|
643
|
+
else
|
644
|
+
entry
|
645
|
+
end
|
646
|
+
end
|
647
|
+
end
|
739
648
|
|
740
|
-
|
741
|
-
|
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
|
-
|
744
|
-
|
745
|
-
|
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
|
-
|
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
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
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
|
-
|
764
|
-
|
765
|
-
end
|
701
|
+
def enforce_types(prop_arr, values)
|
702
|
+
return if values.nil?
|
766
703
|
|
767
|
-
|
768
|
-
attr_accessor :selector
|
704
|
+
values = values.split(/\s+/) if has_multiple_values? && values.is_a?(String)
|
769
705
|
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
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
|
-
|
782
|
-
|
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
|
-
|
785
|
-
|
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
|
-
|
790
|
-
|
791
|
-
|
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
|
-
|
794
|
-
|
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
|
-
|
804
|
-
|
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
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
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
|
-
|
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
|