From: David Lutterkort <lut...@redhat.com> This makes it possible to have a full MachineConfiguration object referenced from a Machinetemplate --- server/lib/cimi/models.rb | 4 +- server/lib/cimi/models/base.rb | 5 +++ server/lib/cimi/models/machine_template.rb | 6 +-- server/lib/cimi/models/schema.rb | 44 +++++++++++++++++++++- server/tests/cimi/data/machine_create_by_value.xml | 7 ++++ server/tests/cimi/model/machine_template_spec.rb | 29 ++++++++++++++ 6 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 server/tests/cimi/data/machine_create_by_value.xml
diff --git a/server/lib/cimi/models.rb b/server/lib/cimi/models.rb index 20c0ef1..5cffc23 100644 --- a/server/lib/cimi/models.rb +++ b/server/lib/cimi/models.rb @@ -62,15 +62,15 @@ require_relative './models/cloud_entry_point' CIMI::Model::ResourceMetadata.acts_as_root_entity +require_relative './models/credential' require_relative './models/volume' require_relative './models/volume_template' require_relative './models/volume_configuration' require_relative './models/volume_image' require_relative './models/machine' -require_relative './models/machine_template' require_relative './models/machine_configuration' require_relative './models/machine_image' -require_relative './models/credential' +require_relative './models/machine_template' require_relative './models/network_port' require_relative './models/network' require_relative './models/network_template' diff --git a/server/lib/cimi/models/base.rb b/server/lib/cimi/models/base.rb index ac838a4..a96909f 100644 --- a/server/lib/cimi/models/base.rb +++ b/server/lib/cimi/models/base.rb @@ -60,6 +60,11 @@ require_relative '../helpers/database_helper' # A shorthand for +struct name { scalar :href }+; in JSON, this is # represented as +{ name: { "href": string } }+, and in XML as +<name # href="..."/>+ +# [ref(name, [klass])] +# A reference to another object, like the reference to the +# MachineConfiguration in a MachineTemplate. If +klass+ is not given, +# an attempt is made to infer the class of the target of the reference +# from +name+ # [struct(name, opts, &block)] # A structured subobject; the block defines the schema of the # subobject. The +:content+ option can be used to specify the attribute diff --git a/server/lib/cimi/models/machine_template.rb b/server/lib/cimi/models/machine_template.rb index 5ba9b3e..9e3f198 100644 --- a/server/lib/cimi/models/machine_template.rb +++ b/server/lib/cimi/models/machine_template.rb @@ -17,9 +17,9 @@ class CIMI::Model::MachineTemplate < CIMI::Model::Base acts_as_root_entity - href :machine_config - href :machine_image - href :credential + ref :machine_config + ref :machine_image + ref :credential array :volumes do scalar :href diff --git a/server/lib/cimi/models/schema.rb b/server/lib/cimi/models/schema.rb index 298075b..5a5d2c9 100644 --- a/server/lib/cimi/models/schema.rb +++ b/server/lib/cimi/models/schema.rb @@ -92,7 +92,27 @@ class CIMI::Model::Schema content = opts[:content] super(name, opts) if opts[:class] - opts[:schema] = opts[:class].schema + raise "Cannot use both :class and :schema" if opts[:schema] + refname = "#{opts[:class].name.split("::").last}Ref" + if CIMI::Model::const_defined?(refname) + @klass = CIMI::Model::const_get(refname) + else + @klass = Class.new(opts[:class]) do + scalar :href + + def ref_id(ctx) + # FIXME: We should use ctx's routes to split + # out the :id + href.split('/').last + end + + def find(ctx) + opts[:class].find(ref_id(ctx), ctx) + end + end + CIMI::Model::const_set(refname, @klass) + end + opts[:schema] = @klass.schema end if opts[:schema] if block_given? @@ -150,9 +170,21 @@ class CIMI::Model::Schema json end + def convert(value) + if @klass + @klass.new(value || {}) + else + super(value) + end + end + private def struct - @struct_class ||= ::Struct.new(nil, *@schema.attribute_names) + if @klass + @klass + else + @struct_class ||= ::Struct.new(nil, *@schema.attribute_names) + end end end @@ -375,6 +407,14 @@ class CIMI::Model::Schema add_attributes!([name, opts], Struct, &block) end + def ref(name, klass = nil) + unless klass + s = name.to_s.camelize.gsub(/Config$/, "Configuration") + klass = CIMI::Model::const_get(s) + end + struct(name, :class => klass) + end + def hash(name) add_attributes!([name, {}], Hash) end diff --git a/server/tests/cimi/data/machine_create_by_value.xml b/server/tests/cimi/data/machine_create_by_value.xml new file mode 100644 index 0000000..ecb6735 --- /dev/null +++ b/server/tests/cimi/data/machine_create_by_value.xml @@ -0,0 +1,7 @@ +<MachineCreate xmlns="http://schemas.dmtf.org/cimi/1"> + <name>xml_machine_by_value</name> + <machineTemplate> + <machineConfig href="http://localhost:3001/cimi/machine_configurations/m1-small"/> + <machineImage href="http://localhost:3001/cimi/machine_images/img2"/> + </machineTemplate> +</MachineCreate> diff --git a/server/tests/cimi/model/machine_template_spec.rb b/server/tests/cimi/model/machine_template_spec.rb index b1f6376..ed4a3d8 100644 --- a/server/tests/cimi/model/machine_template_spec.rb +++ b/server/tests/cimi/model/machine_template_spec.rb @@ -29,4 +29,33 @@ describe "MachineTemplate model" do should_properly_serialize_model CIMI::Model::MachineTemplate, @xml, @json end + describe "can have an embedded machineConfig" do + MACHINE_CONFIG_ID = "http://cimi.example.org/machine_configs/1" + + it "in XML" do + mt = CIMI::Model::MachineTemplate.from_xml(@xml) + mt.name.must_equal "My First Template" + mt.machine_config.href.must_equal MACHINE_CONFIG_ID + mt.machine_config.id.must_be_nil + mt.machine_config.cpu = 7 + + mc = parse_xml(mt.to_xml)["MachineTemplate"].first["machineConfig"].first + mc.wont_be_nil + mc["href"].must_equal MACHINE_CONFIG_ID + mc["cpu"].first["content"].must_equal "7" + end + + it "in JSON" do + mt = CIMI::Model::MachineTemplate.from_json(@json) + mt.name.must_equal "My First Template" + mt.machine_config.href.must_equal MACHINE_CONFIG_ID + mt.machine_config.id.must_be_nil + mt.machine_config.cpu = 7 + + mc = JSON::parse(mt.to_json)["machineConfig"] + mc.wont_be_nil + mc["href"].must_equal MACHINE_CONFIG_ID + mc["cpu"].must_equal 7 + end + end end -- 1.8.1