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.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +43 -0
  5. data/.yardopts +1 -0
  6. data/AUTHORS +9 -0
  7. data/Gemfile +11 -0
  8. data/LICENSE +13 -0
  9. data/README.md +212 -0
  10. data/Rakefile +28 -0
  11. data/config/occi.yml +4 -0
  12. data/ext/mkrf_conf.rb +35 -0
  13. data/lib/occi/collection.rb +192 -0
  14. data/lib/occi/core/action.rb +32 -0
  15. data/lib/occi/core/action_instance.rb +38 -0
  16. data/lib/occi/core/actions.rb +20 -0
  17. data/lib/occi/core/attribute.rb +99 -0
  18. data/lib/occi/core/attributes.rb +172 -0
  19. data/lib/occi/core/categories.rb +51 -0
  20. data/lib/occi/core/category.rb +153 -0
  21. data/lib/occi/core/entities.rb +47 -0
  22. data/lib/occi/core/entity.rb +264 -0
  23. data/lib/occi/core/kind.rb +58 -0
  24. data/lib/occi/core/kinds.rb +22 -0
  25. data/lib/occi/core/link.rb +95 -0
  26. data/lib/occi/core/links.rb +34 -0
  27. data/lib/occi/core/mixin.rb +55 -0
  28. data/lib/occi/core/mixins.rb +41 -0
  29. data/lib/occi/core/properties.rb +35 -0
  30. data/lib/occi/core/related.rb +7 -0
  31. data/lib/occi/core/resource.rb +78 -0
  32. data/lib/occi/core/resources.rb +14 -0
  33. data/lib/occi/core.rb +31 -0
  34. data/lib/occi/helpers/inspect.rb +12 -0
  35. data/lib/occi/infrastructure/compute.rb +122 -0
  36. data/lib/occi/infrastructure/network/ipnetwork.rb +27 -0
  37. data/lib/occi/infrastructure/network.rb +107 -0
  38. data/lib/occi/infrastructure/networkinterface/ipnetworkinterface.rb +27 -0
  39. data/lib/occi/infrastructure/networkinterface.rb +103 -0
  40. data/lib/occi/infrastructure/os_tpl.rb +19 -0
  41. data/lib/occi/infrastructure/resource_tpl.rb +19 -0
  42. data/lib/occi/infrastructure/storage.rb +61 -0
  43. data/lib/occi/infrastructure/storagelink.rb +56 -0
  44. data/lib/occi/infrastructure.rb +25 -0
  45. data/lib/occi/log.rb +66 -0
  46. data/lib/occi/model.rb +86 -0
  47. data/lib/occi/parser/json.rb +34 -0
  48. data/lib/occi/parser/ova.rb +35 -0
  49. data/lib/occi/parser/ovf.rb +154 -0
  50. data/lib/occi/parser/text.rb +234 -0
  51. data/lib/occi/parser/xml.rb +18 -0
  52. data/lib/occi/parser.rb +78 -0
  53. data/lib/occi/settings.rb +9 -0
  54. data/lib/occi/version.rb +3 -0
  55. data/lib/occi-core.rb +50 -0
  56. data/occi-core.gemspec +36 -0
  57. data/spec/occi/collection_spec.rb +38 -0
  58. data/spec/occi/core/attribute_spec.rb +0 -0
  59. data/spec/occi/core/attributes_spec.rb +42 -0
  60. data/spec/occi/core/categories_spec.rb +27 -0
  61. data/spec/occi/core/category_spec.rb +38 -0
  62. data/spec/occi/core/entity_spec.rb +46 -0
  63. data/spec/occi/core/resource_spec.rb +18 -0
  64. data/spec/occi/infrastructure/compute_spec.rb +29 -0
  65. data/spec/occi/log_spec.rb +14 -0
  66. data/spec/occi/model_spec.rb +50 -0
  67. data/spec/occi/parser/text_spec.rb +31 -0
  68. data/spec/occi/parser_spec.rb +114 -0
  69. data/spec/occi/test.json +33 -0
  70. data/spec/occi/test.ova +0 -0
  71. data/spec/occi/test.ovf +198 -0
  72. data/spec/spec_helper.rb +25 -0
  73. metadata +304 -0
