occi-core 4.1.3 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. data/.gitignore +1 -0
  2. data/Gemfile +8 -0
  3. data/README.md +49 -17
  4. data/lib/occi/collection.rb +37 -21
  5. data/lib/occi/core/action.rb +5 -5
  6. data/lib/occi/core/action_instance.rb +45 -3
  7. data/lib/occi/core/actions.rb +2 -1
  8. data/lib/occi/core/attributes.rb +253 -73
  9. data/lib/occi/core/categories.rb +1 -0
  10. data/lib/occi/core/category.rb +25 -8
  11. data/lib/occi/core/entities.rb +1 -0
  12. data/lib/occi/core/entity.rb +51 -74
  13. data/lib/occi/core/kind.rb +15 -11
  14. data/lib/occi/core/kinds.rb +1 -1
  15. data/lib/occi/core/link.rb +14 -15
  16. data/lib/occi/core/links.rb +1 -1
  17. data/lib/occi/core/mixin.rb +5 -5
  18. data/lib/occi/core/mixins.rb +2 -2
  19. data/lib/occi/core/properties.rb +90 -12
  20. data/lib/occi/core/resource.rb +7 -3
  21. data/lib/occi/core/resources.rb +2 -2
  22. data/lib/occi/errors/attribute_definitions_converted_error.rb +5 -0
  23. data/lib/occi/errors/attribute_missing_error.rb +5 -0
  24. data/lib/occi/errors/attribute_name_invalid_error.rb +5 -0
  25. data/lib/occi/errors/attribute_not_defined_error.rb +5 -0
  26. data/lib/occi/errors/attribute_property_type_error.rb +5 -0
  27. data/lib/occi/errors/attribute_type_error.rb +5 -0
  28. data/lib/occi/errors/kind_not_defined_error.rb +5 -0
  29. data/lib/occi/errors/parser_input_error.rb +5 -0
  30. data/lib/occi/errors/parser_type_error.rb +5 -0
  31. data/lib/occi/errors.rb +1 -0
  32. data/lib/occi/extensions/hashie.rb +25 -0
  33. data/lib/occi/helpers/comparators/action_instance.rb +22 -0
  34. data/lib/occi/helpers/comparators/attributes.rb +22 -0
  35. data/lib/occi/helpers/comparators/categories.rb +22 -0
  36. data/lib/occi/helpers/comparators/category.rb +22 -0
  37. data/lib/occi/helpers/comparators/collection.rb +40 -0
  38. data/lib/occi/helpers/comparators/entities.rb +22 -0
  39. data/lib/occi/helpers/comparators/entity.rb +22 -0
  40. data/lib/occi/helpers/comparators/properties.rb +26 -0
  41. data/lib/occi/helpers/comparators.rb +1 -0
  42. data/lib/occi/infrastructure/compute.rb +11 -9
  43. data/lib/occi/infrastructure/network.rb +27 -27
  44. data/lib/occi/infrastructure/networkinterface.rb +22 -23
  45. data/lib/occi/infrastructure/os_tpl.rb +1 -1
  46. data/lib/occi/infrastructure/resource_tpl.rb +1 -1
  47. data/lib/occi/infrastructure/storage.rb +7 -6
  48. data/lib/occi/infrastructure/storagelink.rb +4 -4
  49. data/lib/occi/log.rb +13 -10
  50. data/lib/occi/model.rb +9 -8
  51. data/lib/occi/parser/json.rb +11 -9
  52. data/lib/occi/parser/ova.rb +12 -6
  53. data/lib/occi/parser/ovf.rb +173 -116
  54. data/lib/occi/parser/text/constants.rb +87 -0
  55. data/lib/occi/parser/text.rb +161 -200
  56. data/lib/occi/parser/xml.rb +10 -8
  57. data/lib/occi/parser.rb +100 -50
  58. data/lib/occi/settings.rb +2 -1
  59. data/lib/occi/version.rb +1 -1
  60. data/lib/occi-core.rb +6 -4
  61. data/occi-core.gemspec +0 -7
  62. data/spec/occi/collection_samples/collection1.json +1 -0
  63. data/spec/occi/collection_samples/directory2/collection2.json +1 -0
  64. data/spec/occi/collection_spec.rb +961 -31
  65. data/spec/occi/core/action_instance_spec.rb +317 -0
  66. data/spec/occi/core/action_spec.rb +71 -0
  67. data/spec/occi/core/attributes_spec.rb +582 -27
  68. data/spec/occi/core/category_spec.rb +194 -18
  69. data/spec/occi/core/entities_spec.rb +96 -0
  70. data/spec/occi/core/entity_spec.rb +317 -28
  71. data/spec/occi/core/kind_spec.rb +127 -16
  72. data/spec/occi/core/link_spec.rb +35 -0
  73. data/spec/occi/core/links_spec.rb +130 -0
  74. data/spec/occi/core/mixins_spec.rb +107 -0
  75. data/spec/occi/core/properties_spec.rb +167 -0
  76. data/spec/occi/core/resource_spec.rb +23 -9
  77. data/spec/occi/core_spec.rb +12 -0
  78. data/spec/occi/infrastructure/compute_spec.rb +218 -18
  79. data/spec/occi/infrastructure/network_spec.rb +96 -0
  80. data/spec/occi/infrastructure/networkinterface_spec.rb +96 -0
  81. data/spec/occi/infrastructure/storage_spec.rb +33 -0
  82. data/spec/occi/infrastructure/storagelink_spec.rb +45 -0
  83. data/spec/occi/log_spec.rb +104 -1
  84. data/spec/occi/model_spec.rb +251 -39
  85. data/spec/occi/{test.json → parser/json_samples/test.json} +0 -0
  86. data/spec/occi/parser/ova_samples/test.dump +0 -0
  87. data/spec/occi/{test.ova → parser/ova_samples/test.ova} +0 -0
  88. data/spec/occi/parser/ovf_samples/test.dump +0 -0
  89. data/spec/occi/{test.ovf → parser/ovf_samples/test.ovf} +0 -0
  90. data/spec/occi/parser/text_samples/occi_categories.dump +0 -0
  91. data/spec/occi/parser/text_samples/occi_categories.text +2 -0
  92. data/spec/occi/parser/text_samples/occi_compute_rocci_server.dump +0 -0
  93. data/spec/occi/parser/text_samples/occi_compute_rocci_server.resource.dump +0 -0
  94. data/spec/occi/parser/text_samples/occi_compute_rocci_server.text +10 -0
  95. data/spec/occi/parser/text_samples/occi_link_resource_instance.dump +0 -0
  96. data/spec/occi/parser/text_samples/occi_link_resource_instance.text +7 -0
  97. data/spec/occi/parser/text_samples/occi_link_simple.dump +0 -0
  98. data/spec/occi/parser/text_samples/occi_link_simple.link_string.dump +0 -0
  99. data/spec/occi/parser/text_samples/occi_link_simple.text +1 -0
  100. data/spec/occi/parser/text_samples/occi_link_w_attributes.dump +0 -0
  101. data/spec/occi/parser/text_samples/occi_link_w_attributes.text +7 -0
  102. data/spec/occi/parser/text_samples/occi_link_w_category.dump +0 -0
  103. data/spec/occi/parser/text_samples/occi_link_w_category.text +3 -0
  104. data/spec/occi/parser/text_samples/occi_model_rocci_server.dump +0 -0
  105. data/spec/occi/parser/text_samples/occi_model_rocci_server.text +51 -0
  106. data/spec/occi/parser/text_samples/occi_network_rocci_server.dump +0 -0
  107. data/spec/occi/parser/text_samples/occi_network_rocci_server.resource.dump +0 -0
  108. data/spec/occi/parser/text_samples/occi_network_rocci_server.text +11 -0
  109. data/spec/occi/parser/text_samples/occi_resource_w_attributes.dump +0 -0
  110. data/spec/occi/parser/text_samples/occi_resource_w_attributes.text +11 -0
  111. data/spec/occi/parser/text_samples/occi_resource_w_inline_links.dump +0 -0
  112. data/spec/occi/parser/text_samples/occi_resource_w_inline_links.text +16 -0
  113. data/spec/occi/parser/text_samples/occi_resource_w_inline_links_only.dump +0 -0
  114. data/spec/occi/parser/text_samples/occi_resource_w_inline_links_only.text +13 -0
  115. data/spec/occi/parser/text_samples/occi_storage_rocci_server.dump +0 -0
  116. data/spec/occi/parser/text_samples/occi_storage_rocci_server.resource.dump +0 -0
  117. data/spec/occi/parser/text_samples/occi_storage_rocci_server.text +9 -0
  118. data/spec/occi/parser/text_spec.rb +274 -78
  119. data/spec/occi/parser/xml_samples/test.xml +352 -0
  120. data/spec/occi/parser_spec.rb +255 -104
  121. data/spec/occi-core_spec.rb +31 -0
  122. data/spec/spec_helper.rb +6 -2
  123. metadata +110 -111
  124. checksums.yaml +0 -7
  125. data/spec/occi/core/attribute_spec.rb +0 -0
