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.
- data/.gitignore +1 -0
- data/Gemfile +8 -0
- data/README.md +49 -17
- data/lib/occi/collection.rb +37 -21
- data/lib/occi/core/action.rb +5 -5
- data/lib/occi/core/action_instance.rb +45 -3
- data/lib/occi/core/actions.rb +2 -1
- data/lib/occi/core/attributes.rb +253 -73
- data/lib/occi/core/categories.rb +1 -0
- data/lib/occi/core/category.rb +25 -8
- data/lib/occi/core/entities.rb +1 -0
- data/lib/occi/core/entity.rb +51 -74
- data/lib/occi/core/kind.rb +15 -11
- data/lib/occi/core/kinds.rb +1 -1
- data/lib/occi/core/link.rb +14 -15
- data/lib/occi/core/links.rb +1 -1
- data/lib/occi/core/mixin.rb +5 -5
- data/lib/occi/core/mixins.rb +2 -2
- data/lib/occi/core/properties.rb +90 -12
- data/lib/occi/core/resource.rb +7 -3
- data/lib/occi/core/resources.rb +2 -2
- data/lib/occi/errors/attribute_definitions_converted_error.rb +5 -0
- data/lib/occi/errors/attribute_missing_error.rb +5 -0
- data/lib/occi/errors/attribute_name_invalid_error.rb +5 -0
- data/lib/occi/errors/attribute_not_defined_error.rb +5 -0
- data/lib/occi/errors/attribute_property_type_error.rb +5 -0
- data/lib/occi/errors/attribute_type_error.rb +5 -0
- data/lib/occi/errors/kind_not_defined_error.rb +5 -0
- data/lib/occi/errors/parser_input_error.rb +5 -0
- data/lib/occi/errors/parser_type_error.rb +5 -0
- data/lib/occi/errors.rb +1 -0
- data/lib/occi/extensions/hashie.rb +25 -0
- data/lib/occi/helpers/comparators/action_instance.rb +22 -0
- data/lib/occi/helpers/comparators/attributes.rb +22 -0
- data/lib/occi/helpers/comparators/categories.rb +22 -0
- data/lib/occi/helpers/comparators/category.rb +22 -0
- data/lib/occi/helpers/comparators/collection.rb +40 -0
- data/lib/occi/helpers/comparators/entities.rb +22 -0
- data/lib/occi/helpers/comparators/entity.rb +22 -0
- data/lib/occi/helpers/comparators/properties.rb +26 -0
- data/lib/occi/helpers/comparators.rb +1 -0
- data/lib/occi/infrastructure/compute.rb +11 -9
- data/lib/occi/infrastructure/network.rb +27 -27
- data/lib/occi/infrastructure/networkinterface.rb +22 -23
- data/lib/occi/infrastructure/os_tpl.rb +1 -1
- data/lib/occi/infrastructure/resource_tpl.rb +1 -1
- data/lib/occi/infrastructure/storage.rb +7 -6
- data/lib/occi/infrastructure/storagelink.rb +4 -4
- data/lib/occi/log.rb +13 -10
- data/lib/occi/model.rb +9 -8
- data/lib/occi/parser/json.rb +11 -9
- data/lib/occi/parser/ova.rb +12 -6
- data/lib/occi/parser/ovf.rb +173 -116
- data/lib/occi/parser/text/constants.rb +87 -0
- data/lib/occi/parser/text.rb +161 -200
- data/lib/occi/parser/xml.rb +10 -8
- data/lib/occi/parser.rb +100 -50
- data/lib/occi/settings.rb +2 -1
- data/lib/occi/version.rb +1 -1
- data/lib/occi-core.rb +6 -4
- data/occi-core.gemspec +0 -7
- data/spec/occi/collection_samples/collection1.json +1 -0
- data/spec/occi/collection_samples/directory2/collection2.json +1 -0
- data/spec/occi/collection_spec.rb +961 -31
- data/spec/occi/core/action_instance_spec.rb +317 -0
- data/spec/occi/core/action_spec.rb +71 -0
- data/spec/occi/core/attributes_spec.rb +582 -27
- data/spec/occi/core/category_spec.rb +194 -18
- data/spec/occi/core/entities_spec.rb +96 -0
- data/spec/occi/core/entity_spec.rb +317 -28
- data/spec/occi/core/kind_spec.rb +127 -16
- data/spec/occi/core/link_spec.rb +35 -0
- data/spec/occi/core/links_spec.rb +130 -0
- data/spec/occi/core/mixins_spec.rb +107 -0
- data/spec/occi/core/properties_spec.rb +167 -0
- data/spec/occi/core/resource_spec.rb +23 -9
- data/spec/occi/core_spec.rb +12 -0
- data/spec/occi/infrastructure/compute_spec.rb +218 -18
- data/spec/occi/infrastructure/network_spec.rb +96 -0
- data/spec/occi/infrastructure/networkinterface_spec.rb +96 -0
- data/spec/occi/infrastructure/storage_spec.rb +33 -0
- data/spec/occi/infrastructure/storagelink_spec.rb +45 -0
- data/spec/occi/log_spec.rb +104 -1
- data/spec/occi/model_spec.rb +251 -39
- data/spec/occi/{test.json → parser/json_samples/test.json} +0 -0
- data/spec/occi/parser/ova_samples/test.dump +0 -0
- data/spec/occi/{test.ova → parser/ova_samples/test.ova} +0 -0
- data/spec/occi/parser/ovf_samples/test.dump +0 -0
- data/spec/occi/{test.ovf → parser/ovf_samples/test.ovf} +0 -0
- data/spec/occi/parser/text_samples/occi_categories.dump +0 -0
- data/spec/occi/parser/text_samples/occi_categories.text +2 -0
- data/spec/occi/parser/text_samples/occi_compute_rocci_server.dump +0 -0
- data/spec/occi/parser/text_samples/occi_compute_rocci_server.resource.dump +0 -0
- data/spec/occi/parser/text_samples/occi_compute_rocci_server.text +10 -0
- data/spec/occi/parser/text_samples/occi_link_resource_instance.dump +0 -0
- data/spec/occi/parser/text_samples/occi_link_resource_instance.text +7 -0
- data/spec/occi/parser/text_samples/occi_link_simple.dump +0 -0
- data/spec/occi/parser/text_samples/occi_link_simple.link_string.dump +0 -0
- data/spec/occi/parser/text_samples/occi_link_simple.text +1 -0
- data/spec/occi/parser/text_samples/occi_link_w_attributes.dump +0 -0
- data/spec/occi/parser/text_samples/occi_link_w_attributes.text +7 -0
- data/spec/occi/parser/text_samples/occi_link_w_category.dump +0 -0
- data/spec/occi/parser/text_samples/occi_link_w_category.text +3 -0
- data/spec/occi/parser/text_samples/occi_model_rocci_server.dump +0 -0
- data/spec/occi/parser/text_samples/occi_model_rocci_server.text +51 -0
- data/spec/occi/parser/text_samples/occi_network_rocci_server.dump +0 -0
- data/spec/occi/parser/text_samples/occi_network_rocci_server.resource.dump +0 -0
- data/spec/occi/parser/text_samples/occi_network_rocci_server.text +11 -0
- data/spec/occi/parser/text_samples/occi_resource_w_attributes.dump +0 -0
- data/spec/occi/parser/text_samples/occi_resource_w_attributes.text +11 -0
- data/spec/occi/parser/text_samples/occi_resource_w_inline_links.dump +0 -0
- data/spec/occi/parser/text_samples/occi_resource_w_inline_links.text +16 -0
- data/spec/occi/parser/text_samples/occi_resource_w_inline_links_only.dump +0 -0
- data/spec/occi/parser/text_samples/occi_resource_w_inline_links_only.text +13 -0
- data/spec/occi/parser/text_samples/occi_storage_rocci_server.dump +0 -0
- data/spec/occi/parser/text_samples/occi_storage_rocci_server.resource.dump +0 -0
- data/spec/occi/parser/text_samples/occi_storage_rocci_server.text +9 -0
- data/spec/occi/parser/text_spec.rb +274 -78
- data/spec/occi/parser/xml_samples/test.xml +352 -0
- data/spec/occi/parser_spec.rb +255 -104
- data/spec/occi-core_spec.rb +31 -0
- data/spec/spec_helper.rb +6 -2
- metadata +110 -111
- checksums.yaml +0 -7
- 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 "
|
|
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 "
|
|
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 "
|
|
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 =
|
|
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 "
|
|
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 "
|
|
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
|
data/lib/occi/parser/json.rb
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
module Occi
|
|
2
2
|
module Parser
|
|
3
3
|
module Json
|
|
4
|
-
# @param [String]
|
|
4
|
+
# @param [String] body
|
|
5
5
|
# @return [Occi::Collection]
|
|
6
|
-
def self.collection(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
data/lib/occi/parser/ova.rb
CHANGED
|
@@ -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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
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
|
data/lib/occi/parser/ovf.rb
CHANGED
|
@@ -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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
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
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
98
|
+
|
|
99
|
+
collection
|
|
60
100
|
end
|
|
61
101
|
|
|
62
|
-
doc
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
141
|
+
|
|
142
|
+
compute
|
|
122
143
|
end
|
|
123
|
-
collection
|
|
124
|
-
end
|
|
125
144
|
|
|
126
|
-
|
|
145
|
+
def parse_compute_memory(resource_alloc, compute)
|
|
146
|
+
alloc_units = resource_alloc.xpath("item:AllocationUnits/text()", 'item' => "#{RASD}").to_s
|
|
127
147
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
-
|
|
135
|
-
|
|
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
|
-
|
|
141
|
-
|
|
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
|
-
|
|
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
|