omf_sfa 0.2.5 → 0.2.6

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.
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