occi-core 4.0.0.alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rspec +1 -0
- data/.travis.yml +43 -0
- data/.yardopts +1 -0
- data/AUTHORS +9 -0
- data/Gemfile +11 -0
- data/LICENSE +13 -0
- data/README.md +212 -0
- data/Rakefile +28 -0
- data/config/occi.yml +4 -0
- data/ext/mkrf_conf.rb +35 -0
- data/lib/occi/collection.rb +192 -0
- data/lib/occi/core/action.rb +32 -0
- data/lib/occi/core/action_instance.rb +38 -0
- data/lib/occi/core/actions.rb +20 -0
- data/lib/occi/core/attribute.rb +99 -0
- data/lib/occi/core/attributes.rb +172 -0
- data/lib/occi/core/categories.rb +51 -0
- data/lib/occi/core/category.rb +153 -0
- data/lib/occi/core/entities.rb +47 -0
- data/lib/occi/core/entity.rb +264 -0
- data/lib/occi/core/kind.rb +58 -0
- data/lib/occi/core/kinds.rb +22 -0
- data/lib/occi/core/link.rb +95 -0
- data/lib/occi/core/links.rb +34 -0
- data/lib/occi/core/mixin.rb +55 -0
- data/lib/occi/core/mixins.rb +41 -0
- data/lib/occi/core/properties.rb +35 -0
- data/lib/occi/core/related.rb +7 -0
- data/lib/occi/core/resource.rb +78 -0
- data/lib/occi/core/resources.rb +14 -0
- data/lib/occi/core.rb +31 -0
- data/lib/occi/helpers/inspect.rb +12 -0
- data/lib/occi/infrastructure/compute.rb +122 -0
- data/lib/occi/infrastructure/network/ipnetwork.rb +27 -0
- data/lib/occi/infrastructure/network.rb +107 -0
- data/lib/occi/infrastructure/networkinterface/ipnetworkinterface.rb +27 -0
- data/lib/occi/infrastructure/networkinterface.rb +103 -0
- data/lib/occi/infrastructure/os_tpl.rb +19 -0
- data/lib/occi/infrastructure/resource_tpl.rb +19 -0
- data/lib/occi/infrastructure/storage.rb +61 -0
- data/lib/occi/infrastructure/storagelink.rb +56 -0
- data/lib/occi/infrastructure.rb +25 -0
- data/lib/occi/log.rb +66 -0
- data/lib/occi/model.rb +86 -0
- data/lib/occi/parser/json.rb +34 -0
- data/lib/occi/parser/ova.rb +35 -0
- data/lib/occi/parser/ovf.rb +154 -0
- data/lib/occi/parser/text.rb +234 -0
- data/lib/occi/parser/xml.rb +18 -0
- data/lib/occi/parser.rb +78 -0
- data/lib/occi/settings.rb +9 -0
- data/lib/occi/version.rb +3 -0
- data/lib/occi-core.rb +50 -0
- data/occi-core.gemspec +36 -0
- data/spec/occi/collection_spec.rb +38 -0
- data/spec/occi/core/attribute_spec.rb +0 -0
- data/spec/occi/core/attributes_spec.rb +42 -0
- data/spec/occi/core/categories_spec.rb +27 -0
- data/spec/occi/core/category_spec.rb +38 -0
- data/spec/occi/core/entity_spec.rb +46 -0
- data/spec/occi/core/resource_spec.rb +18 -0
- data/spec/occi/infrastructure/compute_spec.rb +29 -0
- data/spec/occi/log_spec.rb +14 -0
- data/spec/occi/model_spec.rb +50 -0
- data/spec/occi/parser/text_spec.rb +31 -0
- data/spec/occi/parser_spec.rb +114 -0
- data/spec/occi/test.json +33 -0
- data/spec/occi/test.ova +0 -0
- data/spec/occi/test.ovf +198 -0
- data/spec/spec_helper.rb +25 -0
- metadata +304 -0
data/lib/occi/log.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Occi
|
4
|
+
class Log
|
5
|
+
|
6
|
+
include ::Logger::Severity
|
7
|
+
|
8
|
+
attr_reader :logger
|
9
|
+
|
10
|
+
# creates a new OCCI logger
|
11
|
+
# @param [IO,String] log_dev The log device. This is a filename (String) or IO object (typically +STDOUT+,
|
12
|
+
# +STDERR+, or an open file).
|
13
|
+
def initialize(log_dev)
|
14
|
+
if log_dev.kind_of? Logger
|
15
|
+
@logger = log_dev
|
16
|
+
else
|
17
|
+
@logger = Logger.new(log_dev)
|
18
|
+
end
|
19
|
+
|
20
|
+
# 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
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def close
|
27
|
+
ActiveSupport::Notifications.unsubscribe(@log_subscriber)
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param [Logger::Severity] severity
|
31
|
+
def level=(severity)
|
32
|
+
@logger.level = severity
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [Logger::Severity]
|
36
|
+
def level
|
37
|
+
@logger.level
|
38
|
+
end
|
39
|
+
|
40
|
+
# @see info
|
41
|
+
def self.debug(message)
|
42
|
+
ActiveSupport::Notifications.instrument("log", :level => Logger::DEBUG, :message => message)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Log an +INFO+ message
|
46
|
+
# @param [String] message the message to log; does not need to be a String
|
47
|
+
def self.info(message)
|
48
|
+
ActiveSupport::Notifications.instrument("log", :level => Logger::INFO, :message => message)
|
49
|
+
end
|
50
|
+
|
51
|
+
# @see info
|
52
|
+
def self.warn(message)
|
53
|
+
ActiveSupport::Notifications.instrument("log", :level => Logger::WARN, :message => message)
|
54
|
+
end
|
55
|
+
|
56
|
+
# @see info
|
57
|
+
def self.error(message)
|
58
|
+
ActiveSupport::Notifications.instrument("log", :level => Logger::ERROR, :message => message)
|
59
|
+
end
|
60
|
+
|
61
|
+
# @see info
|
62
|
+
def self.fatal(message)
|
63
|
+
ActiveSupport::Notifications.instrument("log", :level => Logger::FATAL, :message => message)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/lib/occi/model.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
module Occi
|
2
|
+
class Model < Occi::Collection
|
3
|
+
|
4
|
+
# @param [Occi::Core::Collection] collection
|
5
|
+
def initialize(collection=nil)
|
6
|
+
super(nil, nil) # model must be empty for model class
|
7
|
+
register_core
|
8
|
+
register_collection collection if collection.kind_of? Occi::Collection
|
9
|
+
end
|
10
|
+
|
11
|
+
def model=(model)
|
12
|
+
# will not assign a model inside a model
|
13
|
+
end
|
14
|
+
|
15
|
+
# register Occi Core categories enitity, resource and link
|
16
|
+
def register_core
|
17
|
+
Occi::Log.info "### Registering OCCI Core categories enitity, resource and link ###"
|
18
|
+
register Occi::Core::Entity.kind
|
19
|
+
register Occi::Core::Resource.kind
|
20
|
+
register Occi::Core::Link.kind
|
21
|
+
end
|
22
|
+
|
23
|
+
# register Occi Infrastructure categories
|
24
|
+
def register_infrastructure
|
25
|
+
Occi::Log.info "### Registering OCCI Infrastructure categories ###"
|
26
|
+
Occi::Infrastructure.categories.each { |category| register category }
|
27
|
+
end
|
28
|
+
|
29
|
+
# register OCCI categories from files
|
30
|
+
#
|
31
|
+
# @param [String] path to a folder containing files which include OCCI collections in JSON format. The path is
|
32
|
+
# recursively searched for files with the extension .json .
|
33
|
+
# @param [Sting] scheme_base_url base location for provider specific extensions of the OCCI model
|
34
|
+
def register_files(path, scheme_base_url='http://localhost')
|
35
|
+
Occi::Log.info "### Initializing OCCI Model from #{path} ###"
|
36
|
+
Dir.glob(path + '/**/*.json').each do |file|
|
37
|
+
collection = Occi::Collection.new(JSON.parse(File.read(file)))
|
38
|
+
# add location of service provider to scheme if it has a relative location
|
39
|
+
collection.kinds.collect { |kind| kind.scheme = scheme_base_url + kind.scheme if kind.scheme.start_with? '/' } if collection.kinds
|
40
|
+
collection.mixins.collect { |mixin| mixin.scheme = scheme_base_url + mixin.scheme if mixin.scheme.start_with? '/' } if collection.mixins
|
41
|
+
collection.actions.collect { |action| action.scheme = scheme_base_url + action.scheme if action.scheme.start_with? '/' } if collection.actions
|
42
|
+
register_collection collection
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# register OCCI categories from OCCI collection
|
47
|
+
def register_collection(collection)
|
48
|
+
collection.kinds.each { |kind| kind.model = self }
|
49
|
+
collection.mixins.each { |mixin| mixin.model = self }
|
50
|
+
collection.actions.each { |action| action.model = self }
|
51
|
+
merge! collection
|
52
|
+
end
|
53
|
+
|
54
|
+
# clear all entities from all categories
|
55
|
+
def reset()
|
56
|
+
categories.each { |category| category.entities = [] if category.respond_to? :entities }
|
57
|
+
end
|
58
|
+
|
59
|
+
# @param [Occi::Core::Category] category
|
60
|
+
def register(category)
|
61
|
+
Occi::Log.debug "### Registering category #{category}"
|
62
|
+
# add model to category as back reference
|
63
|
+
category.model = self
|
64
|
+
@kinds << category unless get_by_id(category.to_s) if category.class.ancestors.include? Occi::Core::Kind
|
65
|
+
@mixins << category unless get_by_id(category.to_s) if category.class.ancestors.include? Occi::Core::Mixin
|
66
|
+
@actions << category unless get_by_id(category.to_s) if category.class.ancestors.include? Occi::Core::Action
|
67
|
+
end
|
68
|
+
|
69
|
+
# @param [Occi::Core::Category] category
|
70
|
+
def unregister(category)
|
71
|
+
Occi::Log.debug "### Unregistering category #{category.type_identifier}"
|
72
|
+
@kinds.delete category
|
73
|
+
@mixins.delete category
|
74
|
+
@actions.delete category
|
75
|
+
end
|
76
|
+
|
77
|
+
# Return all categories from model. If filter is present, return only the categories specified by filter
|
78
|
+
#
|
79
|
+
# @param [Occi::Collection,Occi::Core::Category,String] filter
|
80
|
+
# @return [Occi::Collection] collection
|
81
|
+
def get(filter = nil)
|
82
|
+
filter ? self.get_related_to(filter) : self
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Occi
|
2
|
+
module Parser
|
3
|
+
module Json
|
4
|
+
# @param [String] string
|
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.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.related, mixin.actions) } 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
|
14
|
+
|
15
|
+
if collection.resources.size == 1 && collection.links.size > 0
|
16
|
+
if collection.resources.first.links.empty?
|
17
|
+
collection.links.each { |link| link.source = collection.resources.first }
|
18
|
+
collection.resources.first.links = collection.links
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# TODO: replace the following mechanism with one in the Links class
|
23
|
+
# replace link locations with link objects in all resources
|
24
|
+
collection.resources.each do |resource|
|
25
|
+
resource.links.collect! do |resource_link|
|
26
|
+
lnk = collection.links.select { |link| resource_link == link.to_s }.first
|
27
|
+
lnk ||= resource_link
|
28
|
+
end
|
29
|
+
end
|
30
|
+
collection
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Occi
|
2
|
+
module Parser
|
3
|
+
module Ova
|
4
|
+
|
5
|
+
# @param [String] string
|
6
|
+
# @return [Occi::Collection]
|
7
|
+
def self.collection(string)
|
8
|
+
tar = Gem::Package::TarReader.new(StringIO.new(string))
|
9
|
+
ovf = mf = cert = nil
|
10
|
+
files = {}
|
11
|
+
tar.each do |entry|
|
12
|
+
tempfile = Tempfile.new(entry.full_name)
|
13
|
+
tempfile.write(entry.read)
|
14
|
+
tempfile.close
|
15
|
+
files[entry.full_name] = tempfile.path
|
16
|
+
ovf = tempfile.path if entry.full_name.end_with? '.ovf'
|
17
|
+
mf = tempfile.path if entry.full_name.end_with? '.mf'
|
18
|
+
cert = tempfile.path if entry.full_name.end_with? '.cert'
|
19
|
+
end
|
20
|
+
|
21
|
+
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
|
27
|
+
|
28
|
+
raise 'no ovf file found' if ovf.nil?
|
29
|
+
|
30
|
+
Occi::Parser::Ovf.collection(File.read(ovf), files)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
module Occi
|
2
|
+
module Parser
|
3
|
+
module Ovf
|
4
|
+
|
5
|
+
# Declaring Class constants for OVF XML namespaces (defined in OVF specification ver.1.1)
|
6
|
+
OVF ="http://schemas.dmtf.org/ovf/envelope/1"
|
7
|
+
RASD ="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
|
8
|
+
VSSD ="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
|
9
|
+
OVFENV="http://schemas.dmtf.org/ovf/environment/1"
|
10
|
+
CIM ="http://schemas.dmtf.org/wbem/wscim/1/common"
|
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]
|
24
|
+
else
|
25
|
+
references[file.attributes['id'].to_s] = 'file://' + href.to_s
|
26
|
+
end
|
27
|
+
else
|
28
|
+
references[file.attributes['id'].to_s] = href.to_s
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
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
|
50
|
+
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)
|
53
|
+
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']
|
58
|
+
end
|
59
|
+
collection.resources << storage
|
60
|
+
end
|
61
|
+
|
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
|
66
|
+
end
|
67
|
+
|
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
|
119
|
+
end
|
120
|
+
end
|
121
|
+
collection.resources << compute
|
122
|
+
end
|
123
|
+
collection
|
124
|
+
end
|
125
|
+
|
126
|
+
####################Helper method for calculation of storage size based on allocation units configured###########
|
127
|
+
|
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
|
132
|
+
|
133
|
+
|
134
|
+
def self.calculate_capacity_gb(capacity)
|
135
|
+
capacity_gb = capacity.to_f/(2**30)
|
136
|
+
capacity_gb
|
137
|
+
end
|
138
|
+
|
139
|
+
|
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
|
148
|
+
|
149
|
+
###############End of Helper methods for OVF Parsing ##################################################################
|
150
|
+
|
151
|
+
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,234 @@
|
|
1
|
+
module Occi
|
2
|
+
module Parser
|
3
|
+
module Text
|
4
|
+
# Backwards compatibility for Ruby 1.8.7 and named groups in regular expressions
|
5
|
+
if RUBY_VERSION =~ /1.8/
|
6
|
+
require 'oniguruma'
|
7
|
+
REGEXP = Oniguruma::ORegexp
|
8
|
+
else
|
9
|
+
REGEXP = Regexp
|
10
|
+
end
|
11
|
+
|
12
|
+
# Regular expressions
|
13
|
+
REGEXP_QUOTED_STRING = /([^"\\]|\\.)*/
|
14
|
+
REGEXP_LOALPHA = /[a-z]/
|
15
|
+
REGEXP_DIGIT = /[0-9]/
|
16
|
+
REGEXP_INT = /#{REGEXP_DIGIT}*/
|
17
|
+
REGEXP_FLOAT = /#{REGEXP_DIGIT}*\.#{REGEXP_DIGIT}*/
|
18
|
+
REGEXP_NUMBER = /#{REGEXP_INT}|#{REGEXP_FLOAT}/
|
19
|
+
REGEXP_BOOL = /true|false/
|
20
|
+
|
21
|
+
# Regular expressions for OCCI
|
22
|
+
if Occi::Settings.compatibility
|
23
|
+
# Compatibility with terms starting with a number
|
24
|
+
REGEXP_TERM = /(#{REGEXP_LOALPHA}|#{REGEXP_DIGIT})(#{REGEXP_LOALPHA}|#{REGEXP_DIGIT}|-|_)*/
|
25
|
+
else
|
26
|
+
REGEXP_TERM = /#{REGEXP_LOALPHA}(#{REGEXP_LOALPHA}|#{REGEXP_DIGIT}|-|_)*/
|
27
|
+
end
|
28
|
+
REGEXP_SCHEME = /#{URI::ABS_URI_REF}#/
|
29
|
+
REGEXP_TYPE_IDENTIFIER = /#{REGEXP_SCHEME}#{REGEXP_TERM}/
|
30
|
+
REGEXP_CLASS = /action|mixin|kind/
|
31
|
+
|
32
|
+
REGEXP_ATTR_COMPONENT = /#{REGEXP_LOALPHA}(#{REGEXP_LOALPHA}|#{REGEXP_DIGIT}|-|_)*/
|
33
|
+
REGEXP_ATTRIBUTE_NAME = /#{REGEXP_ATTR_COMPONENT}(\.#{REGEXP_ATTR_COMPONENT})*/
|
34
|
+
REGEXP_ATTRIBUTE_PROPERTY = /immutable|required/
|
35
|
+
REGEXP_ATTRIBUTE_DEF = /(#{REGEXP_ATTRIBUTE_NAME})(\{#{REGEXP_ATTRIBUTE_PROPERTY}(\s+#{REGEXP_ATTRIBUTE_PROPERTY})*\})?/
|
36
|
+
REGEXP_ATTRIBUTE_LIST = /#{REGEXP_ATTRIBUTE_DEF}(\s+#{REGEXP_ATTRIBUTE_DEF})*/
|
37
|
+
REGEXP_ATTRIBUTE_REPR = /#{REGEXP_ATTRIBUTE_NAME}=("#{REGEXP_QUOTED_STRING}"|#{REGEXP_NUMBER}|#{REGEXP_BOOL})/
|
38
|
+
|
39
|
+
REGEXP_ACTION = /#{REGEXP_TYPE_IDENTIFIER}/
|
40
|
+
REGEXP_ACTION_LIST = /#{REGEXP_ACTION}(\s+#{REGEXP_ACTION})*/
|
41
|
+
|
42
|
+
REGEXP_RESOURCE_TYPE = /#{REGEXP_TYPE_IDENTIFIER}(\s+#{REGEXP_TYPE_IDENTIFIER})*/
|
43
|
+
REGEXP_LINK_INSTANCE = /#{URI::URI_REF}/
|
44
|
+
REGEXP_LINK_TYPE = /#{REGEXP_TYPE_IDENTIFIER}(\s+#{REGEXP_TYPE_IDENTIFIER})*/
|
45
|
+
|
46
|
+
# Regular expression for OCCI Categories
|
47
|
+
if Occi::Settings.compatibility
|
48
|
+
REGEXP_CATEGORY = "Category:\\s*(?<term>#{REGEXP_TERM})" << # term (mandatory)
|
49
|
+
";\\s*scheme=\"(?<scheme>#{REGEXP_SCHEME})#{REGEXP_TERM}?\"" << # scheme (mandatory)
|
50
|
+
";\\s*class=\"(?<class>#{REGEXP_CLASS})\"" << # class (mandatory)
|
51
|
+
"(;\\s*title=\"(?<title>#{REGEXP_QUOTED_STRING})\")?" << # title (optional)
|
52
|
+
"(;\\s*rel=\"(?<rel>#{REGEXP_TYPE_IDENTIFIER})\")?"<< # rel (optional)
|
53
|
+
"(;\\s*location=\"(?<location>#{URI::URI_REF})\")?" << # location (optional)
|
54
|
+
"(;\\s*attributes=\"(?<attributes>#{REGEXP_ATTRIBUTE_LIST})\")?" << # attributes (optional)
|
55
|
+
"(;\\s*actions=\"(?<actions>#{REGEXP_ACTION_LIST})\")?" << # actions (optional)
|
56
|
+
';?' # additional semicolon at the end (not specified, for interoperability)
|
57
|
+
else
|
58
|
+
REGEXP_CATEGORY = "Category:\\s*(?<term>#{REGEXP_TERM})" << # term (mandatory)
|
59
|
+
";\\s*scheme=\"(?<scheme>#{REGEXP_SCHEME})\"" << # scheme (mandatory)
|
60
|
+
";\\s*class=\"(?<class>#{REGEXP_CLASS})\"" << # class (mandatory)
|
61
|
+
"(;\\s*title=\"(?<title>#{REGEXP_QUOTED_STRING})\")?" << # title (optional)
|
62
|
+
"(;\\s*rel=\"(?<rel>#{REGEXP_TYPE_IDENTIFIER})\")?"<< # rel (optional)
|
63
|
+
"(;\\s*location=\"(?<location>#{URI::URI_REF})\")?" << # location (optional)
|
64
|
+
"(;\\s*attributes=\"(?<attributes>#{REGEXP_ATTRIBUTE_LIST})\")?" << # attributes (optional)
|
65
|
+
"(;\\s*actions=\"(?<actions>#{REGEXP_ACTION_LIST})\")?" << # actions (optional)
|
66
|
+
';?' # additional semicolon at the end (not specified, for interoperability)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Regular expression for OCCI Link Instance References
|
70
|
+
REGEXP_LINK = "Link:\\s*\\<(?<uri>#{URI::URI_REF})\\>" << # uri (mandatory)
|
71
|
+
";\\s*rel=\"(?<rel>#{REGEXP_RESOURCE_TYPE})\"" << # rel (mandatory)
|
72
|
+
"(;\\s*self=\"(?<self>#{REGEXP_LINK_INSTANCE})\")?" << # self (optional)
|
73
|
+
"(;\\s*category=\"(?<category>#{REGEXP_LINK_TYPE})\")?" << # category (optional)
|
74
|
+
"(?<attributes>(;\\s*(#{REGEXP_ATTRIBUTE_REPR}))*)" << # attributes (optional)
|
75
|
+
';?' # additional semicolon at the end (not specified, for interoperability)
|
76
|
+
|
77
|
+
# Regular expression for OCCI Entity Attributes
|
78
|
+
REGEXP_ATTRIBUTE = "X-OCCI-Attribute:\\s*(?<name>#{REGEXP_ATTRIBUTE_NAME})=(\"(?<string>#{REGEXP_QUOTED_STRING})\"|(?<number>#{REGEXP_NUMBER})|(?<bool>#{REGEXP_BOOL}))" <<
|
79
|
+
';?' # additional semicolon at the end (not specified, for interoperability)
|
80
|
+
|
81
|
+
# Regular expression for OCCI Location
|
82
|
+
REGEXP_LOCATION = "X-OCCI-Location:\\s*(?<location>#{URI::URI_REF})" <<
|
83
|
+
';?' # additional semicolon at the end (not specified, for interoperability)
|
84
|
+
|
85
|
+
|
86
|
+
def self.categories(lines)
|
87
|
+
collection = Occi::Collection.new
|
88
|
+
lines.each do |line|
|
89
|
+
line.strip!
|
90
|
+
category = self.category(line) if line.start_with? 'Category:'
|
91
|
+
collection << category if category.kind_of? Occi::Core::Category
|
92
|
+
end
|
93
|
+
collection
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.resource(lines)
|
97
|
+
collection = Occi::Collection.new
|
98
|
+
resource = Occi::Core::Resource.new
|
99
|
+
lines.each do |line|
|
100
|
+
line.strip!
|
101
|
+
case line
|
102
|
+
when /^Category:/
|
103
|
+
category = self.category(line)
|
104
|
+
resource.kind = category if category.kind_of? Occi::Core::Kind
|
105
|
+
resource.mixins << category if category.kind_of? Occi::Core::Mixin
|
106
|
+
when /^X-OCCI-Attribute:/
|
107
|
+
resource.attributes.merge! self.attribute(line)
|
108
|
+
when /^Link:/
|
109
|
+
resource.links << self.link_string(line, resource)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
collection << resource if resource.kind_of? Occi::Core::Resource
|
113
|
+
collection
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.link(lines)
|
117
|
+
collection = Occi::Collection.new
|
118
|
+
link = Occi::Core::Link.new
|
119
|
+
lines.each do |line|
|
120
|
+
line.strip!
|
121
|
+
case line
|
122
|
+
when /^Category:/
|
123
|
+
category = self.category(line)
|
124
|
+
link.kind = category if category.kind_of? Occi::Core::Kind
|
125
|
+
link.mixins << category if category.kind_of? Occi::Core::Mixin
|
126
|
+
when /^X-OCCI-Attribute:/
|
127
|
+
link.attributes.merge! self.attribute(line)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
collection << link if link.kind_of? Occi::Core::Link
|
131
|
+
collection
|
132
|
+
end
|
133
|
+
|
134
|
+
def self.locations(lines)
|
135
|
+
locations = []
|
136
|
+
lines.each do |line|
|
137
|
+
line.strip!
|
138
|
+
locations << self.location(line) if line.start_with? 'X-OCCI-Location:'
|
139
|
+
end
|
140
|
+
locations
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
def self.category(string)
|
146
|
+
# create regular expression from regexp string
|
147
|
+
regexp = REGEXP.new(REGEXP_CATEGORY)
|
148
|
+
# match string to regular expression
|
149
|
+
match = regexp.match string
|
150
|
+
|
151
|
+
raise "could not match #{string}" unless match
|
152
|
+
|
153
|
+
term = match[:term]
|
154
|
+
scheme = match[:scheme]
|
155
|
+
title = match[:title]
|
156
|
+
related = match[:rel].to_s.split
|
157
|
+
attributes = Occi::Core::Attributes.new
|
158
|
+
if match[:attributes]
|
159
|
+
match[:attributes].split.each do |attribute|
|
160
|
+
property_string = attribute[/#{REGEXP_ATTRIBUTE_DEF}/, -2]
|
161
|
+
properties = Occi::Core::Properties.new
|
162
|
+
if property_string
|
163
|
+
properties.required = true if property_string.include? 'required'
|
164
|
+
properties.mutable = false if property_string.include? 'immutable'
|
165
|
+
end
|
166
|
+
name = attribute[/#{REGEXP_ATTRIBUTE_DEF}/, 1]
|
167
|
+
attributes.merge! name.split('.').reverse.inject(properties) { |a, n| Occi::Core::Attributes.new(n => a) }
|
168
|
+
end
|
169
|
+
end
|
170
|
+
actions = match[:actions].to_s.split
|
171
|
+
location = match[:location]
|
172
|
+
case match[:class]
|
173
|
+
when 'kind'
|
174
|
+
Occi::Core::Kind.new scheme, term, title, attributes, related, actions, location
|
175
|
+
when 'mixin'
|
176
|
+
Occi::Core::Mixin.new scheme, term, title, attributes, related, actions, location
|
177
|
+
when 'action'
|
178
|
+
Occi::Core::Action.new scheme, term, title, attributes
|
179
|
+
else
|
180
|
+
raise "Category with class #{match[:class]} not recognized in string: #{string}"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def self.attribute(string)
|
185
|
+
# create regular expression from regexp string
|
186
|
+
regexp = REGEXP.new(REGEXP_ATTRIBUTE)
|
187
|
+
# match string to regular expression
|
188
|
+
match = regexp.match string
|
189
|
+
|
190
|
+
raise "could not match #{string}" unless match
|
191
|
+
|
192
|
+
value = match[:string] if match[:string]
|
193
|
+
value = match[:number].to_i if match[:number]
|
194
|
+
value = match[:bool] == "true" if match[:bool]
|
195
|
+
Occi::Core::Attributes.split match[:name] => value
|
196
|
+
end
|
197
|
+
|
198
|
+
def self.link_string(string, source)
|
199
|
+
# create regular expression from regexp string
|
200
|
+
regexp = REGEXP.new(REGEXP_LINK)
|
201
|
+
# match string to regular expression
|
202
|
+
match = regexp.match string
|
203
|
+
|
204
|
+
raise "could not match #{string}" unless match
|
205
|
+
|
206
|
+
categories = match[:category].split
|
207
|
+
kind = categories.shift
|
208
|
+
mixins = categories
|
209
|
+
actions = nil
|
210
|
+
rel = match[:rel]
|
211
|
+
target = match[:uri]
|
212
|
+
location = match[:self]
|
213
|
+
|
214
|
+
# create an array of the list of attributes
|
215
|
+
attributes = match[:attributes].sub(/^\s*;\s*/, '').split ';'
|
216
|
+
# parse each attribute and create an OCCI Attribute object from it
|
217
|
+
attributes = attributes.inject(Hashie::Mash.new) { |hsh, attribute| hsh.merge!(Occi::Parser::Text.attribute('X-OCCI-Attribute: ' + attribute)) }
|
218
|
+
Occi::Core::Link.new kind, mixins, attributes, actions, rel, target, source, location
|
219
|
+
end
|
220
|
+
|
221
|
+
def self.location(string)
|
222
|
+
# create regular expression from regexp string
|
223
|
+
regexp = REGEXP.new(REGEXP_LOCATION)
|
224
|
+
# match string to regular expression
|
225
|
+
match = regexp.match string
|
226
|
+
|
227
|
+
raise "could not match #{string}" unless match
|
228
|
+
|
229
|
+
match[:location]
|
230
|
+
end
|
231
|
+
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Occi
|
2
|
+
module Parser
|
3
|
+
module Xml
|
4
|
+
# @param [String] string
|
5
|
+
# @return [Occi::Collection]
|
6
|
+
def self.collection(string)
|
7
|
+
collection = Occi::Collection.new
|
8
|
+
hash = Hashie::Mash.new(Hash.from_xml(Nokogiri::XML(string)))
|
9
|
+
collection.kinds.merge hash.kinds.collect { |kind| Occi::Core::Kind.new(kind.scheme, kind.term, kind.title, kind.attributes, 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.related, mixin.actions) } 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) } if hash.links
|
14
|
+
collection
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|