data/lib/occi/log.rb CHANGED
@@ -5,21 +5,24 @@ module Occi
5
5
 
6
6
  include ::Logger::Severity
7
7
 
8
- attr_reader :logger
8
+ attr_reader :logger, :log_prefix
9
9
 
10
10
  # creates a new OCCI logger
11
11
  # @param [IO,String] log_dev The log device. This is a filename (String) or IO object (typically +STDOUT+,
12
+ # @param [String] log_prefix String placed in front of every logged message
12
13
  # +STDERR+, or an open file).
13
- def initialize(log_dev)
14
+ def initialize(log_dev, log_prefix = '[rOCCI-core]')
14
15
  if log_dev.kind_of? Logger
15
16
  @logger = log_dev
16
17
  else
17
18
  @logger = Logger.new(log_dev)
18
19
  end
19
20
 
21
+ @log_prefix = log_prefix.blank? ? '' : log_prefix.strip
22
+
20
23
  # subscribe to log messages and send to logger
21
- @log_subscriber = ActiveSupport::Notifications.subscribe("log") do |name, start, finish, id, payload|
22
- @logger.log(payload[:level], payload[:message]) if @logger
24
+ @log_subscriber = ActiveSupport::Notifications.subscribe("rOCCI-core.log") do |name, start, finish, id, payload|
25
+ @logger.log(payload[:level], "#{@log_prefix} #{payload[:message]}") if @logger
23
26
  end
24
27
  end
25
28
 
@@ -39,28 +42,28 @@ module Occi
39
42
 
40
43
  # @see info
41
44
  def self.debug(message)
42
- ActiveSupport::Notifications.instrument("log", :level => Logger::DEBUG, :message => message)
45
+ ActiveSupport::Notifications.instrument("rOCCI-core.log", :level => Logger::DEBUG, :message => message)
43
46
  end
44
47
 
45
48
  # Log an +INFO+ message
46
49
  # @param [String] message the message to log; does not need to be a String
47
50
  def self.info(message)
48
- ActiveSupport::Notifications.instrument("log", :level => Logger::INFO, :message => message)
51
+ ActiveSupport::Notifications.instrument("rOCCI-core.log", :level => Logger::INFO, :message => message)
49
52
  end
50
53
 
51
54
  # @see info
52
55
  def self.warn(message)
53
- ActiveSupport::Notifications.instrument("log", :level => Logger::WARN, :message => message)
56
+ ActiveSupport::Notifications.instrument("rOCCI-core.log", :level => Logger::WARN, :message => message)
54
57
  end
55
58
 
56
59
  # @see info
57
60
  def self.error(message)
