omf_sfa 0.2.5 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
File without changes
@@ -25,6 +25,7 @@
25
25
  }
26
26
  </style>
27
27
  <link href="/assets/css/rest_api.css" rel="stylesheet">
28
+ ##HEADER##
28
29
  </head>
29
30
  <body>
30
31
  <div class="navbar navbar-inverse navbar-fixed-top">
@@ -5,6 +5,7 @@ require 'uuid'
5
5
  require 'set'
6
6
  require 'json'
7
7
  require 'thin/async'
8
+ require 'cgi'
8
9
 
9
10
  require 'omf_base/lobject'
10
11
 
@@ -57,8 +58,8 @@ module OMF::SFA::AM::Rest
57
58
  end
58
59
 
59
60
  class UnsupportedMethodException < RackException
60
- def initialize()
61
- super 403, "Unsupported Method"
61
+ def initialize(method_name = nil, class_name = nil)
62
+ super 403, "Unsupported Method '#{class_name || 'Unknown'}::#{method_name || 'Unknown'}'"
62
63
  end
63
64
  end
64
65
 
@@ -82,6 +83,18 @@ module OMF::SFA::AM::Rest
82
83
  end
83
84
  end
84
85
 
86
+ # Raised when a request triggers an async call whose
87
+ # result we need before answering the request
88
+ #
89
+ class RetryLaterException < Exception
90
+ attr_reader :delay
91
+
92
+ def initialize(delay = 3)
93
+ @delay = delay
94
+ end
95
+ end
96
+
97
+
85
98
 
86
99
  class RestHandler < OMF::Base::LObject
87
100
  @@service_name = nil
@@ -103,6 +116,19 @@ module OMF::SFA::AM::Rest
103
116
  self.new().render_html(parts)
104
117
  end
105
118
 
119
+ # Parse format of 'resource_uri' and (re)turn into a
120
+ # description hash (optionally provided).
121
+ #
122
+ def self.parse_resource_uri(resource_uri, description = {})
123
+ if UUID.validate(resource_uri)
124
+ description[:uuid] = resource_uri
125
+ elsif resource_uri.start_with? 'urn:'
126
+ description[:urn] = resource_uri
127
+ else
128
+ description[:name] = resource_uri
129
+ end
130
+ description
131
+ end
106
132
 
107
133
  def initialize(opts = {})
108
134
  @opts = opts
@@ -112,12 +138,13 @@ module OMF::SFA::AM::Rest
112
138
  begin
113
139
  Thread.current[:http_host] = env["HTTP_HOST"]
114
140
  req = ::Rack::Request.new(env)
141
+ headers = {
142
+ 'Access-Control-Allow-Origin' => '*',
143
+ 'Access-Control-Allow-Methods' => 'GET, POST, OPTIONS',
144
+ 'Access-Control-Allow-Headers' => 'origin, x-csrftoken, content-type, accept'
145
+ }
115
146
  if req.request_method == 'OPTIONS'
116
- return [200 ,{
117
- 'Access-Control-Allow-Origin' => '*' ,
118
- 'Access-Control-Allow-Methods' => 'GET, POST, OPTIONS',
119
- 'Access-Control-Allow-Headers' => 'origin, x-csrftoken, content-type, accept'
120
- }, ""]
147
+ return [200 , headers, ""]
121
148
  end
122
149
  content_type, body = dispatch(req)
123
150
  if body.is_a? Thin::AsyncResponse
@@ -131,7 +158,8 @@ module OMF::SFA::AM::Rest
131
158
  body = JSON.pretty_generate(body)
132
159
  end
133
160
  #return [200 ,{'Content-Type' => content_type}, body + "\n"]
134
- return [200 ,{'Content-Type' => content_type, 'Access-Control-Allow-Origin' => '*' , 'Access-Control-Allow-Methods' => 'GET, POST, OPTIONS' }, body + "\n"]
161
+ headers['Content-Type'] = content_type
162
+ return [200 , headers, body + "\n"]
135
163
  rescue RackException => rex
136
164
  return rex.reply
137
165
  rescue RedirectException => rex
@@ -139,16 +167,33 @@ module OMF::SFA::AM::Rest
139
167
  return [301, {'Location' => rex.path, "Content-Type" => ""}, ['Next window!']]
140
168
  # rescue OMF::SFA::AM::AMManagerException => aex
141
169
  # return RackException.new(400, aex.to_s).reply
170
+ rescue RetryLaterException => rex
171
+ body = {
172
+ type: 'retry',
173
+ delay: rex.delay
174
+ }
175
+ debug "Retry later request"
176
+ if req['_format'] == 'html'
177
+ headers['Refresh'] = rex.delay.to_s
178
+ opts = {} #{html_header: "<META HTTP-EQUIV='refresh' CONTENT='#{rex.delay}'>"}
179
+ body = convert_to_html(body, env, opts)
180
+ return [200 , headers, body + "\n"]
181
+ end
182
+ headers['Content-Type'] = 'application/json'
183
+ return [504, headers, JSON.pretty_generate(body)]
184
+
142
185
  rescue Exception => ex
