tim 0.1.2 → 0.2.0
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.
- data/Gemfile +17 -0
- data/README.rdoc +231 -8
- data/app/controllers/tim/application_controller.rb +6 -3
- data/app/controllers/tim/base_images_controller.rb +10 -18
- data/app/controllers/tim/image_versions_controller.rb +10 -9
- data/app/controllers/tim/provider_images_controller.rb +13 -10
- data/app/controllers/tim/target_images_controller.rb +9 -7
- data/app/controllers/tim/templates_controller.rb +7 -7
- data/app/exceptions/tim/exceptions.rb +6 -0
- data/app/filters/tim/resource_link_filter.rb +56 -0
- data/app/models/tim/base_image.rb +7 -3
- data/app/models/tim/image_version.rb +4 -2
- data/app/models/tim/provider_image.rb +42 -6
- data/app/models/tim/target_image.rb +48 -9
- data/app/models/tim/template.rb +18 -3
- data/app/patches/rails/active_record/autosave_association.rb +29 -0
- data/app/validators/template_validator.rb +9 -5
- data/app/views/tim/base_images/_base_image.xml.haml +1 -0
- data/app/views/tim/target_images/_target_image.xml.haml +1 -0
- data/db/migrate/20121115151914_add_import_to_tim_base_images.rb +5 -0
- data/db/migrate/20121210131423_add_build_method_to_target_image.rb +5 -0
- data/db/migrate/20121216131814_rename_provider_account_id_attribute.rb +13 -0
- data/db/migrate/20121216134538_add_factory_base_image_id_to_image_versions.rb +5 -0
- data/lib/image_factory/model/base_image.rb +6 -0
- data/lib/tim/engine.rb +12 -0
- data/lib/tim/version.rb +1 -1
- data/spec/controllers/base_images_controller_spec.rb +24 -8
- data/spec/controllers/image_versions_controller_spec.rb +20 -7
- data/spec/controllers/provider_images_controller_spec.rb +19 -6
- data/spec/controllers/target_images_controller_spec.rb +22 -8
- data/spec/factories/tim/base_image.rb +5 -1
- data/spec/factories/tim/image_factory/target_image.rb +1 -0
- data/spec/factories/tim/image_version.rb +4 -0
- data/spec/factories/tim/provider_image.rb +4 -1
- data/spec/factories/tim/target_image.rb +6 -2
- data/spec/filters/resource_link_filter_spec.rb +158 -0
- data/spec/models/base_image_spec.rb +5 -5
- data/spec/models/dummy/pool_family_spec.rb +1 -1
- data/spec/models/dummy/provider_account_spec.rb +3 -1
- data/spec/models/dummy/provider_type_spec.rb +2 -1
- data/spec/models/dummy/user_spec.rb +1 -1
- data/spec/models/image_version_spec.rb +4 -3
- data/spec/models/provider_image_spec.rb +28 -5
- data/spec/models/target_image_spec.rb +74 -4
- data/spec/models/template_spec.rb +11 -2
- data/spec/validators/template_validator_spec.rb +10 -0
- data/spec/views/base_images_spec.rb +2 -1
- data/spec/views/provider_images_spec.rb +1 -0
- data/test/dummy/app/decorators/tim/controllers/base_images_controller_decorator.rb +13 -0
- data/test/dummy/config/database.yml +0 -3
- data/test/dummy/config/initializers/tim.rb +1 -1
- data/test/dummy/config/routes.rb +6 -1
- data/test/dummy/db/migrate/20121216133232_add_provider_account_id_to_provider_images.rb +5 -0
- data/test/dummy/db/schema.rb +28 -24
- data/tim.gemspec +32 -0
- metadata +46 -60
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +0 -982
- data/test/dummy/log/test.log +0 -8629
- data/test/dummy/tmp/cache/assets/C7A/BB0/sprockets%2F13445f7a19078dd2df39517062aa6711 +0 -0
- data/test/dummy/tmp/cache/assets/C8C/CC0/sprockets%2F95d79f3b3096348427f3e4e38b5202e3 +0 -0
- data/test/dummy/tmp/cache/assets/CB0/2B0/sprockets%2F79106b90879c02a115d7f6f1c8390ac4 +0 -0
- data/test/dummy/tmp/cache/assets/CE0/690/sprockets%2F04c628c2a636286bfa92a4966b82b92a +0 -0
- data/test/dummy/tmp/cache/assets/D03/040/sprockets%2Fd9e94204d4b307145f12efc109b16c1f +0 -0
- data/test/dummy/tmp/cache/assets/D06/DC0/sprockets%2Fcd282851b6e4c463409ba3ece67e0510 +0 -0
- data/test/dummy/tmp/cache/assets/D23/5F0/sprockets%2F2a521f3183c6bbcd71bd26a5490b201e +0 -0
- data/test/dummy/tmp/cache/assets/D64/3A0/sprockets%2F56ac1aed10c39b12a88cb1b30f668f58 +0 -0
- data/test/dummy/tmp/cache/assets/D69/BD0/sprockets%2F0aaf75cf34556b33a9fec534fe4d0415 +0 -0
- data/test/dummy/tmp/cache/assets/D87/D80/sprockets%2Fefa3c8b210e87358c7add88cd6f49597 +0 -0
- data/test/dummy/tmp/cache/assets/D89/200/sprockets%2Ff9b4e953c874ed6a87de6490d055d9db +0 -0
- data/test/dummy/tmp/cache/assets/DF4/430/sprockets%2F403bb1de60cae4325cebd7e6c389b8ad +0 -0
- data/test/dummy/tmp/cache/assets/E00/500/sprockets%2Faaddc5b6f2cb6b98930cc54cf4c64a95 +0 -0
- data/test/dummy/tmp/cache/assets/EB3/CE0/sprockets%2Fd75a89c9fffacd99bce7eed96844eafc +0 -0
|
@@ -2,26 +2,28 @@ module Tim
|
|
|
2
2
|
class TargetImagesController < Tim::ApplicationController
|
|
3
3
|
respond_to :json, :only => :update
|
|
4
4
|
|
|
5
|
+
prepend_before_filter ResourceLinkFilter.new({ :target_image => :image_version }),
|
|
6
|
+
:only => [:create]
|
|
5
7
|
before_filter :factory_keys, :only => :update
|
|
6
8
|
|
|
7
9
|
def index
|
|
8
10
|
@target_images = Tim::TargetImage.all unless defined? @target_images
|
|
9
|
-
respond_with @
|
|
11
|
+
respond_with(@target_images, @respond_options)
|
|
10
12
|
end
|
|
11
13
|
|
|
12
14
|
def show
|
|
13
15
|
@target_image = Tim::TargetImage.find(params[:id]) unless defined? @target_image
|
|
14
|
-
respond_with @
|
|
16
|
+
respond_with(@target_image, @respond_options)
|
|
15
17
|
end
|
|
16
18
|
|
|
17
19
|
def new
|
|
18
20
|
@target_image = Tim::TargetImage.new unless defined? @target_image
|
|
19
|
-
respond_with @
|
|
21
|
+
respond_with(@target_image, @respond_options)
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
def edit
|
|
23
25
|
@target_image = Tim::TargetImage.find(params[:id]) unless defined? @target_image
|
|
24
|
-
respond_with @
|
|
26
|
+
respond_with(@target_image, @respond_options)
|
|
25
27
|
end
|
|
26
28
|
|
|
27
29
|
def create
|
|
@@ -29,7 +31,7 @@ module Tim
|
|
|
29
31
|
if @target_image.save
|
|
30
32
|
flash[:notice] = 'Image version was successfully created.'
|
|
31
33
|
end
|
|
32
|
-
respond_with @
|
|
34
|
+
respond_with(@target_image, @respond_options)
|
|
33
35
|
end
|
|
34
36
|
|
|
35
37
|
def update
|
|
@@ -37,7 +39,7 @@ module Tim
|
|
|
37
39
|
if @target_image.update_attributes(params[:target_image])
|
|
38
40
|
flash[:notice] = 'Target image was successfully updated.'
|
|
39
41
|
end
|
|
40
|
-
respond_with @
|
|
42
|
+
respond_with(@target_image, @respond_options)
|
|
41
43
|
end
|
|
42
44
|
|
|
43
45
|
# DELETE /target_images/1
|
|
@@ -45,7 +47,7 @@ module Tim
|
|
|
45
47
|
def destroy
|
|
46
48
|
@target_image = Tim::TargetImage.find(params[:id]) unless defined? @target_image
|
|
47
49
|
@target_image.destroy
|
|
48
|
-
respond_with @
|
|
50
|
+
respond_with(@target_image, @respond_options)
|
|
49
51
|
end
|
|
50
52
|
|
|
51
53
|
# TODO Add factory permission check
|
|
@@ -3,22 +3,22 @@ module Tim
|
|
|
3
3
|
|
|
4
4
|
def index
|
|
5
5
|
@templates = Tim::Template.all unless defined? @templates
|
|
6
|
-
respond_with @
|
|
6
|
+
respond_with(@templates, @respond_options)
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
def show
|
|
10
10
|
@template = Tim::Template.find(params[:id]) unless defined? @template
|
|
11
|
-
respond_with @
|
|
11
|
+
respond_with(@template, @respond_options)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def new
|
|
15
15
|
@template = Tim::Template.new unless defined? @template
|
|
16
|
-
respond_with @
|
|
16
|
+
respond_with(@template, @respond_options)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def edit
|
|
20
20
|
@template = Tim::Template.find(params[:id])
|
|
21
|
-
respond_with @
|
|
21
|
+
respond_with(@template, @respond_options)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def create
|
|
@@ -26,7 +26,7 @@ module Tim
|
|
|
26
26
|
if @template.save
|
|
27
27
|
flash[:notice] = 'Template was successfully created.'
|
|
28
28
|
end
|
|
29
|
-
respond_with @
|
|
29
|
+
respond_with(@template, @respond_options)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def update
|
|
@@ -34,13 +34,13 @@ module Tim
|
|
|
34
34
|
if @template.update_attributes(params[:template])
|
|
35
35
|
flash[:notice] = 'Template was successfully updated.'
|
|
36
36
|
end
|
|
37
|
-
respond_with @
|
|
37
|
+
respond_with(@template, @respond_options)
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def destroy
|
|
41
41
|
@template = Tim::Template.find(params[:id]) unless defined? @template
|
|
42
42
|
@template.destroy
|
|
43
|
-
respond_with @
|
|
43
|
+
respond_with(@template, @respond_options)
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Before filter for controllers that handle REST API requests. Conductor uses
|
|
2
|
+
# linking to resources like <pool id='1'/> (resulting in :pool => { :id => 1 }
|
|
3
|
+
# in request params hash) but ActiveRecord expects linking to resources like
|
|
4
|
+
# <pool_id>1</pool_id> (resluting in :pool_id => 1 in request params hash).
|
|
5
|
+
#
|
|
6
|
+
# This before filter operates on request params hash to rewrite it from our
|
|
7
|
+
# format to ActiveRecord-friendly format.
|
|
8
|
+
#
|
|
9
|
+
# The constructor of the filter accepts specification of what should be
|
|
10
|
+
# transformed. E.g.:
|
|
11
|
+
#
|
|
12
|
+
# before_filter ResourceLinkFilter.new({ :catalog => :pool }),
|
|
13
|
+
# :only => [:create, :update]
|
|
14
|
+
#
|
|
15
|
+
# would transform { :catalog => { :pool => { :id => 1 }}}
|
|
16
|
+
# into { :catalog => { :pool_id => 1 }}
|
|
17
|
+
#
|
|
18
|
+
# See the specs in spec/util/resource_link_filter_spec.rb for more examples.
|
|
19
|
+
#
|
|
20
|
+
|
|
21
|
+
# NOTE This filter was taken from the aeolus conductor project: https://github.com/aeolusproject/conductor/
|
|
22
|
+
|
|
23
|
+
class Tim::ResourceLinkFilter
|
|
24
|
+
def initialize(resource_links)
|
|
25
|
+
@resource_links = resource_links
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def before(controller)
|
|
29
|
+
return unless controller.request.format == :xml
|
|
30
|
+
|
|
31
|
+
transform_resource_links_recursively(controller.params, @resource_links)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def transform_resource_links_recursively(subparams, sublinks)
|
|
38
|
+
return if subparams == nil
|
|
39
|
+
|
|
40
|
+
case sublinks
|
|
41
|
+
when Symbol # then transform the link (last level of recursion)
|
|
42
|
+
return if subparams[sublinks] == nil || subparams[sublinks][:id] == nil
|
|
43
|
+
|
|
44
|
+
subparams[:"#{sublinks}_id"] = subparams[sublinks][:id]
|
|
45
|
+
subparams.delete(sublinks)
|
|
46
|
+
when Array # then process each item
|
|
47
|
+
sublinks.each do |item|
|
|
48
|
+
transform_resource_links_recursively(subparams, item)
|
|
49
|
+
end
|
|
50
|
+
when Hash # then descend into each entry
|
|
51
|
+
sublinks.each_key do |key|
|
|
52
|
+
transform_resource_links_recursively(subparams[key], sublinks[key])
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
module Tim
|
|
2
2
|
class BaseImage < Tim::Base
|
|
3
|
-
has_many :image_versions
|
|
4
|
-
belongs_to :template
|
|
3
|
+
has_many :image_versions, :inverse_of => :base_image
|
|
4
|
+
belongs_to :template, :inverse_of => :base_images
|
|
5
|
+
|
|
5
6
|
belongs_to :user, :class_name => Tim.user_class
|
|
6
7
|
|
|
7
8
|
accepts_nested_attributes_for :template
|
|
8
9
|
accepts_nested_attributes_for :image_versions
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
validates_presence_of :name
|
|
12
|
+
validates_presence_of :template, :unless => :import
|
|
13
|
+
|
|
14
|
+
attr_accessible :template, :name, :description, :import
|
|
11
15
|
attr_accessible :template_attributes
|
|
12
16
|
attr_accessible :image_versions_attributes, :as => :admin
|
|
13
17
|
attr_protected :id
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
module Tim
|
|
2
2
|
class ImageVersion < Tim::Base
|
|
3
|
-
belongs_to :base_image
|
|
4
|
-
has_many :target_images
|
|
3
|
+
belongs_to :base_image, :inverse_of => :image_versions
|
|
4
|
+
has_many :target_images, :inverse_of => :image_version
|
|
5
5
|
|
|
6
6
|
accepts_nested_attributes_for :base_image
|
|
7
7
|
accepts_nested_attributes_for :target_images
|
|
8
8
|
|
|
9
|
+
validates_presence_of :base_image
|
|
10
|
+
|
|
9
11
|
attr_accessible :base_image_attributes
|
|
10
12
|
attr_accessible :target_images_versions_attributes
|
|
11
13
|
attr_protected :id
|
|
@@ -1,37 +1,63 @@
|
|
|
1
1
|
module Tim
|
|
2
2
|
class ProviderImage < Tim::Base
|
|
3
|
-
belongs_to :target_image
|
|
3
|
+
belongs_to :target_image, :inverse_of => :provider_images
|
|
4
4
|
belongs_to :provider_account, :class_name => Tim.provider_account_class
|
|
5
5
|
|
|
6
6
|
accepts_nested_attributes_for :target_image
|
|
7
7
|
|
|
8
8
|
attr_accessible :target_image_attributes
|
|
9
|
+
attr_accessible :external_image_id, :if => :imported?
|
|
9
10
|
attr_accessible :status, :status_detail, :progress #, :as => :image_factory
|
|
10
11
|
attr_accessible :provider
|
|
11
12
|
attr_writer :credentials
|
|
12
13
|
attr_protected :id
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
validates_presence_of :target_image
|
|
16
|
+
validates_presence_of :external_image_id, :if => :imported?
|
|
17
|
+
|
|
18
|
+
after_create :create_factory_provider_image, :unless => :imported?
|
|
19
|
+
after_create :create_import, :if => :imported?
|
|
20
|
+
|
|
21
|
+
def imported?
|
|
22
|
+
target_image.imported?
|
|
23
|
+
end
|
|
15
24
|
|
|
16
25
|
private
|
|
26
|
+
def factory_provider_credentials
|
|
27
|
+
@credentials
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def factory_provider
|
|
31
|
+
self.provider
|
|
32
|
+
end
|
|
33
|
+
|
|
17
34
|
def create_factory_provider_image
|
|
18
35
|
begin
|
|
19
|
-
provider_image = ImageFactory::ProviderImage.new(:
|
|
20
|
-
:provider => self.provider,
|
|
21
|
-
:credentials => @credentials,
|
|
36
|
+
provider_image = ImageFactory::ProviderImage.new(:credentials => factory_provider_credentials,
|
|
22
37
|
# TODO Remove this when upgrading to 3.2
|
|
23
38
|
# target conflicts with rails 3.0.10
|
|
24
39
|
# ActiveRecord::Associations::Association#target
|
|
25
40
|
:target => target_image.target,
|
|
26
41
|
:parameters => "")
|
|
42
|
+
provider_image.provider = factory_provider
|
|
27
43
|
# TODO There is a bug in ARes 3.0.10 that will add map name twice when setting in mass assign. So we set
|
|
28
44
|
# parameters separately.
|
|
29
45
|
# Setting parameters at mass assign results in json => {"target_image":"parameters":{"parameters":{"..."}}}"
|
|
30
46
|
# This should be tested and removed if fixed in 3.2
|
|
31
47
|
provider_image.parameters = { :callbacks => ["#{ImageFactory::ProviderImage.callback_url}/#{self.id}"] }
|
|
48
|
+
if target_image.snapshot?
|
|
49
|
+
provider_image.parameters[:snapshot] = true
|
|
50
|
+
provider_image.template = self.target_image.template.xml
|
|
51
|
+
else
|
|
52
|
+
provider_image.target_image_id = self.target_image.factory_id
|
|
53
|
+
end
|
|
54
|
+
|
|
32
55
|
provider_image.save!
|
|
33
56
|
populate_factory_fields(provider_image)
|
|
34
57
|
self.save
|
|
58
|
+
rescue Errno::ECONNREFUSED
|
|
59
|
+
raise Tim::Error::ImagefactoryConnectionRefused.new("Unable to connect"\
|
|
60
|
+
" to Imagefactory server @ #{Tim::ImageFactory::Base.site}")
|
|
35
61
|
rescue => e
|
|
36
62
|
# TODO Add proper error handling
|
|
37
63
|
raise e
|
|
@@ -45,7 +71,17 @@ module Tim
|
|
|
45
71
|
self.progress = factory_provider_image.percent_complete
|
|
46
72
|
self.provider = factory_provider_image.provider
|
|
47
73
|
self.external_image_id = factory_provider_image.identifier_on_provider
|
|
48
|
-
self.
|
|
74
|
+
self.factory_provider_account_id = factory_provider_image.provider_account_identifier
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# TODO At the moment this method simply sets fields to import defaults.
|
|
78
|
+
# We should investigate whether we can check the image exists and if the
|
|
79
|
+
# user can access it. Deltacloud?
|
|
80
|
+
def create_import
|
|
81
|
+
self.status = "COMPLETE"
|
|
82
|
+
self.progress = "COMPLETE"
|
|
83
|
+
self.status_detail = "Imported Image"
|
|
84
|
+
self.save
|
|
49
85
|
end
|
|
50
86
|
end
|
|
51
87
|
end
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
module Tim
|
|
2
2
|
class TargetImage < Tim::Base
|
|
3
|
-
belongs_to :image_version
|
|
3
|
+
belongs_to :image_version, :inverse_of => :target_images
|
|
4
|
+
has_many :provider_images, :inverse_of => :target_image
|
|
5
|
+
|
|
4
6
|
belongs_to :provider_type, :class_name => Tim.provider_type_class
|
|
5
|
-
has_many :provider_images
|
|
6
7
|
|
|
7
8
|
accepts_nested_attributes_for :image_version
|
|
8
9
|
accepts_nested_attributes_for :provider_images
|
|
9
10
|
|
|
11
|
+
validates_presence_of :image_version, :target
|
|
12
|
+
|
|
10
13
|
attr_accessible :image_version_attributes
|
|
11
14
|
attr_accessible :provider_images_attributes
|
|
12
15
|
attr_accessible :status, :status_detail, :progress #, :as => :image_factory
|
|
@@ -14,25 +17,42 @@ module Tim
|
|
|
14
17
|
|
|
15
18
|
attr_protected :id
|
|
16
19
|
|
|
17
|
-
after_create :create_factory_target_image
|
|
20
|
+
after_create :create_factory_target_image, :if => :create_factory_target_image?
|
|
21
|
+
after_create :set_import_snapshot_status, :if => lambda { |t| t.imported? || t.snapshot? }
|
|
18
22
|
|
|
19
23
|
def template
|
|
20
24
|
image_version.base_image.template
|
|
21
25
|
end
|
|
22
26
|
|
|
27
|
+
def imported?
|
|
28
|
+
image_version.base_image.import
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def snapshot?
|
|
32
|
+
build_method == "SNAPSHOT"
|
|
33
|
+
end
|
|
34
|
+
|
|
23
35
|
private
|
|
24
36
|
def create_factory_target_image
|
|
25
37
|
begin
|
|
26
|
-
target_image = ImageFactory::TargetImage.new(:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
# when a map is provided in mass assign
|
|
38
|
+
target_image = ImageFactory::TargetImage.new(:target => target,
|
|
39
|
+
:parameters => nil)
|
|
40
|
+
# A bug in ARes adds parameters twice to the resulting json when a map
|
|
41
|
+
# is provided in mass assign
|
|
31
42
|
target_image.parameters = { :callbacks => ["#{ImageFactory::TargetImage.callback_url}/#{self.id}"] }
|
|
43
|
+
|
|
44
|
+
if image_version.factory_base_image_id
|
|
45
|
+
target_image.base_image_id = image_version.factory_base_image_id
|
|
46
|
+
else
|
|
47
|
+
target_image.template = template.xml
|
|
48
|
+
end
|
|
32
49
|
target_image.save!
|
|
33
50
|
|
|
34
51
|
populate_factory_fields(target_image)
|
|
35
52
|
self.save
|
|
53
|
+
rescue Errno::ECONNREFUSED
|
|
54
|
+
raise Tim::Error::ImagefactoryConnectionRefused.new("Unable to connect"\
|
|
55
|
+
" to Imagefactory server @ #{Tim::ImageFactory::Base.site}")
|
|
36
56
|
rescue => e
|
|
37
57
|
# TODO Add proper error handling
|
|
38
58
|
raise e
|
|
@@ -44,7 +64,26 @@ module Tim
|
|
|
44
64
|
self.factory_id = factory_target_image.id
|
|
45
65
|
self.status_detail = factory_target_image.status_detail.activity
|
|
46
66
|
self.progress = factory_target_image.percent_complete
|
|
67
|
+
unless self.image_version.factory_base_image_id
|
|
68
|
+
image_version.factory_base_image_id = factory_target_image.base_image_id
|
|
69
|
+
image_version.save!
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def set_import_snapshot_status
|
|
74
|
+
self.progress = "COMPLETE"
|
|
75
|
+
self.status = "COMPLETE"
|
|
76
|
+
if self.imported?
|
|
77
|
+
self.status_detail = "Imported Image"
|
|
78
|
+
elsif self.snapshot?
|
|
79
|
+
self.status_detail = "Snapshot Image"
|
|
80
|
+
end
|
|
81
|
+
self.save
|
|
47
82
|
end
|
|
48
83
|
|
|
84
|
+
private
|
|
85
|
+
def create_factory_target_image?
|
|
86
|
+
!imported? && !snapshot?
|
|
87
|
+
end
|
|
49
88
|
end
|
|
50
|
-
end
|
|
89
|
+
end
|
data/app/models/tim/template.rb
CHANGED
|
@@ -5,15 +5,30 @@ module Tim
|
|
|
5
5
|
include ActiveModel::Validations
|
|
6
6
|
validates_with TemplateValidator
|
|
7
7
|
|
|
8
|
-
has_many :base_images
|
|
8
|
+
has_many :base_images, :inverse_of => :template
|
|
9
9
|
|
|
10
10
|
attr_accessible :xml
|
|
11
11
|
attr_protected :id
|
|
12
12
|
|
|
13
|
+
OS = Struct.new(:name, :version, :arch)
|
|
14
|
+
|
|
13
15
|
# Used in views to display the xml elements of this template
|
|
14
16
|
def xml_elements
|
|
15
|
-
|
|
17
|
+
parsed_xml.xpath("//template/*").to_xml
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def os
|
|
21
|
+
OS.new(
|
|
22
|
+
parsed_xml.xpath("//template/os/name").text,
|
|
23
|
+
parsed_xml.xpath("//template/os/version").text,
|
|
24
|
+
parsed_xml.xpath("//template/os/arch").text
|
|
25
|
+
)
|
|
16
26
|
end
|
|
17
27
|
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def parsed_xml
|
|
31
|
+
@parsed_xml ||= ::Nokogiri::XML::Document.parse(xml)
|
|
32
|
+
end
|
|
18
33
|
end
|
|
19
|
-
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# There is a bug in Rails which causes issues when using accepts_nested_attrs
|
|
2
|
+
# and inverse_of on associations: https://github.com/rails/rails/issues/7809/
|
|
3
|
+
# This code was lifted from the pull request of the bug shown above. It solves
|
|
4
|
+
# the issue. Until this is merged into rails we will have to carry the patch
|
|
5
|
+
# ourselves.
|
|
6
|
+
|
|
7
|
+
module ActiveRecord
|
|
8
|
+
module AutosaveAssociation
|
|
9
|
+
extend ActiveSupport::Concern
|
|
10
|
+
|
|
11
|
+
# Returns whether or not this record has been changed in any way (including whether
|
|
12
|
+
# any of its nested autosave associations are likewise changed)
|
|
13
|
+
def changed_for_autosave?
|
|
14
|
+
@_changed_for_autosave_called ||= false
|
|
15
|
+
if @_changed_for_autosave_called
|
|
16
|
+
# traversing a cyclic graph of objects; stop it
|
|
17
|
+
result = false
|
|
18
|
+
else
|
|
19
|
+
begin
|
|
20
|
+
@_changed_for_autosave_called = true
|
|
21
|
+
result = new_record? || changed? || marked_for_destruction? || nested_records_changed_for_autosave?
|
|
22
|
+
ensure
|
|
23
|
+
@_changed_for_autosave_called = false
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
result
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|