58
- ActiveSupport::Notifications.instrument("log", :level => Logger::ERROR, :message => message)
61
+ ActiveSupport::Notifications.instrument("rOCCI-core.log", :level => Logger::ERROR, :message => message)
59
62
  end
60
63
 
61
64
  # @see info
62
65
  def self.fatal(message)
63
- ActiveSupport::Notifications.instrument("log", :level => Logger::FATAL, :message => message)
66
+ ActiveSupport::Notifications.instrument("rOCCI-core.log", :level => Logger::FATAL, :message => message)
64
67
  end
65
68
  end
66
- end
69
+ end
data/lib/occi/model.rb CHANGED
@@ -14,7 +14,7 @@ module Occi
14
14
 
15
15
  # register Occi Core categories enitity, resource and link
16
16
  def register_core
17
- Occi::Log.info "### Registering OCCI Core categories enitity, resource and link ###"
17
+ Occi::Log.info "[#{self.class}] Registering OCCI Core categories enitity, resource and link"
18
18
  register Occi::Core::Entity.kind
19
19
  register Occi::Core::Resource.kind
20
20
  register Occi::Core::Link.kind
@@ -22,7 +22,7 @@ module Occi
22
22
 
23
23
  # register Occi Infrastructure categories
24
24
  def register_infrastructure
25
- Occi::Log.info "### Registering OCCI Infrastructure categories ###"
25
+ Occi::Log.info "[#{self.class}] Registering OCCI Infrastructure categories"
26
26
  Occi::Infrastructure.categories.each { |category| register category }
27
27
  end
28
28
 
@@ -32,7 +32,8 @@ module Occi
32
32
  # recursively searched for files with the extension .json .
33
33
  # @param [Sting] scheme_base_url base location for provider specific extensions of the OCCI model
34
34
  def register_files(path, scheme_base_url='http://localhost')
35
- Occi::Log.info "### Initializing OCCI Model from #{path} ###"
35
+ Occi::Log.info "[#{self.class}] Initializing OCCI Model from #{path}"
36
+ raise ArgumentError, "Directory \"#{path}\" does not exist" unless File.directory?(path)
36
37
  Dir.glob(path + '/**/*.json').each do |file|
37
38
  collection = Occi::Collection.new(JSON.parse(File.read(file)))
38
39
  # add location of service provider to scheme if it has a relative location
@@ -53,12 +54,12 @@ module Occi
53
54
 
54
55
  # clear all entities from all categories
55
56
  def reset()
56
- categories.each { |category| category.entities = [] if category.respond_to? :entities }
57
+ categories.each { |category| category.entities = Occi::Core::Entities.new if category.respond_to? :entities }
57
58
  end
58
59
 
59
60
  # @param [Occi::Core::Category] category
60
61
  def register(category)
61
- Occi::Log.debug "### Registering category #{category}"
62
+ Occi::Log.debug "[#{self.class}] Registering category #{category}"
62
63
  # add model to category as back reference
63
64
  category.model = self
64
65
  @kinds << category unless get_by_id(category.to_s) if category.class.ancestors.include? Occi::Core::Kind
@@ -68,7 +69,7 @@ module Occi
68
69
 
69
70
  # @param [Occi::Core::Category] category
70
71
  def unregister(category)
71
- Occi::Log.debug "### Unregistering category #{category.type_identifier}"
72
+ Occi::Log.debug "[#{self.class}] Unregistering category #{category.type_identifier}"
72
73
  @kinds.delete category
73
74
  @mixins.delete category
74
75
  @actions.delete category
@@ -79,8 +80,8 @@ module Occi
79
80
  # @param [Occi::Collection,Occi::Core::Category,String] filter
80
81
  # @return [Occi::Collection] collection
81
82
  def get(filter = nil)
82
- filter ? self.get_related_to(filter) : self
83
+ (filter && !filter.empty? ) ? self.get_related_to(filter) : self
83
84
  end
84
85
 
85
86
  end
86
- end
87
+ end
@@ -1,16 +1,17 @@
1
1
  module Occi
2
2
  module Parser
3
3
  module Json
4
- # @param [String] string
4
+ # @param [String] body
5
5
  # @return [Occi::Collection]
6
- def self.collection(string)
7
- collection = Occi::Collection.new
8
- hash = Hashie::Mash.new(JSON.parse(string))
9
- collection.kinds.merge hash.kinds.collect { |kind| Occi::Core::Kind.new(kind.scheme, kind.term, kind.title, kind.attributes, kind.parent ||= kind.related, kind.actions) } if hash.kinds
10
- collection.mixins.merge hash.mixins.collect { |mixin| Occi::Core::Mixin.new(mixin.scheme, mixin.term, mixin.title, mixin.attributes, mixin.depends ||= mixin.related, mixin.actions, mixin.applies) } if hash.mixins
11
- collection.actions.merge hash.actions.collect { |action| Occi::Core::Action.new(action.scheme, action.term, action.title, action.attributes) } if hash.actions
12
- collection.resources.merge hash.resources.collect { |resource| Occi::Core::Resource.new(resource.kind, resource.mixins, resource.attributes, resource.actions, resource.links) } if hash.resources
13
- collection.links.merge hash.links.collect { |link| Occi::Core::Link.new(link.kind, link.mixins, link.attributes, [], nil, link.target) } if hash.links
6
+ def self.collection(body)
7
+
8
+ begin
9
+ hash = Hashie::Mash.new(JSON.parse(body))
10
+ rescue JSON::ParserError => perr
11
+ Occi::Log.error "[#{self}] Failed to parse JSON input: #{perr.message}"
12
+ raise Occi::Errors::ParserInputError, perr.message
13
+ end
14
+ collection = Occi::Collection.new(hash)
14
15
 
15
16
  if collection.resources.size == 1 && collection.links.size > 0
16
17
  if collection.resources.first.links.empty?
@@ -27,6 +28,7 @@ module Occi
27
28
  lnk ||= resource_link
28
29
  end
29
30
  end
31
+
30
32
  collection
31
33
  end