143
186
  body = {
144
- :error => {
145
- :reason => ex.to_s,
146
- :bt => ex.backtrace #.select {|l| !l.start_with?('/') }
187
+ type: 'error',
188
+ error: {
189
+ reason: ex.to_s,
190
+ bt: ex.backtrace #.select {|l| !l.start_with?('/') }
147
191
  }
148
192
  }
149
193
  warn "ERROR: #{ex}"
150
194
  debug ex.backtrace.join("\n")
151
- return [500, { "Content-Type" => 'application/json', 'Access-Control-Allow-Origin' => '*', 'Access-Control-Allow-Methods' => 'GET, POST, OPTIONS' }, JSON.pretty_generate(body)]
195
+ headers['Content-Type'] = 'application/json'
196
+ return [500, headers, JSON.pretty_generate(body)]
152
197
  end
153
198
  end
154
199
 
@@ -168,7 +213,7 @@ module OMF::SFA::AM::Rest
168
213
  #debug 'POST(', resource_uri, '): body(', format, '): "', description, '"'
169
214
 
170
215
  if resource = opts[:resource]
171
- debug 'POST: Modify ', resource
216
+ debug 'POST: Modify ', resource, ' --- ', resource.class
172
217
  modify_resource(resource, description, opts)
173
218
  else
174
219
  if description.is_a? Array
@@ -179,13 +224,13 @@ module OMF::SFA::AM::Rest
179
224
  return show_resources(resources, nil, opts)
180
225
  else
181
226
  debug 'POST: Create ', resource_uri
182
- if resource_uri
183
- if UUID.validate(resource_uri)
184
- description[:uuid] = resource_uri
185
- else
186
- description[:name] = resource_uri
187
- end
188
- end
227
+ # if resource_uri
228
+ # if UUID.validate(resource_uri)
229
+ # description[:uuid] = resource_uri
230
+ # else
231
+ # description[:name] = resource_uri
232
+ # end
233
+ # end
189
234
  resource = create_resource(description, opts, resource_uri)
190
235
  end
191
236
  end
@@ -200,6 +245,7 @@ module OMF::SFA::AM::Rest
200
245
  end
201
246
 
202
247
  def on_delete(resource_uri, opts)
248
+ res = ['application/json', {}]
203
249
  if resource = opts[:resource]
204
250
  if (context = opts[:context])
205
251
  remove_resource_from_context(resource, context)
@@ -210,17 +256,21 @@ module OMF::SFA::AM::Rest
210
256
  resource.destroy
211
257
  end
212
258
  else
213
- # Delete ALL resources of this type
214
- raise OMF::SFA::AM::Rest::BadRequestException.new "I'm sorry, Dave. I'm afraid I can't do that."
259
+ res = on_delete_all(opts) || res
215
260
  end
216
- resource.reload
217
- return res
261
+ res
218
262
  end
219
263
 
264
+ def on_delete_all(opts)
265
+ # Delete ALL resources of this type
266
+ raise OMF::SFA::AM::Rest::BadRequestException.new "I'm sorry, Dave. I'm afraid I can't do that."
267
+ end
220
268
 
221
269
  def find_handler(path, opts)
222
- debug "find_handler: path; '#{path}' opts: #{opts}"
223
- resource_id = opts[:resource_uri] = path.shift
270
+ #debug "find_handler: path; '#{path}' opts: #{opts}"
271
+ debug "find_handler: path; '#{path}'"
272
+ rid = path.shift
273
+ resource_id = opts[:resource_uri] = (rid ? URI.decode(rid) : nil) # make sure we get rid of any URI encoding
224
274
  opts[:resource] = nil
225
275
  if resource_id
226
276
  resource = opts[:resource] = find_resource(resource_id, {}, opts)
@@ -231,7 +281,8 @@ module OMF::SFA::AM::Rest
231
281
  opts[:context] = resource
232
282
  comp = path.shift
233
283
  if (handler = @coll_handlers[comp.to_sym])
234
- opts[:resource_uri] = path.join('/')
284
+ opts[:context_name] = comp
285
+ opts[:resource_uri] = URI.decode(path.join('/'))
235
286
  if handler.is_a? Proc
236
287
  return handler.call(path, opts)
237
288
  end
@@ -250,30 +301,38 @@ module OMF::SFA::AM::Rest
250
301
  end
251
302
  description.delete(:href)
252
303
  resource.update(description) ? resource : nil
253
- #raise UnsupportedMethodException.new
254
304
  end
255
305
 
256
306
 
257
307
  def create_resource(description, opts, resource_uri = nil)
258
- #debug "Create: #{description.class}--#{description}"
308
+ debug "Create: uri: '#{resource_uri.inspect}' class: #{description.class}--#{description}"
259
309
 
260
- if resource_uri
261
- if UUID.validate(resource_uri)
262
- description[:uuid] = resource_uri
263
- else
264
- description[:name] = resource_uri
310
+ query = {}
311
+ unless (resource_uri || '').empty?
312
+ query = self.class.parse_resource_uri(resource_uri, query)
313
+ description.merge!(query)
314
+ else
315
+ [:uuid, :urn, :name].each do |k|
316
+ if v = description[k]
317
+ query[k] = v
318
+ end
265
319
  end
266
320
  end
267
321
 
268
322
  # Let's find if the resource already exists. If yes, just modify it
269
- if uuid = description[:uuid]
270
- debug 'Trying to find resource ', uuid, "'"
271
- resource = @resource_class.first(uuid: uuid)
323
+ # if description[:uuid] || descri
324
+ # debug 'Trying to find resource ', uuid, "'"
325
+ # resource = @resource_class.first(uuid: uuid)
326
+ # end
327
+ unless query.empty?
328
+ debug 'Trying to find "', @resource_class, '" ', query, "'"
329
+ resource = @resource_class.first(query)
272
330
  end
273
331
  if resource
274
332
  modify_resource(resource, description, opts)
275
333
  else
276
- resource = @resource_class.create(description)
334
+ debug 'Trying to create resource ', @resource_class, ' - ', description
335
+ resource = _really_create_resource(description, opts)
277
336
  on_new_resource(resource)
278
337
  end
279
338
  if (context = opts[:context])
@@ -282,6 +341,25 @@ module OMF::SFA::AM::Rest
282
341
  return resource
283
342
  end
284
343
 
344
+ def _really_create_resource(description, opts)
345
+ @resource_class.create(description)
346
+ end
347
+
348
+ # Parse format of 'resource_uri' and (re)turn into a
349
+ # description hash (optionally provided).
350
+ #
351
+ def _parse_resource_uri(resource_uri, description = {})
352
+ if UUID.validate(resource_uri)
353
+ description[:uuid] = resource_uri
354
+ elsif resource_uri.start_with? 'urn:'
355
+ description[:urn] = resource_uri
356
+ else
357
+ description[:name] = resource_uri
358
+ end
359
+ description
360
+ end
361
+
362
+
285
363
  # Can be used to further customize a newly created
286
364
  # resource.
287
365
  #
@@ -289,12 +367,12 @@ module OMF::SFA::AM::Rest
289
367
  debug "Created: #{resource}"
290
368
  end
291
369
 
292
- def add_resource_to_context(user, context)
293
- raise UnsupportedMethodException.new
370
+ def add_resource_to_context(resource, context)
371
+ raise UnsupportedMethodException.new(:add_resource_to_context, self.class)
294
372
  end
295
373
 
296
- def remove_resource_from_context(user, context)
297
- raise UnsupportedMethodException.new
374
+ def remove_resource_from_context(resource, context)
375
+ raise UnsupportedMethodException.new(:remove_resource_from_context, self.class)
298
376
  end
299
377
 
300
378
 
@@ -305,6 +383,7 @@ module OMF::SFA::AM::Rest
305
383
  # store them in +opts+.
306
384
  #
307
385
  def populate_opts(req, opts)
386
+ opts[:req] = req
308
387
  path = req.path_info.split('/').select { |p| !p.empty? }
309
388
  opts[:target] = find_handler(path, opts)
310
389
  rl = req.params.delete('_level')
@@ -411,12 +490,12 @@ module OMF::SFA::AM::Rest
411
490
  descr.delete(:resource_uri)
412
491
  if UUID.validate(resource_uri)
413
492
  descr[:uuid] = resource_uri
493
+ elsif resource_uri.start_with?('urn')
494
+ descr[:urn] = resource_uri
414
495
  else
415
496
  descr[:name] = resource_uri
416
497
  end
417
- if resource_uri.start_with?('urn')
418
- descr[:urn] = resource_uri
419
- end
498
+
420
499
  #authenticator = Thread.current["authenticator"]
421
500
  debug "Finding #{@resource_class}.first(#{descr})"
422
501
  @resource_class.first(descr)
@@ -424,7 +503,11 @@ module OMF::SFA::AM::Rest
424
503
 
425
504
  def show_resource_list(opts)
426
505
  # authenticator = Thread.current["authenticator"]
427
- resources = @resource_class.all()
506
+ if (context = opts[:context])
507
+ resources = context.send(opts[:context_name].to_sym)
508
+ else
509
+ resources = @resource_class.all()
510
+ end
428
511
  show_resources(resources, nil, opts)
429
512
  end
430
513
 
@@ -433,9 +516,10 @@ module OMF::SFA::AM::Rest
433
516
  hopts = {max_level: opts[:max_level], level: 0}
434
517
  objs = {}
435
518
  res_hash = resources.map do |a|
519
+ next unless a # TODO: This seems to be a bug in OProperty (removing objects)
436
520
  a.to_hash(objs, hopts)
437
521
  #a.to_hash_brief(:href_use_class_prefix => true)
438
- end
522
+ end.compact
439
523
  if resource_name
440
524
  prefix = about = opts[:req].path
441
525
  res = {
@@ -488,6 +572,7 @@ module OMF::SFA::AM::Rest
488
572
  # Render an HTML page using the resource's template. The
489
573
  # template is populated with information provided in 'parts'
490
574
  #
575
+ # * :header - HTML header additions
491
576
  # * :title - HTML title
492
577
  # * :service - Service path (usually a set of <a>)
493
578
  # * :content - Main content
@@ -497,6 +582,9 @@ module OMF::SFA::AM::Rest
497
582
  def render_html(parts = {})
498
583
  #puts "PP>> #{parts}"
499
584
  tmpl = html_template()
585
+ if (header = parts[:header])
586
+ tmpl = tmpl.gsub('##HEADER##', header)
587
+ end
500
588
  if (result = parts[:result])
501
589
  tmpl = tmpl.gsub('##JS##', JSON.pretty_generate(result))
502
590
  end
@@ -532,6 +620,7 @@ module OMF::SFA::AM::Rest
532
620
  _convert_obj_to_html(body, nil, res, opts)
533
621
 
534
622
  render_html(
623
+ header: opts[:html_header] || '',
535
624
  result: body,
536
625
  title: @@service_name || env["HTTP_HOST"],
537
626
  service: h2.join('/'),
@@ -546,7 +635,7 @@ module OMF::SFA::AM::Rest
546
635
  protected
547
636
  def _convert_obj_to_html(obj, ref_name, res, opts)
548
637
  klass = obj.class
549
- #puts "CONVERT>>>> #{obj.class}::#{obj}"
638
+ #puts "CONVERT>>>> #{ref_name} ... #{obj.class}::#{obj.to_s[0 .. 80]}"
550
639
  if (obj.is_a? OMF::SFA::Resource::OPropertyArray) || obj.is_a?(Array)
551
640
  if obj.empty?
552
641
  res << '<span class="empty">empty</span>'
@@ -563,6 +652,9 @@ module OMF::SFA::AM::Rest
563
652
  if obj.to_s.start_with? 'http://'
564
653
  res << _convert_link_to_html(obj)
565
654
  else
655
+ if obj.is_a? String
656
+ obj = CGI.escapeHTML obj
657
+ end
566
658
  res << " <span class='value'>#{obj}</span> "
567
659
  end
568
660
  end
@@ -573,6 +665,9 @@ module OMF::SFA::AM::Rest
573
665
  array.each do |obj|
574
666
  #puts "AAA>>>> #{obj}::#{opts}"
575
667
  name = nil
668
+ if (obj.is_a? OMF::SFA::Resource::OResource)
669
+ obj = obj.to_hash()
670
+ end
576
671
  if obj.is_a? Hash
577
672
  if name = obj[:name] || obj[:uuid]
578
673
  res << "<li><span class='key'>#{_convert_link_to_html obj[:href], name}:</span>"
@@ -15,7 +15,7 @@ module OMF::SFA::Resource
15
15
  sfa_class 'channel', :namespace => :ol
16
16
  sfa :number, :attribute => true
17
17
  sfa :frequency, :attribute => true
18
- sfa :interfaces, :inline => true, :has_many => true
18
+ sfa :interfaces, :inline => true, :has_many => true, :inverse => :channel
19
19
 
20
20
  def _from_sfa_interfaces_property_xml(resource_el, props, context)
21
21
  resource_el.children.each do |el|
@@ -1,5 +1,5 @@
1
1
 
2
-
2
+ require 'set'
3
3
  require 'omf-sfa/resource/channel'
4
4
  #require 'omf-sfa/resource/link_property'
5
5
 
@@ -21,10 +21,25 @@ module OMF::SFA::Resource
21
21
  oproperty :packet_loss, Float # 0 .. 1
22
22
 
23
23
  sfa_class 'link'
24
- sfa :link_type, :content_attribute => :name
24
+ sfa :link_type, attr_value: 'name' #:content_attribute => :name
25
+ sfa :component_manager
25
26
  sfa :property # sets capacity, latency and packet_loss
26
27
  #sfa :properties, LinkProperty, :inline => true, :has_many => true
27
28
 
29
+ #Override xml serialization of 'component_manager'
30
+ def _to_sfa_xml_component_manager(res_el, pdef, obj2id, opts)
31
+ cms = Set.new
32
+ self.interfaces.each do |ifs|
33
+ cms << ifs.node.component_manager
34
+ end
35
+ cms.each do |cm|
36
+ next unless cm # not sure if 'nil' could show up her
37
+ el = res_el.add_child(Nokogiri::XML::Element.new('component_manager', res_el.document))
38
+ el.set_attribute('name', cm)
39
+ end
40
+
41
+ end
42
+
28
43
  #Override xml serialization of 'property'
29
44
  def _to_sfa_xml_property(res_el, pdef, obj2id, opts)
30
45
  capacity = self.capacity
@@ -9,16 +9,18 @@ module OMF::SFA::Resource
9
9
  class Node < OComponent
10
10
 
11
11
 
12
+ oproperty :component_manager, String, :required => false
12
13
  oproperty :hardware_type, String, :required => false
13
14
  oproperty :available, Boolean, :default => true
14
15
  oproperty :sliver_type, SliverType, :required => false # Is this required?
15
- oproperty :interfaces, :interface, :functional => false
16
+ oproperty :interfaces, :interface, :functional => false, :inverse => :node
16
17
  oproperty :exclusive, Boolean, :default => true
17
18
  oproperty :services, OMF::SFA::Resource::AbstractService, functional: false
18
19
 
19
20
  #belongs_to :sliver
20
21
 
21
22
  sfa_class 'node'
23
+ sfa :component_manager, attr_value: 'name'
22
24
  sfa :hardware_type, :inline => true, :has_many => true
23
25
  sfa :available, attr_value: 'now', in_request: false # <available now="true">
24
26
  #sfa :sliver_type, :attr_value => 'name'
@@ -28,6 +30,7 @@ module OMF::SFA::Resource
28
30
  sfa :services, :has_many => true
29
31
 
30
32
 
33
+
31
34
  # Override xml serialization of 'interface'
32
35
  def _to_sfa_property_xml(pname, value, res_el, pdef, obj2id, opts)
33
36
  if pname == 'interfaces'
@@ -8,26 +8,26 @@ require 'omf_base/lobject'
8
8
  # and overrides Time objects serialization. We want 'JSON.load' to return actual Time
9
9
  # objects instead of Strings.
10
10
  #
11
- class Time
12
- def to_json(*args)
13
- {
14
- JSON.create_id => self.class.name,
15
- 's' => tv_sec,
16
- 'n' => respond_to?(:tv_nsec) ? tv_nsec : tv_usec * 1000
17
- }.to_json(*args)
18
- end
19
-
20
- def self.json_create(object)
21
- if usec = object.delete('u') # used to be tv_usec -> tv_nsec
22
- object['n'] = usec * 1000
23
- end
24
- if instance_methods.include?(:tv_nsec)
25
- at(object['s'], Rational(object['n'], 1000))
26
- else
27
- at(object['s'], object['n'] / 1000)
28
- end
29
- end
30
- end
11
+ # class Time
12
+ # def to_json(*args)
13
+ # {
14
+ # JSON.create_id => self.class.name,
15
+ # 's' => tv_sec,
16
+ # 'n' => respond_to?(:tv_nsec) ? tv_nsec : tv_usec * 1000
17
+ # }.to_json(*args)
18
+ # end
19
+ #
20
+ # def self.json_create(object)
21
+ # if usec = object.delete('u') # used to be tv_usec -> tv_nsec
22
+ # object['n'] = usec * 1000
23
+ # end
24
+ # if instance_methods.include?(:tv_nsec)
25
+ # at(object['s'], Rational(object['n'], 1000))
26
+ # else
27
+ # at(object['s'], object['n'] / 1000)
28
+ # end
29
+ # end
30
+ # end
31
31
 
32
32
  #raise "JSON deserialisation no longer working - require 'json' early" unless JSON.load(Time.now.to_json).is_a? Time
33
33
 
@@ -42,35 +42,27 @@ module OMF::SFA::Resource
42
42
 
43
43
  property :name, String
44
44
  property :type, String, length: 2
45
- property :s_value, String # actually serialized Object
45
+ property :s_value, Text, :lazy => false # actually serialized Object
46
46
  property :n_value, Float
47
47
 
48
48
  belongs_to :o_resource
49
49
 
50
- def self.prop_all(query, opts = {}, resource_class = nil)
51
- i = 0
52
- where = query.map do |pn, v|
53
- h = _analyse_value(v)
54
- tbl = "p#{i}"
55
- i += 1
56
- if (val = h[:v]).is_a? String
57
- val = "'#{val}'"
58
- end
59
- "#{tbl}.#{h[:f]} #{h[:t] == 's' ? 'LIKE' : '='} #{val}"
60
- end
61
- i.times do |j|
62
- where << "r.id = p#{j}.o_resource_id"
50
+ def self.create(attr = {})
51
+ if (value = attr.delete(:value))
52
+ h = self._analyse_value(value)
53
+ attr[h[:f]] = h[:v]
54
+ attr[:type] = h[:t]
63
55
  end
64
- where << "r.type = '#{resource_class}'" if resource_class
56
+ super
57
+ end
65
58
 
66
- table = storage_names[:default]
67
- from = i.times.map {|j| "#{table} AS p#{j}" }
68
- from << "omf_sfa_resource_o_resources AS r" # TODO: Shouldn't hard-code that
59
+ def self.prop_all(query, opts = {}, resource_class = nil)
60
+ from, where = self._build_query(query, resource_class)
69
61
  q = "SELECT DISTINCT r.id, r.type, r.uuid, r.name FROM #{from.join(', ')} WHERE #{where.join(' AND ')};"
70
62
  if l = opts[:limit]
71
63
  q += " LIMIT #{l} OFFSET #{opts[:offset] || 0}"
72
64
  end
73
- debug "prop_all q: #{q}"
65
+ #debug "prop_all q: #{q}"
74
66
  res = repository(:default).adapter.select(q)
75
67
  ores = res.map do |qr|
76
68
  if resource_class
@@ -83,6 +75,63 @@ module OMF::SFA::Resource
83
75
  ores
84
76
  end
85
77
 
78
+ def self.count(query)
79
+ from, where = self._build_query(query)
80
+ q = "SELECT COUNT(r.id) FROM #{from.join(', ')} WHERE #{where.join(' AND ')};"
81
+ res = repository(:default).adapter.select(q)
82
+ #debug "count res: #{res} q: #{query} sql: #{q}"
83
+ res[0]
84
+ end
85
+
86
+ # Query:
87
+ # resource: Resource to find properties for
88
+ # name: Name of property
89
+ # value: Value of property
90
+ #
91
+ # Return the FROM and WHERE elements for 'query'
92
+ #
93
+ # TODO: THIS IS REALLY BROKEN! Need to define what a query is in this context
94
+ #
95
+ def self._build_query(query, resource_class = nil)
96
+ i = 0
97
+ where = query.map do |pn, v|
98
+ tbl = "p#{i}"
99
+ case pn.to_sym
100
+ when :resource
101
+ unless v.is_a? OResource
102
+ raise "Expected type OResource for :resource, but got '#{v}::#{v.class}'"
103
+ end
104
+ "#{tbl}.o_resource_id = #{v.id}"
105
+ when :name
106
+ "#{tbl}.name = '#{v}'"
107
+ else
108
+ h = _analyse_value(v)
109
+ i += 1
110
+ if (val = h[:v]).is_a? String
111
+ val = "'#{val}'"
112
+ end
113
+ "#{tbl}.#{h[:f]} #{h[:t] == 's' ? 'LIKE' : '='} #{val}"
114
+ end
115
+ end
116
+
117
+ # TODO: Hack!!!
118
+ unless i <= 1
119
+ raise "Are you using the query facility on OProperties correctly? (#{i})"
120
+ else
121
+ i = 1
122
+ end
123
+
124
+ i.times do |j|
125
+ where << "r.id = p#{j}.o_resource_id"
126
+ end
127
+ where << "r.type = '#{resource_class}'" if resource_class
128
+
129
+ table = storage_names[:default]
130
+ from = i.times.map {|j| "#{table} AS p#{j}" }
131
+ from << "omf_sfa_resource_o_resources AS r" # TODO: Shouldn't hard-code that
132
+ [from, where]
133
+ end
134
+
86
135
  @@name2class = {}
87
136
  def self._create_resource(query_result)
88
137
  qr = query_result
@@ -102,31 +151,12 @@ module OMF::SFA::Resource
102
151
 
103
152
  def value=(val)
104
153
  h = self.class._analyse_value(val)
154
+ #puts "VALUE>>> #{h}"
105
155
  attribute_set(h[:f], h[:v])
106
156
  attribute_set(:type, h[:t])
107
157
  save
108
158
  end
109
159
 
110
- # if val.is_a? Numeric
111
- # attribute_set(:n_value, val)
112
- # attribute_set(:type, (val.is_a? Integer) ? 'i' : 'f')
113
- # elsif val.is_a? String
114
- # attribute_set(:s_value, val)
115
- # attribute_set(:type, 's')
116
- # elsif val.is_a? OResource
117
- # attribute_set(:s_value, val.uuid.to_s)
118
- # attribute_set(:type, 'r')
119
- # elsif val.is_a? Time
120
- # attribute_set(:n_value, val.to_i)
121
- # attribute_set(:type, 't')
122
- # else
123
- # puts "OOOOO INSETRT (#{attribute_get(:name)})> #{val.class}"
124
- # attribute_set(:s_value, JSON.generate([val]))
125
- # attribute_set(:type, 'o')
126
- # end
127
- # save
128
- # end
129
-
130
160
  def self._analyse_value(val)
131
161
 
132
162
  if val.is_a? Numeric
@@ -233,18 +263,41 @@ module OMF::SFA::Resource
233
263
 
234
264
  end # OProperty
235
265
 
266
+
236
267
  class OPropertyArray
268
+
237
269
  def <<(val)
238
- #puts ">>> Adding #{val} to #{@name} - #{@on_set_block}"
239
- p = OProperty.create(name: @name, o_resource: @resource)
270
+ #puts "------------------ Checking #{@resource.name} => #{@name}"
240
271
  if @on_set_block
241
272
  val = @on_set_block.call(val)
242
273
  return if val.nil? #
243
274
  end
244
- p.value = val
275
+ if val.is_a? OResource
276
+ # Make sure we only have a single reference
277
+ return if OProperty.count(name: @name, resource: @resource, value: val) > 0
278
+ end
279
+ #puts ">>> Adding #{val} to #{@name} - #{@on_set_block}"
280
+ p = OProperty.create(name: @name, o_resource: @resource, value: val)
281
+ if @on_modified_block
282
+ @on_modified_block.call(val, true)
283
+ end
284
+ #p.value = val
245
285
  self
246
286
  end
247
287
 
288
+ def delete(val)
289
+ # this is rather inefficient
290
+ p = OProperty.all(name: @name, o_resource: @resource).find do |p|
291
+ p.value == val
292
+ end
293
+ return nil unless p
294
+ p.destroy
295
+ if @on_removed_block
296
+ @on_removed_block.call(val)
297
+ end
298
+ val
299
+ end
300
+
248
301
  # Delete all members
249
302
  def clear
250
303
  OProperty.all(name: @name, o_resource: @resource).destroy
@@ -268,7 +321,8 @@ module OMF::SFA::Resource
268
321
  end
269
322
 
270
323
  def length
271
- OProperty.count(name: @name, o_resource: @resource)
324
+ #raise "LENGTH"
325
+ OProperty.count(name: @name, resource: @resource)
272
326
  end
273
327
 
274
328
  def empty?
@@ -277,8 +331,12 @@ module OMF::SFA::Resource
277
331
 
278
332
  # Callback to support 'reverse' operation
279
333
  def on_modified(&block)
280
- raise "Not implemented"
281
- #@on_modified_block = block
334
+ #raise "Not implemented"
335
+ @on_modified_block = block
336
+ end
337
+
338
+ def on_removed(&block)
339
+ @on_removed_block = block
282
340
  end
283
341
 
284
342
  def on_set(&block)
@@ -299,6 +357,10 @@ module OMF::SFA::Resource
299
357
  "<#{self.class}: name=#{@name} resource=#{@resource.name || @resource.uuid} >"
300
358
  end
301
359
 
360
+ def method_missing(m, *args, &block)
361
+ self.to_a().send(m, &block)
362
+ end
363
+
302
364
  def initialize(resource, name)
303
365
  @resource = resource
304
366
  @name = name
@@ -3,6 +3,7 @@ require 'dm-core'
3
3
  require 'dm-types'
4
4
  require 'dm-validations'
5
5
  require 'dm-aggregates'
6
+ require 'dm_noisy_failures'
6
7
 
7
8
  require 'omf_base/lobject'
8
9
  require 'set'
@@ -271,7 +272,7 @@ module OMF::SFA::Resource
271
272
  alias_method :[], :oproperty_get
272
273
 
273
274
  def oproperty_set(pname, value, type = nil)
274
- #puts "OPROPERTY_SET pname:'#{pname}', value:'#{value.class}'::#{type}, self:'#{self.inspect}'"
275
+ #puts "OPROPERTY_SET pname:'#{pname}', value:'#{value}'::#{value.class}::#{type}, self:'#{self.inspect}'"
275
276
  pname = pname.to_sym
276
277
  if pname == :name
277
278
  self.name = value
@@ -31,6 +31,7 @@ module OMF::SFA
31
31
  @@sfa_classes = {}
32
32
  @@sfa_name2class = {}
33
33
  @@sfa_suppress_id = {}
34
+ @@sfa_suppress_uuid = {}
34
35
 
35
36
  #
36
37
  # @opts
@@ -74,6 +75,14 @@ module OMF::SFA
74
75
  @@sfa_suppress_id[self] == true
75
76
  end
76
77
 
78
+ def sfa_suppress_uuid
79
+ @@sfa_suppress_uuid[self] = true
80
+ end
81
+
82
+ def sfa_suppress_uuid?
83
+ @@sfa_suppress_uuid[self] == true
84
+ end
85
+
77
86
  # Define a SFA property
78
87
  #
79
88
  # @param [Symbol] name name of resource in RSpec
@@ -467,6 +476,11 @@ module OMF::SFA
467
476
  unless opts[:suppress_id] || self.class.sfa_suppress_id?
468
477
  new_element.set_attribute('id', id) #if detail_level > 0
469
478
  end
479
+
480
+ unless opts[:suppress_uuid] || self.class.sfa_suppress_uuid?
481
+ new_element.set_attribute('uuid', self.uuid) #if detail_level > 0
482
+ end
483
+
470
484
  #if href = self.href(opts)
471
485
  # new_element.set_attribute('omf:href', href)
472
486
  #end
@@ -0,0 +1,160 @@
1
+ #
2
+ # Load topology from BRITE file
3
+ #
4
+
5
+ require 'omf_sfa'
6
+
7
+ # BRITE format
8
+ #
9
+ # Topology: ( [numNodes] Nodes, [numEdges] Edges )
10
+ # Model ( [ModelNum] ): [Model.toString()]
11
+ #
12
+ # Nodes: ([numNodes]):
13
+ # [NodeID] [x-coord] [y-coord] [inDegree] [outDegree] [ASid] [type]
14
+ # [NodeID] [x-coord] [y-coord] [inDegree] [outDegree] [ASid] [type]
15
+ # [NodeID] [x-coord] [y-coord] [inDegree] [outDegree] [ASid] [type]
16
+ # ...
17
+ #
18
+ # Edges: ([numEdges]):
19
+ # [EdgeID] [fromNodeID] [toNodeID] [Length] [Delay] [Bandwidth] [ASFromNodeID] [ASToNodeID] [EdgeType] [Direction]
20
+ # [EdgeID] [fromNodeID] [toNodeID] [Length] [Delay] [Bandwidth] [ASFromNodeID] [ASToNodeID] [EdgeType] [Direction]
21
+ # [EdgeID] [fromNodeID] [toNodeID] [Length] [Delay] [Bandwidth] [ASFromNodeID] [ASToNodeID] [EdgeType] [Direction]
22
+ #
23
+ module OMF::SFA::Util
24
+ class BriteParser < OMF::Base::LObject
25
+
26
+ def initialize()
27
+ @nodes = {}
28
+ @edges = []
29
+ #@sliver = OMF::SFA::Resource::Sliver.def_sliver
30
+
31
+ end
32
+
33
+ def on_new_node(&block)
34
+ @on_new_node = block
35
+ end
36
+
37
+ def on_new_edge(&block)
38
+ @on_new_edge = block
39
+ end
40
+
41
+ def create_node(opts)
42
+ node = @on_new_node.call(opts)
43
+ @nodes[opts[:id]] = node if node
44
+ end
45
+
46
+ def create_edge(opts)
47
+ from = @nodes[opts[:from]]
48
+ to = @nodes[opts[:to]]
49
+ edge = @on_new_edge.call(opts, from, to)
50
+ @edges << edge if edge
51
+ end
52
+
53
+ def to_rspec()
54
+ OComponent.to_rspec(@nodes.values() + @edges, :request, suppress_id: true)
55
+ end
56
+
57
+ def parse_file(file_name)
58
+ f = File.open(File.absolute_path(file_name))
59
+ sp = [
60
+ lambda {|l, i| _parse_header(l, i)},
61
+ lambda {|l, i| _parse_nodes(l, i)},
62
+ lambda {|l, i| _parse_edges(l, i)},
63
+ ]
64
+ p = sp.shift
65
+ i = 0
66
+ f.each do |l|
67
+ if l.strip!.empty?
68
+ next if i == 0 # skip multiple consectutive empty lines
69
+ p = sp.shift
70
+ i = 0
71
+ next
72
+ end
73
+ p.call(l, i)
74
+ i += 1
75
+ end
76
+ end
77
+
78
+ def _parse_header(l, i)
79
+ case l
80
+ when /^Topology/
81
+ # ignore Topology: ( 111 Nodes, 111 Edges )
82
+ when /^Model/
83
+ unless m = l.match(/Model\W*([\d]*)\W*:*(.*)/)
84
+ fatal "Missing 'Model' declaration in header"
85
+ exit -1
86
+ end
87
+ @model_type = m[1]
88
+ @model_opts = m[2]
89
+ else
90
+ warn "Ignoring unexpected header line - #{l}"
91
+ end
92
+ end
93
+
94
+ def _parse_nodes(l, i)
95
+ return if i == 0
96
+
97
+ unless m = l.match(/([\d]+)\s+([\d\.]+)\s+([\d\.]+)\s+([\d]+)\s+([\d]+)\s+([\d\-]+)\s+(.*)/)
98
+ fatal "Can't parse node declaration - #{l}"
99
+ exit -1
100
+ end
101
+ if (pa = m.to_a[1 .. -1]).length != 7
102
+ fatal "Expected 7 parameters in node declaration, but got '#{pa.length}' - #{l}"
103
+ exit -1
104
+ end
105
+ # [NodeID] [x-coord] [y-coord] [inDegree] [outDegree] [ASid] [type]
106
+ n = {}
107
+ [[:id, :i], [:x, :f], [:y, :f], nil, nil, nil, [:type]].each_with_index do |k, i|
108
+ next if k.nil?
109
+
110
+ v = pa[i]
111
+ case k[1]
112
+ when :i
113
+ v = v.to_i
114
+ when :f
115
+ v = v.to_f
116
+ else
117
+ v.strip!
118
+ end
119
+ #puts "name: #{name} i: #{i}"
120
+ n[k[0]] = v
121
+ end
122
+ create_node(n)
123
+ #puts "NODES - #{n}"
124
+ end
125
+
126
+ def _parse_edges(l, i)
127
+ return if i == 0
128
+ unless m = l.match(/([\d]+)\s+([\d]+)\s+([\d]+)\s+([\d\.]+)\s+([\d\.]+)\s+([\d\.]+)\s+([\d\-]+)\s+([\d\-]+)\s+([^\s]+)\s+([^\s]+)/)
129
+ fatal "Can't parse edge declaration - #{l}"
130
+ exit -1
131
+ end
132
+ if (pa = m.to_a[1 .. -1]).length != 10
133
+ fatal "Expected 10 parameters in edge declaration, but got '#{pa.length}' - #{pa}"
134
+ exit -1
135
+ end
136
+ # [EdgeID] [fromNodeID] [toNodeID] [Length] [Delay] [Bandwidth] [ASFromNodeID] [ASToNodeID] [EdgeType] [Direction]
137
+ e = {}
138
+ [[:id, :i], [:from, :i], [:to, :i], [:length, :f], [:delay, :f], [:bw, :f], nil, nil, [:type], [:direction]].each_with_index do |k, i|
139
+ next if k.nil?
140
+
141
+ v = pa[i]
142
+ case k[1]
143
+ when :i
144
+ v = v.to_i
145
+ when :f
146
+ v = v.to_f
147
+ else
148
+ v.strip!
149
+ end
150
+ #puts "name: #{name} i: #{i}"
151
+ e[k[0]] = v
152
+ end
153
+ create_edge(e)
154
+ #@edges << e
155
+ #puts "EDGES - #{e}"
156
+ end
157
+
158
+ end
159
+ end
160
+
@@ -0,0 +1,277 @@
1
+
2
+ require 'json'
3
+ require 'omf_base'
4
+ require 'omf-sfa/resource'
5
+ include OMF::SFA::Resource
6
+
7
+
8
+ module OMF::SFA::Util
9
+
10
+ class GraphJSONException < Exception
11
+
12
+ end
13
+
14
+
15
+ # This class handles the convertion between GraphJson
16
+ # and a set of resources.
17
+ #
18
+ # Usage:
19
+ # GraphJson.parse_file(file_name) => Array of OResources
20
+ #
21
+ class GraphJSON < OMF::Base::LObject
22
+
23
+ def self.parse_file(file_name, opts = {})
24
+ content = File.open(file_name).read()
25
+ self.new.parse(JSON.parse(content, symbolize_names: true), opts)
26
+ end
27
+
28
+ # Parse a hash following the GraphJSON format and return a
29
+ # list od resources.
30
+ #
31
+ # * opts
32
+ # - :node_services Services to add to each node (default: [])
33
+ # - :create_new_uuids Don't use '_id' for UUID, create new ones
34
+ #
35
+ def parse(descr_hash, opts = {})
36
+ @create_new_uuids = (opts[:create_new_uuids] == true)
37
+ unless graph = descr_hash[:graph]
38
+ raise GraphJSONException.new "Expected description 'graph' element at root - #{descr_hash}"
39
+ end
40
+ [:nodes, :edges].each do |type|
41
+ unless graph[type]
42
+ raise GraphJSONException.new "Missing '#{type}' declaration"
43
+ end
44
+ graph[type].each do |e|
45
+ unless id = e[:_id]
46
+ raise GraphJSONException.new "Missing '_id' for #{type} - #{e}"
47
+ end
48
+ if @id2descr.key? id
49
+ raise GraphJSONException.new "Duplicated id '#{id}' detected - #{e}"
50
+ end
51
+ @id2descr[id] = e
52
+ end
53
+ end
54
+ parse_defaults(graph, opts)
55
+ parse_nodes(graph[:nodes], opts)
56
+ parse_edges(graph, opts)
57
+ #puts ">>>>> #{@resources}"
58
+ @resources
59
+ end
60
+
61
+ def initialize()
62
+ @id2descr = {}
63
+ @resources = {}
64
+ @sliver_types = {}
65
+ end
66
+
67
+ def parse_defaults(graph, opts)
68
+ @defaults = {node: {}, interface: {}, network: {}}
69
+ (graph[:defaults] || {}).each do |type, h|
70
+ type_def = @defaults[type.to_sym] ||= {}
71
+ h.each do |name, id|
72
+ unless ref = @id2descr[id]
73
+ raise GraphJSONException.new "Defaults refer to unknown id '#{id}'"
74
+ end
75
+ unless val = ref[name]
76
+ raise GraphJSONException.new "Defaults refer to unspecified property '#{name}' in '#{id}' - #{ref}"
77
+ end
78
+ type_def[name] = val
79
+ #puts "#{type}::#{name} ===> #{val}"
80
+ end
81
+ end
82
+ end
83
+
84
+ def parse_nodes(nodes, opts)
85
+ nodes.each do |n|
86
+ unless type = n[:_type]
87
+ raise GraphJSONException.new "Missing '_type' declaration - #{n}"
88
+ end
89
+ case type
90
+ when 'node'
91
+ parse_node(n, opts)
92
+ when 'network'
93
+ parse_network(n, opts)
94
+ else
95
+ raise GraphJSONException.new "Unknown node type '#{type}' - #{n}"
96
+ end
97
+ end
98
+ end
99
+
100
+ def parse_node(node, gopts)
101
+ el_defaults = @defaults[:node]
102
+ opts = {}
103
+ unless id = node[:_id]
104
+ raise GraphJSONException.new "Missing node ID '_id' - #{node}"
105
+ end
106
+ opts[:uuid] = id unless @create_new_uuids
107
+ opts[:name] = node[:name]
108
+ parse_value(node, :component_manager, el_defaults, opts, false)
109
+ parse_value(node, :urn, el_defaults, opts, false)
110
+ opts[:sliver_type] = parse_sliver_type(node, el_defaults)
111
+
112
+ @resources[id] = node_r = Node.create(opts)
113
+ (gopts[:node_services] || []).each do |s|
114
+ node_r.services << s
115
+ end
116
+ node_r
117
+ end
118
+
119
+ def parse_network(network, opts)
120
+ el_defaults = @defaults[:network]
121
+ # add defaults
122
+ parse_value(network, :netmask, el_defaults, network, false)
123
+ parse_value(network, :type, el_defaults, network, false)
124
+ end
125
+
126
+ def parse_edges(graph, gopts)
127
+ # First collect interfaces into node declaration
128
+ graph[:edges].each do |e|
129
+ [[:_source, :tail, :_target], [:_target, :head, :_source]].each do |n_id, if_id, opp_id|
130
+ n_descr = @id2descr[e[n_id]]
131
+ next unless n_descr[:_type] == "node"
132
+ if_a = (n_descr[:__ifs] ||= [])
133
+ if_a << (if_descr = e[if_id] || {})
134
+ opp_descr = @id2descr[e[opp_id]]
135
+ if opp_descr[:_type] == "network"
136
+ if_descr[:__nw] = opp_descr
137
+ (opp_descr[:__ifs] ||= []) << if_descr
138
+ end
139
+ (e[:__ifs] ||= []) << if_descr
140
+ end
141
+ end
142
+
143
+ #
144
+ graph[:nodes].each do |n_descr|
145
+ next unless n_descr[:_type] == "node"
146
+ node_id = n_descr[:_id]
147
+ if_a = n_descr[:__ifs]
148
+
149
+ # Add names to all interfaces
150
+ names = if_a.map {|ifd| ifd[:name] }.compact
151
+ i = 0
152
+ if_a.each do |ifs|
153
+ next if ifs[:name] # ok, has one already
154
+ begin
155
+ name = "if#{i}"
156
+ i += 1
157
+ end while names.include?(name)
158
+ ifs[:name] = name
159
+ end
160
+
161
+ # Create interface resource
162
+ node_r = @resources[node_id]
163
+ if_a.each do |ifs|
164
+
165
+ opts = { name: (ifs[:__client_id] = "#{node_r.name}:#{ifs[:name]}") }
166
+ if ip_decl = ifs[:ip]
167
+ if ip_decl.key? :type
168
+ ip_decl[:ip_type] = ip_decl.delete(:type)
169
+ end
170
+ #puts "IP>>> #{ip_decl}"
171
+ opts[:ip] = Ip.create(ip_decl)
172
+ else
173
+
174
+ # TODO: Maybe create IP address if the other end is a network
175
+ if nw = ifs[:__nw]
176
+ idx = nw[:__ifs].index do |oifs|
177
+ ifs[:__client_id] == oifs[:__client_id]
178
+ end
179
+ #puts "\n#{idx}\n"
180
+ end
181
+ end
182
+ if_r = ifs[:__if_r] = Interface.create(opts)
183
+ node_r.interfaces << if_r
184
+ end
185
+
186
+ end
187
+
188
+ # Create Link resources
189
+ graph[:edges].each do |e|
190
+ source = @id2descr[e[:_source]]
191
+ target = @id2descr[e[:_target]]
192
+ unless source && target
193
+ raise GraphJSONException.new "Can't find source or target node - #{e}"
194
+ end
195
+ if source[:_type] == 'node' && target[:_type] == 'node'
196
+ # direct link
197
+ opts = {}
198
+ unless id = e[:_id]
199
+ raise GraphJSONException.new "Missing edge ID '_id' - #{e}"
200
+ end
201
+ opts[:uuid] = id unless @create_new_uuids
202
+ opts[:name] = e[:name] #|| id
203
+ link_r = Link.create(opts)
204
+ @resources[id] = link_r
205
+ elsif source[:_type] == 'network' && target[:_type] == 'network'
206
+ raise GraphJSONException.new "Can't connect two networks directly - #{e}"
207
+ else
208
+ # one side is a network
209
+ network = source[:_type] == 'network' ? source : target
210
+ unless link_r = @resources[nw_id = network[:_id]]
211
+ opts = {name: network[:name]}
212
+ opts[:uuid] = nw_id unless @create_new_uuids
213
+ link_r = Link.create(opts)
214
+ @resources[nw_id] = link_r
215
+ end
216
+ end
217
+ if link_r
218
+ link_r.link_type = e[:link_type] || "lan"
219
+ e[:__ifs].each do |ifs|
220
+ link_r.interfaces << ifs[:__if_r]
221
+ end
222
+ end
223
+
224
+ end
225
+ end
226
+
227
+ def parse_sliver_type(node, el_defaults)
228
+ sliver_type = parse_value(node, :sliver_type, el_defaults, nil, true)
229
+ disk_image_url = parse_value(node, :disk_image, el_defaults, nil, true)
230
+ id = "#{sliver_type}-#{disk_image_url}"
231
+ unless st_res = @sliver_types[id]
232
+ di = DiskImage.create(url: disk_image_url)
233
+ st_res = @sliver_types[id] = SliverType.create(name: sliver_type, disk_image: di)
234
+ end
235
+ st_res
236
+ end
237
+
238
+
239
+ def parse_value(el, name, defaults, opts, is_mandatory = false)
240
+ val = el[name] || defaults[name]
241
+ if is_mandatory && val.nil?
242
+ raise GraphJSONException.new "Can't find value for mandatory property '#{name}' in '#{el}'"
243
+ end
244
+ if opts && !val.nil?
245
+ opts[name.to_sym] = val
246
+ end
247
+ val
248
+ end
249
+
250
+ end
251
+
252
+ end
253
+
254
+ if $0 == __FILE__
255
+
256
+ OMF::Base::Loggable.init_log 'graph_json'
257
+
258
+ GURN.default_domain = "urn:publicid:IDN+acme.org"
259
+ OMF::SFA::Resource::OResource.init()
260
+
261
+ file = ARGV[0] || File.join(File.dirname(__FILE__), '/../../../examples/four_node_one_network.gjson')
262
+ begin
263
+ opts = {
264
+ node_services: [
265
+ InstallService.create(install_path: "/local", url: "http://emmy9.casa.umass.edu/InstaGENI_Images/install-script.tar.gz"),
266
+ ExecuteService.create(command: "sudo sh /local/postboot_script.sh", shell: "sh")
267
+ ],
268
+ create_new_uuids: false
269
+ }
270
+ resources = OMF::SFA::Util::GraphJSON.parse_file(file, opts)
271
+ #puts resources
272
+ rspec = OComponent.to_rspec(resources.values, :request, suppress_id: true)
273
+ puts rspec
274
+ rescue OMF::SFA::Util::GraphJSONException => ex
275
+ puts "ERROR: #{ex}"
276
+ end
277
+ end
@@ -1,4 +1,4 @@
1
1
  module OMF; module SFA
2
2
  #VERSION = "6.0.0.pre.1"
3
- VERSION = "0.2.5"
3
+ VERSION = "0.2.6"
4
4
  end; end
data/omf_sfa.gemspec CHANGED
@@ -32,6 +32,7 @@ Gem::Specification.new do |s|
32
32
  s.add_runtime_dependency "dm-validations", "~> 1.2.0"
33
33
  s.add_runtime_dependency "dm-migrations", "~> 1.2.0"
34
34
  s.add_runtime_dependency "dm-sqlite-adapter", "~> 1.2.0"
35
+ s.add_runtime_dependency 'dm-noisy-failures'
35
36
  s.add_runtime_dependency "uuid", "~> 2.3.5"
36
37
  s.add_runtime_dependency "json", "~> 1.7.7"
37
38
  #
@@ -45,4 +46,7 @@ Gem::Specification.new do |s|
45
46
  s.add_runtime_dependency "omf_base", "~> 1.0.3"
46
47
  s.add_runtime_dependency "eventmachine", "~> 1.0.3"
47
48
  s.add_runtime_dependency "em-minitest-spec", "~> 1.1.1"
49
+ s.add_runtime_dependency "ruby-ip"
50
+
51
+
48
52
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omf_sfa
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.2.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-05-21 00:00:00.000000000 Z
12
+ date: 2014-08-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
@@ -219,6 +219,22 @@ dependencies:
219
219
  - - ~>
220
220
  - !ruby/object:Gem::Version
221
221
  version: 1.2.0
222
+ - !ruby/object:Gem::Dependency
223
+ name: dm-noisy-failures
224
+ requirement: !ruby/object:Gem::Requirement
225
+ none: false
226
+ requirements:
227
+ - - ! '>='
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ type: :runtime
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ none: false
234
+ requirements:
235
+ - - ! '>='
236
+ - !ruby/object:Gem::Version
237
+ version: '0'
222
238
  - !ruby/object:Gem::Dependency
223
239
  name: uuid
224
240
  requirement: !ruby/object:Gem::Requirement
@@ -395,10 +411,27 @@ dependencies:
395
411
  - - ~>
396
412
  - !ruby/object:Gem::Version
397
413
  version: 1.1.1
414
+ - !ruby/object:Gem::Dependency
415
+ name: ruby-ip
416
+ requirement: !ruby/object:Gem::Requirement
417
+ none: false
418
+ requirements:
419
+ - - ! '>='
420
+ - !ruby/object:Gem::Version
421
+ version: '0'
422
+ type: :runtime
423
+ prerelease: false
424
+ version_requirements: !ruby/object:Gem::Requirement
425
+ none: false
426
+ requirements:
427
+ - - ! '>='
428
+ - !ruby/object:Gem::Version
429
+ version: '0'
398
430
  description: OMF's Aggregate manager with SFA and new REST API.
399
431
  email:
400
432
  - omf-user@lists.nicta.com.au
401
433
  executables:
434
+ - brite2rspec.rb
402
435
  - parse_rspec.rb
403
436
  extensions: []
404
437
  extra_rdoc_files: []
@@ -407,9 +440,9 @@ files:
407
440
  - Gemfile
408
441
  - README.md
409
442
  - Rakefile
443
+ - bin/brite2rspec.rb
410
444
  - bin/parse_rspec.rb
411
445
  - etc/omf-sfa/omf-sfa-am.yaml
412
- - examples/brite2rspec.rb
413
446
  - examples/exogeni5nodemanifest.rspec
414
447
  - examples/instageni5nodemanifest.rspec
415
448
  - examples/waxman_10.brite
@@ -472,7 +505,9 @@ files:
472
505
  - lib/omf-sfa/resource/sfa_base.rb
473
506
  - lib/omf-sfa/resource/sliver_type.rb
474
507
  - lib/omf-sfa/resource/user.rb
508
+ - lib/omf-sfa/util/brite_parser.rb
475
509
  - lib/omf-sfa/util/create_sample_testbed.rb
510
+ - lib/omf-sfa/util/graph_json.rb
476
511
  - lib/omf-sfa/util/load_from_sfa_xml.rb
477
512
  - lib/omf-sfa/version.rb
478
513
  - lib/omf_sfa.rb