occi-core 4.0.0.alpha.1

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