32
34
  end
@@ -5,27 +5,33 @@ module Occi
5
5
  # @param [String] string
6
6
  # @return [Occi::Collection]
7
7
  def self.collection(string)
8
+ Occi::Log.debug "[#{self}] Parsing ova format"
8
9
  tar = Gem::Package::TarReader.new(StringIO.new(string))
9
10
  ovf = mf = cert = nil
10
11
  files = {}
12
+
11
13
  tar.each do |entry|
12
14
  tempfile = Tempfile.new(entry.full_name)
13
15
  tempfile.write(entry.read)
14
16
  tempfile.close
15
17
  files[entry.full_name] = tempfile.path
18
+
16
19
  ovf = tempfile.path if entry.full_name.end_with? '.ovf'
17
20
  mf = tempfile.path if entry.full_name.end_with? '.mf'
18
21
  cert = tempfile.path if entry.full_name.end_with? '.cert'
19
22
  end
20
23
 
24
+ Occi::Log.debug "[#{self}] In ova found: #{ovf} #{mf} #{cert}"
25
+ raise Occi::Errors::ParserInputError, 'No ovf file found' unless ovf
26
+
21
27
  File.read(mf).each_line do |line|
22
- name = line.scan(/SHA1\(([^\)]*)\)= (.*)/).flatten.first
23
- sha1 = line.scan(/SHA1\(([^\)]*)\)= (.*)/).flatten.last
24
- Occi::Log.debug "SHA1 hash #{Digest::SHA1.hexdigest(files[name])}"
25
- raise "SHA1 mismatch for file #{name}" if Digest::SHA1.hexdigest(File.read(files[name])) != sha1
26
- end if mf
28
+ line = line.scan(/SHA1\(([^\)]*)\)= (.*)/).flatten
29
+ name = line.first
30
+ sha1 = line.last
27
31
 
28
- raise 'no ovf file found' if ovf.nil?
32
+ Occi::Log.debug "[#{self}] SHA1 hash #{Digest::SHA1.hexdigest(files[name])}"
33
+ raise Occi::Errors::ParserInputError, "SHA1 mismatch for file #{name}" unless Digest::SHA1.hexdigest(File.read(files[name])) == sha1
34
+ end if mf
29
35
 
30
36
  Occi::Parser::Ovf.collection(File.read(ovf), files)
31
37
  end
@@ -9,145 +9,202 @@ module Occi
9
9
  OVFENV="http://schemas.dmtf.org/ovf/environment/1"
10
10
  CIM ="http://schemas.dmtf.org/wbem/wscim/1/common"
11
11
 
12
- # @param [String] string
13
- # @param [Hash] files key value pairs of file names and paths to the file
14
- def self.collection(string, files={})
15
- collection = Occi::Collection.new
16
- doc = Nokogiri::XML(string)
17
- references = {}
18
-
19
- doc.xpath('envelope:Envelope/envelope:References/envelope:File', 'envelope' => "#{OVF}").each do |file|
20
- href = URI.parse(file.attributes['href'].to_s)
21
- if href.relative?
22
- if files[href.to_s]
23
- references[file.attributes['id'].to_s] = 'file://' + files[href.to_s]
12
+ class << self
13
+
14
+ # @param [String] string
15
+ # @param [Hash] files key value pairs of file names and paths to the file
16
+ def collection(string, files={})
17
+ collection = Occi::Collection.new
18
+ doc = Nokogiri::XML(string)
19
+
20
+ references = parse_references(doc, files)
21
+ parse_storage(doc, references, collection)
22
+ parse_network(doc, collection)
23
+ parse_compute(doc, references, collection)
24
+
25
+ collection
26
+ end
27
+
28
+ def parse_references(doc, files)
29
+ references = {}
30
+
31
+ doc.xpath('envelope:Envelope/envelope:References/envelope:File', 'envelope' => "#{OVF}").each do |file|
32
+ href = URI.parse(file.attributes['href'].to_s)
33
+ references[file.attributes['id'].to_s] = if href.relative?
34
+ files[href.to_s] ? "file://#{files[href.to_s]}" : "file://#{href.to_s}"
24
35
  else
25
- references[file.attributes['id'].to_s] = 'file://' + href.to_s
36
+ href.to_s
26
37
  end
27
- else
28
- references[file.attributes['id'].to_s] = href.to_s
29
38
  end
39
+
40
+ references
30
41
  end
31
42
 
32
- doc.xpath('envelope:Envelope/envelope:DiskSection/envelope:Disk', 'envelope' => "#{OVF}").each do |disk|
33
- storage = Occi::Core::Resource.new('http://schemas.ogf.org/occi/infrastructure#storage')
34
- if disk.attributes['fileRef']
35
- storagelink = Occi::Core::Link.new("http://schemas.ogf.org/occi/infrastructure#storagelink")
36
- storagelink.attributes.occi!.core!.title = disk.attributes['fileRef'].to_s
37
- storagelink.attributes.occi!.core!.target = references[disk.attributes['fileRef'].to_s]
38
- storage.attributes.occi!.core!.title = disk.attributes['diskId'].to_s
39
- storage.links << storagelink
40
- else
41
- #OCCI accepts storage size in GB
42
- #OVF ver 1.1: The capacity of a virtual disk shall be specified by the ovf:capacity attribute with an xs:long integer
43
- #value. The default unit odf allocation shall be bytes. The optional string attribute
44
- #ovf:capacityAllocationUnits may be used to specify a particular unit of allocation.
45
- alloc_units = disk.attributes['capacityAllocationUnits'].to_s
46
- if alloc_units.empty?
47
- # The capacity is defined in bytes , convert to GB and pass it to OCCI
48
- capacity = disk.attributes['capacity'].to_s
49
- capacity =capacity.to_i
43
+ def parse_storage(doc, references, collection)
44
+ doc.xpath('envelope:Envelope/envelope:DiskSection/envelope:Disk', 'envelope' => "#{OVF}").each do |disk|
45
+ storage = Occi::Infrastructure::Storage.new
46
+
47
+ if disk.attributes['fileRef']
48
+ parse_storage_disk_file(disk, storage, references)
50
49
  else