@@ -0,0 +1,99 @@
1
+ module Occi
2
+ module Core
3
+ module Attribute
4
+
5
+ attr_accessor :properties
6
+
7
+ end
8
+ end
9
+ end
10
+
11
+ class StringAttribute < String
12
+
13
+ attr_accessor :properties
14
+
15
+ def properties
16
+ self.properties ||= Occi::Core::Properties.new
17
+ end
18
+
19
+ end
20
+
21
+ class NumericAttribute
22
+
23
+ attr_accessor :properties
24
+
25
+ def properties
26
+ self.properties ||= Occi::Core::Properties.new :type => 'number'
27
+ end
28
+
29
+ end
30
+
31
+ class FalseClass
32
+
33
+ include Occi::Core::Attribute
34
+
35
+ def properties
36
+ self.properties ||= Occi::Core::Properties.new :type => 'boolean'
37
+ end
38
+
39
+ end
40
+
41
+ class TrueClass
42
+
43
+ include Occi::Core::Attribute
44
+
45
+ def properties
46
+ self.properties ||= Occi::Core::Properties.new :type => 'boolean'
47
+ end
48
+
49
+ end
50
+
51
+ #module Occi
52
+ # module Core
53
+ # class Attribute < Occi::Core::AttributeProperties
54
+ #
55
+ # attr_accessor :_value
56
+ #
57
+ # # @param [Hash] properties
58
+ # # @param [Hash] default
59
+ # def initialize(properties={})
60
+ # super(properties)
61
+ # case properties
62
+ # when Occi::Core::AttributeProperties
63
+ # self._value = properties._value if properties._value if properties.respond_to?('_value')
64
+ # else
65
+ # self._value = properties[:value] if properties[:value]
66
+ # end
67
+ # end
68
+ #
69
+ # def _value=(value)
70
+ # raise "value #{value} can not be assigned as the attribute is not mutable" unless self._mutable if self._value
71
+ # case self._type
72
+ # when 'number'
73
+ # raise "value #{value} from class #{value.class.name} does not match attribute property type #{self._type}" unless value.kind_of?(Numeric)
74
+ # when 'boolean'
75
+ # raise "value #{value} from class #{value.class.name} does not match attribute property type #{self._type}" unless !!value == value
76
+ # when 'string'
77
+ # raise "value #{value} from class #{value.class.name} does not match attribute property type #{self._type}" unless value.kind_of?(String) || value.kind_of?(Occi::Core::Entity)
78
+ # else
79
+ # raise "property type #{self._type} is not one of the allowed types number, boolean or string"
80
+ # end
81
+ # raise "value #{value} does not match pattern #{self._pattern}" if value.to_s.scan(Regexp.new(self._pattern)).empty? unless value.kind_of?(Occi::Core::Entity)
82
+ # @_value = value
83
+ # end
84
+ #
85
+ # def inspect
86
+ # self._value
87
+ # end
88
+ #
89
+ # def to_s
90
+ # self._value
91
+ # end
92
+ #
93
+ # def empty?
94
+ # self._value.nil?
95
+ # end
96
+ #
97
+ # end
98
+ # end
99
+ #end
@@ -0,0 +1,172 @@
1
+ module Occi
2
+ module Core
3
+ class Attributes < Hashie::Mash
4
+
5
+ attr_accessor :converted
6
+
7
+ include Occi::Helpers::Inspect
8
+
9
+ def converted?
10
+ @converted||=false
11
+ end
12
+
13
+ def [](key)
14
+ if key.to_s.include? '.'
15
+ key, string = key.to_s.split('.', 2)
16
+ attributes = super(key)
17
+ raise "Attribute with key #{key} not found" unless attributes
18
+ attributes[string]
19
+ else
20
+ super(key)
21
+ end
22
+ end
23
+
24
+ def []=(key, value)
25
+ if key.to_s.include? '.'
26
+ key, string = key.to_s.split('.', 2)
27
+ super(key, Occi::Core::Attributes.new) unless self[key].kind_of? Occi::Core::Attributes
28
+ self[key][string] = value
29
+ else
30
+ property_key = '_' + key.to_s
31
+ case value
32
+ when Occi::Core::Attributes
33
+ super(key, value)
34
+ when Occi::Core::Properties
35
+ super(key, value.clone)
36
+ super(property_key, value.clone)
37
+ when Hash
38
+ properties = Occi::Core::Properties.new(value)
39
+ super(key, properties.clone)
40
+ super(property_key, properties.clone)
41
+ when Occi::Core::Entity
42
+ raise "value #{value} derived from Occi::Core::Entity assigned but attribute of type #{self[property_key].type} required" unless self[property_key].type == 'string' if self[property_key]
43
+ raise "value #{value} does not match pattern" unless value.to_s.match '^' + self[property_key].pattern + '$' if Occi::Settings.verify_attribute_pattern if self[property_key]
44
+ super(key, value)
45
+ when String
46
+ raise "value #{value} of type String assigned but attribute of type #{self[property_key].type} required" unless self[property_key].type == 'string' if self[property_key]
47
+ raise "value #{value} does not match pattern" unless value.match '^' + self[property_key].pattern + '$' if Occi::Settings.verify_attribute_pattern if self[property_key]
48
+ super(key, value)
49
+ when Numeric
50
+ raise "value #{value} of type String assigned but attribute of type #{self[property_key].type} required" unless self[property_key].type == 'number' if self[property_key]
51
+ raise "value #{value} does not match pattern" unless value.to_s.match '^' + self[property_key].pattern + '$' if Occi::Settings.verify_attribute_pattern if self[property_key]
52
+ super(key, value)
53
+ when NilClass
54
+ super(key, value)
55
+ else
56
+ raise "value #{value} of type #{value.class} not supported as attribute"
57
+ end
58
+ end
59
+ end
60
+
61
+ def remove(attributes)
62
+ attributes.keys.each do |key|
63
+ if self.keys.include? key
64
+ case self[key]
65
+ when Occi::Core::Attributes
66
+ self[key].remove attributes[key]
67
+ else
68
+ self.delete(key)
69
+ end
70
+ end
71
+ end
72
+ self
73
+ end
74
+
75
+ def convert(attributes=Occi::Core::Attributes.new(self))
76
+ attributes.each_pair do |key, value|
77
+ next if attributes.key?(key[1..-1])
78
+ case value
79
+ when Occi::Core::Attributes
80
+ value.convert!
81
+ else
82
+ attributes[key] = nil
83
+ end
84
+ end
85
+ attributes.converted = true
86
+ attributes
87
+ end
88
+
89
+ def convert!
90
+ convert self
91
+ end
92
+
93
+ # @return [Array] key value pair of full attribute names with their corresponding values
94
+ def names
95
+ hash = {}
96
+ self.each_key do |key|
97
+ next if self.key?(key[1..-1])
98
+ if self[key].kind_of? Occi::Core::Attributes
99
+ self[key].names.each_pair { |k, v| hash[key + '.' + k] = v unless v.blank? }
100
+ else
101
+ hash[key] = self[key]
102
+ end
103
+ end
104
+ hash
105
+ end
106
+
107
+ # @param [Hash] attributes
108
+ # @return [Occi::Core::Properties] parsed Properties
109
+ def self.parse(hash)
110
+ hash ||= {}
111
+ attributes = Occi::Core::Attributes.new
112
+ hash.each_pair do |key, value|
113
+ if [:Type, :Required, :Mutable, :Default, :Description, :Pattern, :type, :required, :mutable, :default, :description, :pattern].any? { |k| value.key?(k) and not value[k].kind_of? Hash }
114
+ value[:type] ||= value[:Type] ||= "string"
115
+ value[:required] ||= value[:Required] ||= false
116
+ value[:mutable] ||= value[:Mutable] ||= false
117
+ value[:default] = value[:Default] if value[:Default]
118
+ value[:description] = value[:Description] if value[:Description]
119
+ value[:pattern] ||= value[:Pattern] ||= ".*"
120
+ value.delete :Type
121
+ value.delete :Required
122
+ value.delete :Mutable
123
+ value.delete :Default
124
+ value.delete :Description
125
+ value.delete :Pattern
126
+ attributes[key] = Occi::Core::Properties.new value
127
+ else
128
+ attributes[key] = self.parse attributes[key]
129
+ end
130
+ end
131
+ attributes
132
+ end
133
+
134
+ # @param [Hash] attributes key value pair of full attribute names with their corresponding values
135
+ # @return [Occi::Core::Properties]
136
+ def self.split(attributes)
137
+ attribute = Attributes.new
138
+ attributes.each do |name, value|
139
+ key, _, rest = name.partition('.')
140
+ if rest.empty?
141
+ attribute[key] = value
142
+ else
143
+ attribute.merge! Attributes.new(key => self.split(rest => value))
144
+ end
145
+ end
146
+ return attribute
147
+ end
148
+
149
+ def to_json(*a)
150
+ as_json(*a).to_json(*a)
151
+ end
152
+
153
+ # @param [Hash] options
154
+ # @return [Hashie::Mash] json representation
155
+ def as_json(options={})
156
+ hash = {}
157
+ self.each_pair do |key, value|
158
+ next if self.key?(key[1..-1])
159
+ case value
160
+ when Occi::Core::Attributes
161
+ hash[key] = value.as_json unless value.as_json.size == 0
162
+ else
163
+ hash[key] = value.as_json if value
164
+ end
165
+ end
166
+ hash
167
+ end
168
+
169
+ end
170
+
171
+ end
172
+ end
@@ -0,0 +1,51 @@
1
+ module Occi
2
+ module Core
3
+ class Categories < Set
4
+
5
+ include Occi::Helpers::Inspect
6
+
7
+ attr_accessor :model
8
+
9
+ def initialize(categories=[])
10
+ categories.collect! { |category| convert category } if categories
11
+ super categories
12
+ end
13
+
14
+ def <<(category)
15
+ super convert category
16
+ end
17
+
18
+ def join(separator)
19
+ self.to_a.join(separator)
20
+ end
21
+
22
+ # Returns a Set with all categories related to the specified category
23
+ #
24
+ # @param [Occi::Core::Category] category
25
+ # @return [Occi::Core::Categories]
26
+ def get_related_to(category)
27
+ self.class.new select { |cat| cat.related_to? category }
28
+ end
29
+
30
+ # @param [Occi::Model] model
31
+ # @return [Occi::Model]
32
+ def model=(model)
33
+ @model = model
34
+ collect! { |category| model.get_by_id category.to_s or category }
35
+ end
36
+
37
+ # @param [Hash] options
38
+ # @return [Hashie::Mash] json representation
39
+ def as_json(options={})
40
+ self.to_a.as_json
41
+ end
42
+
43
+ private
44
+
45
+ def convert(category)
46
+ (@model.get_by_id category if @model if category.kind_of? String) or category
47
+ end
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,153 @@
1
+ module Occi
2
+ module Core
3
+ class Category
4
+
5
+ include Occi::Helpers::Inspect
6
+
7
+ attr_accessor :scheme, :term, :title, :attributes, :model
8
+
9
+ def self.categories
10
+ self.mixins + self.actions << self.kind
11
+ end
12
+
13
+ # @param [String ] scheme
14
+ # @param [String] term
15
+ # @param [String] title
16
+ # @param [Hash] attributes
17
+ def initialize(scheme='http://schemas.ogf.org/occi/core#',
18
+ term='category',
19
+ title=nil,
20
+ attributes=Occi::Core::Attributes.new)
21
+ @scheme = scheme
22
+ @term = term
23
+ @title = title
24
+ case attributes
25
+ when Occi::Core::Attributes
26
+ @attributes = attributes
27
+ else
28
+ @attributes = Occi::Core::Attributes.parse attributes
29
+ end
30
+ end
31
+
32
+
33
+ # @param [String] scheme
34
+ # @param [String] term
35
+ # @param [Array] related
36
+ # @return [Class] ruby class with scheme as namespace, term as name and related kind as super class
37
+ def self.get_class(scheme, term, related=['http://schemas.ogf.org/occi/core#entity'])
38
+ related = related.to_a.flatten
39
+ scheme += '#' unless scheme.end_with? '#'
40
+
41
+ if related.first.to_s == 'http://schemas.ogf.org/occi/core#entity' or related.first.nil?
42
+ parent = Occi::Core::Entity
43
+ elsif related.first.kind_of? Occi::Core::Kind
44
+ parent = related.first.entity_type
45
+ elsif related.first.kind_of? Occi::Core::Mixin
46
+ parent = related.first.class
47
+ else
48
+ related_scheme, related_term = related.first.to_s.split '#'
49
+ parent = self.get_class related_scheme, related_term
50
+ end
51
+
52
+ uri = URI.parse(scheme)
53
+
54
+ namespace = if uri.host == 'schemas.ogf.org'
55
+ uri.path.reverse.chomp('/').reverse.split('/')
56
+ else
57
+ uri.host.split('.').reverse + uri.path.reverse.chomp('/').reverse.split('/')
58
+ end
59
+
60
+ namespace = namespace.inject(Object) do |mod, name|
61
+ if mod.constants.collect { |sym| sym.to_s }.include? name.capitalize
62
+ mod.const_get name.capitalize
63
+ else
64
+ mod.const_set name.capitalize, Module.new
65
+ end
66
+ end
67
+
68
+ class_name = term.gsub('-', '_').capitalize
69
+ if namespace.const_defined? class_name
70
+ klass = namespace.const_get class_name
71
+ unless klass.ancestors.include? Occi::Core::Entity or klass.ancestors.include? Occi::Core::Category
72
+ raise "OCCI Kind with type identifier #{scheme + term} could not be created as the corresponding class #{klass.to_s} already exists and is not derived from Occi::Core::Entity"
73
+ end
74
+ else
75
+ klass = namespace.const_set class_name, Class.new(parent)
76
+ klass.kind = Occi::Core::Kind.new scheme, term, nil, {}, related unless parent.ancestors.include? Occi::Core::Category
77
+ end
78
+
79
+ klass
80
+ end
81
+
82
+ # @param [Occi::Model] model
83
+ def model=(model)
84
+ @related.model=model if @related
85
+ end
86
+
87
+ # @return [String] Type identifier of the category
88
+ def type_identifier
89
+ @scheme + @term
90
+ end
91
+
92
+ # check if category is related to another category
93
+ # a category is related to another category
94
+ # if it is included in @related or
95
+ # if it is the category itself
96
+ #
97
+ # @param [String, Category] category Related Category or its type identifier
98
+ # @return [true,false] true if category is related to category_id else false
99
+ def related_to?(category)
100
+ if @related
101
+ self.related.each do |cat|
102
+ return true if cat.to_s == category.to_s
103
+ end
104
+ return true if self.to_s == category.to_s
105
+ end
106
+ false
107
+ end
108
+
109
+ # @param [Hash] options
110
+ # @return [Hashie::Mash] json representation
111
+ def as_json(options={})
112
+ category = Hashie::Mash.new
113
+ category.scheme = @scheme if @scheme
114
+ category.term = @term if @term
115
+ category.title = @title if @title
116
+ category.attributes = @attributes if @attributes.any?
117
+ category
118
+ end
119
+
120
+ # @return [String] short text representation of the category
121
+ def to_string_short
122
+ @term + ';scheme=' + @scheme.inspect + ';class=' + self.class.name.demodulize.downcase.inspect
123
+ end
124
+
125
+ # @return [String] full text representation of the category
126
+ def to_string
127
+ string = self.to_string_short
128
+ string << ';title=' + @title.inspect if @title
129
+ string
130
+ end
131
+
132
+ # @return [String] text representation
133
+ def to_text
134
+ 'Category: ' + self.to_string
135
+ end
136
+
137
+ # @return [Hash] hash containing the HTTP headers of the text/occi rendering
138
+ def to_header
139
+ {:Category => self.to_string}
140
+ end
141
+
142
+ # @return [NilClass] category itself does not have a location
143
+ def location
144
+ nil # not implemented
145
+ end
146
+
147
+ def to_s
148
+ self.type_identifier
149
+ end
150
+
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,47 @@
1
+ module Occi
2
+ module Core
3
+ class Entities < Set
4
+
5
+ include Occi::Helpers::Inspect
6
+
7
+ attr_accessor :model
8
+
9
+ def initialize(entities=[])
10
+ entities.to_a.each { |entity| entity.model = @model } if @model
11
+ super entities
12
+ end
13
+
14
+ def join(separator)
15
+ self.to_a.join(separator)
16
+ end
17
+
18
+ def model=(model)
19
+ @model = model
20
+ each { |entity| entity.model=model }
21
+ end
22
+
23
+ def check
24
+ each { |entity| entity.check }
25
+ end
26
+
27
+ def create(*args)
28
+ entity = Occi::Core::Entity.new(*args)
29
+ entity.model = @model if @model
30
+ self << entity
31
+ entity
32
+ end
33
+
34
+ def <<(entity)
35
+ entity.model = @model if @model
36
+ super entity
37
+ end
38
+
39
+ # @param [Hash] options
40
+ # @return [Hashie::Mash] json representation
41
+ def as_json(options={ })
42
+ self.to_a.as_json
43
+ end
44
+
45
+ end
46
+ end
47
+ end