occi-core 4.0.0.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|