51
- alloc_unit_bytes = self.alloc_units_bytes(alloc_units)
52
- capacity = self.calculate_capacity_bytes(disk.attributes['capacity'].to_s, alloc_unit_bytes)
50
+ parse_storage_disk_alloc(disk, storage, references)
53
51
  end
54
- capacity_gb = self.calculate_capacity_gb(capacity)
55
- Occi::Log.debug('capacity in gb ' + capacity_gb.to_s)
56
- storage.attributes.occi!.storage!.size = capacity_gb.to_s if capacity_gb
57
- storage.attributes.occi!.core!.title = disk.attributes['diskId'].to_s if disk.attributes['diskId']
52
+
53
+ collection.resources << storage
54
+ end
55
+
56
+ collection
57
+ end
58
+
59
+ def parse_storage_disk_file(disk, storage, references)
60
+ storagelink = Occi::Infrastructure::Storagelink.new
61
+ storagelink.title = disk.attributes['fileRef'].to_s
62
+ storagelink.target = references[disk.attributes['fileRef'].to_s]
63
+
64
+ storage.title = disk.attributes['diskId'].to_s
65
+ storage.links << storagelink
66
+
67
+ storage
68
+ end
69
+
70
+ def parse_storage_disk_alloc(disk, storage)
71
+ #OCCI accepts storage size in GB
72
+ #OVF ver 1.1: The capacity of a virtual disk shall be specified by the ovf:capacity attribute with an xs:long integer
73
+ #value. The default unit odf allocation shall be bytes. The optional string attribute
74
+ #ovf:capacityAllocationUnits may be used to specify a particular unit of allocation.
75
+ alloc_units = disk.attributes['capacityAllocationUnits'].to_s
76
+
77
+ if alloc_units.empty?
78
+ # The capacity is defined in bytes, convert to GB and pass it to OCCI
79
+ capacity = disk.attributes['capacity'].to_s.to_i
80
+ else
81
+ alloc_unit_bytes = alloc_units_bytes(alloc_units)
82
+ capacity = calculate_capacity_bytes(disk.attributes['capacity'].to_s, alloc_unit_bytes)
83
+ end
84
+
85
+ capacity_gb = calculate_capacity_gb(capacity)
86
+ storage.size = capacity_gb.to_s if capacity_gb
87
+ storage.title = disk.attributes['diskId'].to_s if disk.attributes['diskId']
88
+
89
+ storage
90
+ end
91
+
92
+ def parse_network(doc, collection)
93
+ doc.xpath('envelope:Envelope/envelope:NetworkSection/envelope:Network', 'envelope' => "#{OVF}").each do |nw|
94
+ network = Occi::Infrastructure::Network.new
95
+ network.title = nw.attributes['name'].to_s
96
+ collection.resources << network
58
97
  end
59
- collection.resources << storage
98
+
99
+ collection
60
100
  end
61
101
 
62
- doc.xpath('envelope:Envelope/envelope:NetworkSection/envelope:Network', 'envelope' => "#{OVF}").each do |nw|
63
- network = Occi::Core::Resource.new('http://schemas.ogf.org/occi/infrastructure#network')
64
- network.attributes.occi!.core!.title = nw.attributes['name'].to_s
65
- collection.resources << network
102
+ def parse_compute(doc, references, collection)
103
+ # Iteration through all the virtual hardware sections,and a sub-iteration on each Item defined in the Virtual Hardware section
104
+ doc.xpath('envelope:Envelope/envelope:VirtualSystem', 'envelope' => "#{OVF}").each do |virtsys|
105
+ compute = Occi::Infrastructure::Compute.new
106
+
107
+ doc.xpath('envelope:Envelope/envelope:VirtualSystem/envelope:VirtualHardwareSection', 'envelope' => "#{OVF}").each do |virthwsec|
108
+ compute.summary = virthwsec.xpath("item:Info/text()", 'item' => "#{RASD}").to_s
109
+ parse_compute_resources(collection, compute, virthwsec)
110
+ end
111
+
112
+ collection.resources << compute
113
+ end
114
+
115
+ collection
66
116
  end
67
117
 
68
- # Iteration through all the virtual hardware sections,and a sub-iteration on each Item defined in the Virtual Hardware section
69
- doc.xpath('envelope:Envelope/envelope:VirtualSystem', 'envelope' => "#{OVF}").each do |virtsys|
70
- compute = Occi::Core::Resource.new('http://schemas.ogf.org/occi/infrastructure#compute')
71
-
72
- doc.xpath('envelope:Envelope/envelope:VirtualSystem/envelope:VirtualHardwareSection', 'envelope' => "#{OVF}").each do |virthwsec|
73
- compute.attributes.occi!.core!.summary = virthwsec.xpath("item:Info/text()", 'item' => "#{RASD}").to_s
74
-
75
- virthwsec.xpath('envelope:Item', 'envelope' => "#{OVF}").each do |resource_alloc|
76
- resType = resource_alloc.xpath("item:ResourceType/text()", 'item' => "#{RASD}")
77
- case resType.to_s
78
- # 4 is the ResourceType for memory in the CIM_ResourceAllocationSettingData
79
- when "4" then
80
- Occi::Log.debug('calculating memory in gb ')
81
- alloc_units = resource_alloc.xpath("item:AllocationUnits/text()", 'item' => "#{RASD}").to_s
82
- Occi::Log.debug('allocated units in ovf file: ' + alloc_units)
83
- alloc_unit_bytes = self.alloc_units_bytes(alloc_units)
84
- capacity = self.calculate_capacity_bytes(resource_alloc.xpath("item:VirtualQuantity/text()", 'item' => "#{RASD}").to_s, alloc_unit_bytes)
85
- capacity_gb = self.calculate_capacity_gb(capacity)
86
- Occi::Log.debug('virtual quantity of memory configured in gb: ' + capacity_gb.to_s)
87
- compute.attributes.occi!.compute!.memory = capacity_gb
88
- # compute.attributes.occi!.compute!.memory = resource_alloc.xpath("item:VirtualQuantity/text()", 'item' => "#{RASD}").to_s.to_i
89
- # 3 is the ResourceType for processor in the CIM_ResourceAllocationSettingData
90
- when "3" then
91
- compute.attributes.occi!.compute!.cores = resource_alloc.xpath("item:VirtualQuantity/text()", 'item' => "#{RASD}").to_s.to_i
92
- when "10" then
93
- networkinterface = Occi::Core::Link.new('http://schemas.ogf.org/occi/infrastructure#networkinterface')
94
- networkinterface.attributes.occi!.core!.title = resource_alloc.xpath("item:ElementName/text()", 'item' => "#{RASD}").to_s
95
- id = resource_alloc.xpath("item:Connection/text()", 'item' => "#{RASD}").to_s
96
- network = collection.resources.select { |resource| resource.attributes.occi!.core!.title.to_s == id }.first
97
- raise "Network with id #{id} not found" unless network
98
- networkinterface.attributes.occi!.core!.target = network
99
- when "17" then
100
- storagelink = Occi::Core::Link.new("http://schemas.ogf.org/occi/infrastructure#storagelink")
101
- storagelink.attributes.occi!.core!.title = resource_alloc.xpath("item:ElementName/text()", 'item' => "#{RASD}").to_s
102
- # extract the mountpoint
103
- host_resource = resource_alloc.xpath("item:HostResource/text()", 'item' => "#{RASD}").to_s
104
- if host_resource.start_with? 'ovf:/disk/'
105
- id = host_resource.gsub('ovf:/disk/', '')
106
- storage = collection.resources.select { |resource| resource.attributes.occi!.core!.title.to_s == id }.first
107
- raise "Disk with id #{id} not found" unless storage
108
- storagelink.attributes.occi!.core!.target = storage
109
- elsif host_resource.start_with? 'ovf:/file/'
110
- id = host_resource.gsub('ovf:/file/', '')
111
- storagelink.attributes.occi!.core!.target = references[id]
112
- end
113
- compute.links << storagelink
114
- end
115
- ##Add the cpu architecture
116
- #system_sec = virthwsec.xpath('envelope:System', 'envelope' => "#{OVF}")
117
- #virtsys_type = system_sec.xpath('vssd_:VirtualSystemType/text()', 'vssd_' => "#{VSSD}")
118
- #compute.attributes.occi!.compute!.architecture = virtsys_type
118
+ def parse_compute_resources(collection, compute, virthwsec)
119
+ virthwsec.xpath('envelope:Item', 'envelope' => "#{OVF}").each do |resource_alloc|
120
+ resType = resource_alloc.xpath("item:ResourceType/text()", 'item' => "#{RASD}")
121
+
122
+ case resType.to_s
123
+ when "4" then
124
+ # 4 is the ResourceType for memory in the CIM_ResourceAllocationSettingData
125
+ parse_compute_memory(resource_alloc, compute)
126
+ when "3" then
127
+ # 3 is the ResourceType for processor in the CIM_ResourceAllocationSettingData
128
+ compute.cores = resource_alloc.xpath("item:VirtualQuantity/text()", 'item' => "#{RASD}").to_s.to_i
129
+ when "10" then
130
+ # extract the network
131
+ parse_compute_network(resource_alloc, compute, collection)
132
+ when "17" then
133
+ # extract the mountpoint
134
+ parse_compute_storage(resource_alloc, compute, collection)
119
135
  end
136
+
137
+ ##Add the cpu architecture
138
+ #system_sec = virthwsec.xpath('envelope:System', 'envelope' => "#{OVF}")
139
+ #compute.architecture = system_sec.xpath('vssd_:VirtualSystemType/text()', 'vssd_' => "#{VSSD}")
120
140
  end
121
- collection.resources << compute
141
+
142
+ compute
122
143
  end
123
- collection
124
- end
125
144
 
126
- ####################Helper method for calculation of storage size based on allocation units configured###########
145
+ def parse_compute_memory(resource_alloc, compute)
146
+ alloc_units = resource_alloc.xpath("item:AllocationUnits/text()", 'item' => "#{RASD}").to_s
127
147
 
128
- def self.calculate_capacity_bytes(capacity, alloc_units_bytes)
129
- total_capacity_bytes = alloc_units_bytes * capacity.to_i
130
- total_capacity_bytes
131
- end
148
+ alloc_unit_bytes = alloc_units_bytes(alloc_units)
149
+ capacity = calculate_capacity_bytes(resource_alloc.xpath("item:VirtualQuantity/text()", 'item' => "#{RASD}").to_s, alloc_unit_bytes)
150
+ capacity_gb = calculate_capacity_gb(capacity)
132
151
 
152
+ compute.memory = capacity_gb
153
+ # compute.attributes.occi!.compute!.memory = resource_alloc.xpath("item:VirtualQuantity/text()", 'item' => "#{RASD}").to_s.to_i
133
154
 
134
- def self.calculate_capacity_gb(capacity)
135
- capacity_gb = capacity.to_f/(2**30)
136
- capacity_gb
137
- end
155
+ compute
156
+ end
138
157
 
158
+ def parse_compute_network(resource_alloc, compute, collection)
159
+ id = resource_alloc.xpath("item:Connection/text()", 'item' => "#{RASD}").to_s
160
+ network = collection.resources.select { |resource| resource.title == id }.first
161
+ raise Occi::Errors::ParserInputError, "Network with id #{id} not found" unless network
139
162
 
140
- def self.alloc_units_bytes(alloc_units)
141
- units = alloc_units.split('*')
142
- #check units[1] is nil??
143
- units[1].strip!
144
- alloc_vars = units[1].split('^')
145
- alloc_units_bytes = (alloc_vars[0].to_i**alloc_vars[1].to_i)
146
- alloc_units_bytes
147
- end
163
+ networkinterface = compute.networkinterface(network)
164
+ networkinterface.title = resource_alloc.xpath("item:ElementName/text()", 'item' => "#{RASD}").to_s
148
165
 
149
- ###############End of Helper methods for OVF Parsing ##################################################################
166
+ compute
167
+ end
168
+
169
+ def parse_compute_storage(resource_alloc, compute, collection)
170
+ host_resource = resource_alloc.xpath("item:HostResource/text()", 'item' => "#{RASD}").to_s
171
+
172
+ if host_resource.start_with? 'ovf:/disk/'
173
+ id = host_resource.gsub('ovf:/disk/', '')
174
+ storage = collection.resources.select { |resource| resource.title == id }.first
175
+ raise Occi::Errors::ParserInputError, "Disk with id #{id} not found" unless storage
176
+ elsif host_resource.start_with? 'ovf:/file/'
177
+ raise Occi::Errors::ParserInputError, 'OVF files are not supported!'
178
+ #id = host_resource.gsub('ovf:/file/', '')
179
+ #storagelink.attributes.occi!.core!.target = references[id]
180
+ end
181
+
182
+ storagelink = compute.storagelink(storage)
183
+ storagelink.title = resource_alloc.xpath("item:ElementName/text()", 'item' => "#{RASD}").to_s
150
184
 
185
+ compute
186
+ end
187
+
188
+ def calculate_capacity_bytes(capacity, alloc_units_bytes)
189
+ total_capacity_bytes = alloc_units_bytes * capacity.to_i
190
+ total_capacity_bytes
191
+ end
192
+
193
+ def calculate_capacity_gb(capacity)
194
+ capacity_gb = capacity.to_f/(2**30)
195
+ capacity_gb
196
+ end
197
+
198
+ def alloc_units_bytes(alloc_units)
199
+ units = alloc_units.split('*')
200
+ #check units[1] is nil??
201
+ units[1].strip!
202
+ alloc_vars = units[1].split('^')
203
+ alloc_units_bytes = (alloc_vars[0].to_i**alloc_vars[1].to_i)
204
+ alloc_units_bytes
205
+ end
206
+
207
+ end
151
208
 
152
209
  end
153
210
  end
@@ -0,0 +1,87 @@
1
+ module Occi
2
+ module Parser
3
+ module Text
4
+ module Constants
5
+
6
+ # Regular expressions
7
+ REGEXP_QUOTED_STRING = /([^"\\]|\\.)*/
8
+ REGEXP_LOALPHA = /[a-z]/
9
+ REGEXP_ALPHA = /[a-zA-Z]/
10
+ REGEXP_DIGIT = /[0-9]/
11
+ REGEXP_INT = /#{REGEXP_DIGIT}+/
12
+ REGEXP_FLOAT = /#{REGEXP_INT}\.#{REGEXP_INT}/
13
+ REGEXP_NUMBER = /#{REGEXP_FLOAT}|#{REGEXP_INT}/
14
+ REGEXP_BOOL = /\b(?<!\|)true(?!\|)\b|\b(?<!\|)false(?!\|)\b/
15
+
16
+ # Regular expressions for OCCI
17
+ REGEXP_TERM = /(#{REGEXP_ALPHA}|#{REGEXP_DIGIT})(#{REGEXP_ALPHA}|#{REGEXP_DIGIT}|-|_)*/# Compatibility with terms starting with a number
18
+ REGEXP_TERM_STRICT = /#{REGEXP_LOALPHA}(#{REGEXP_LOALPHA}|#{REGEXP_DIGIT}|-|_)*/
19
+ REGEXP_SCHEME = /#{URI::ABS_URI_REF}#/
20
+ REGEXP_TYPE_IDENTIFIER = /#{REGEXP_SCHEME}#{REGEXP_TERM}/
21
+ REGEXP_TYPE_IDENTIFIER_STRICT = /#{REGEXP_SCHEME}#{REGEXP_TERM_STRICT}/
22
+ REGEXP_CLASS = /\b(?<!\|)action(?!\|)\b|\b(?<!\|)mixin(?!\|)\b|\b(?<!\|)kind(?!\|)\b/
23
+
24
+ REGEXP_ATTR_COMPONENT = /#{REGEXP_LOALPHA}(#{REGEXP_LOALPHA}|#{REGEXP_DIGIT}|-|_)*/
25
+ REGEXP_ATTRIBUTE_NAME = /#{REGEXP_ATTR_COMPONENT}(\.#{REGEXP_ATTR_COMPONENT})*/
26
+ REGEXP_ATTRIBUTE_PROPERTY = /\b(?<!\|)immutable(?!\|)\b|\b(?<!\|)required(?!\|)\b/
27
+ REGEXP_ATTRIBUTE_DEF = /(#{REGEXP_ATTRIBUTE_NAME})(\{#{REGEXP_ATTRIBUTE_PROPERTY}(\s+#{REGEXP_ATTRIBUTE_PROPERTY})*\})?/
28
+ REGEXP_ATTRIBUTE_LIST = /#{REGEXP_ATTRIBUTE_DEF}(\s+#{REGEXP_ATTRIBUTE_DEF})*/
29
+ REGEXP_ATTRIBUTE_REPR = /#{REGEXP_ATTRIBUTE_NAME}=("#{REGEXP_QUOTED_STRING}"|#{REGEXP_NUMBER}|#{REGEXP_BOOL})/
30
+
31
+ REGEXP_ACTION = /#{REGEXP_TYPE_IDENTIFIER}/
32
+ REGEXP_ACTION_STRICT = /#{REGEXP_TYPE_IDENTIFIER_STRICT}/
33
+ REGEXP_ACTION_LIST = /#{REGEXP_ACTION}(\s+#{REGEXP_ACTION})*/
34
+ REGEXP_ACTION_LIST_STRICT = /#{REGEXP_ACTION_STRICT}(\s+#{REGEXP_ACTION_STRICT})*/
35
+
36
+ REGEXP_RESOURCE_TYPE = /#{REGEXP_TYPE_IDENTIFIER}(\s+#{REGEXP_TYPE_IDENTIFIER})*/
37
+ REGEXP_RESOURCE_TYPE_STRICT = /#{REGEXP_TYPE_IDENTIFIER_STRICT}(\s+#{REGEXP_TYPE_IDENTIFIER_STRICT})*/
38
+ REGEXP_LINK_INSTANCE = /#{URI::URI_REF}/
39
+ REGEXP_LINK_TYPE = /#{REGEXP_TYPE_IDENTIFIER}(\s+#{REGEXP_TYPE_IDENTIFIER})*/
40
+ REGEXP_LINK_TYPE_STRICT = /#{REGEXP_TYPE_IDENTIFIER_STRICT}(\s+#{REGEXP_TYPE_IDENTIFIER_STRICT})*/
41
+
42
+ # Regular expression for OCCI Categories
43
+ REGEXP_CATEGORY = "Category:\\s*(?<term>#{REGEXP_TERM})" << # term (mandatory)
44
+ ";\\s*scheme=\"(?<scheme>#{REGEXP_SCHEME})#{REGEXP_TERM}?\"" << # scheme (mandatory)
45
+ ";\\s*class=\"?(?<class>#{REGEXP_CLASS})\"?" << # class (mandatory)
46
+ "(;\\s*title=\"(?<title>#{REGEXP_QUOTED_STRING})\")?" << # title (optional)
47
+ "(;\\s*rel=\"(?<rel>#{REGEXP_TYPE_IDENTIFIER})\")?"<< # rel (optional)
48
+ "(;\\s*location=\"(?<location>#{URI::URI_REF})\")?" << # location (optional)
49
+ "(;\\s*attributes=\"(?<attributes>#{REGEXP_ATTRIBUTE_LIST})\")?" << # attributes (optional)
50
+ "(;\\s*actions=\"(?<actions>#{REGEXP_ACTION_LIST})\")?" << # actions (optional)
51
+ ';?' # additional semicolon at the end (not specified, for interoperability)
52
+ REGEXP_CATEGORY_STRICT = "Category:\\s*(?<term>#{REGEXP_TERM_STRICT})" << # term (mandatory)
53
+ ";\\s*scheme=\"(?<scheme>#{REGEXP_SCHEME})\"" << # scheme (mandatory)
54
+ ";\\s*class=\"(?<class>#{REGEXP_CLASS})\"" << # class (mandatory)
55
+ "(;\\s*title=\"(?<title>#{REGEXP_QUOTED_STRING})\")?" << # title (optional)
56
+ "(;\\s*rel=\"(?<rel>#{REGEXP_TYPE_IDENTIFIER_STRICT})\")?"<< # rel (optional)
57
+ "(;\\s*location=\"(?<location>#{URI::URI_REF})\")?" << # location (optional)
58
+ "(;\\s*attributes=\"(?<attributes>#{REGEXP_ATTRIBUTE_LIST})\")?" << # attributes (optional)
59
+ "(;\\s*actions=\"(?<actions>#{REGEXP_ACTION_LIST_STRICT})\")?" << # actions (optional)
60
+ ';?' # additional semicolon at the end (not specified, for interoperability)
61
+
62
+ # Regular expression for OCCI Link Instance References
63
+ REGEXP_LINK = "Link:\\s*\\<(?<uri>#{URI::URI_REF})\\>" << # uri (mandatory)
64
+ ";\\s*rel=\"(?<rel>#{REGEXP_RESOURCE_TYPE})\"" << # rel (mandatory)
65
+ "(;\\s*self=\"(?<self>#{REGEXP_LINK_INSTANCE})\")?" << # self (optional)
66
+ "(;\\s*category=\"(?<category>(;?\\s*(#{REGEXP_LINK_TYPE}))+)\")?" << # category (optional)
67
+ "(?<attributes>(;?\\s*(#{REGEXP_ATTRIBUTE_REPR}))*)" << # attributes (optional)
68
+ ';?' # additional semicolon at the end (not specified, for interoperability)
69
+ REGEXP_LINK_STRICT = "Link:\\s*\\<(?<uri>#{URI::URI_REF})\\>" << # uri (mandatory)
70
+ ";\\s*rel=\"(?<rel>#{REGEXP_RESOURCE_TYPE_STRICT})\"" << # rel (mandatory)
71
+ "(;\\s*self=\"(?<self>#{REGEXP_LINK_INSTANCE})\")?" << # self (optional)
72
+ "(;\\s*category=\"(?<category>(;?\\s*(#{REGEXP_LINK_TYPE_STRICT}))+)\")?" << # category (optional)
73
+ "(?<attributes>(;\\s*(#{REGEXP_ATTRIBUTE_REPR}))*)" << # attributes (optional)
74
+ ';?' # additional semicolon at the end (not specified, for interoperability)
75
+
76
+ # Regular expression for OCCI Entity Attributes
77
+ REGEXP_ATTRIBUTE = "X-OCCI-Attribute:\\s*(?<name>#{REGEXP_ATTRIBUTE_NAME})=(\"(?<string>#{REGEXP_QUOTED_STRING})\"|(?<number>#{REGEXP_NUMBER})|(?<bool>#{REGEXP_BOOL}))" <<
78
+ ';?' # additional semicolon at the end (not specified, for interoperability)
79
+
80
+ # Regular expression for OCCI Location
81
+ REGEXP_LOCATION = "X-OCCI-Location:\\s*(?<location>#{URI::URI_REF})" <<
82
+ ';?' # additional semicolon at the end (not specified, for interoperability)
83
+
84
+ end
85
+ end
86
+ end
87
+ end