From: Michal Fojtik <[email protected]>
---
server/lib/deltacloud/drivers/ec2/ec2_driver.rb | 13 +++++++-
.../lib/deltacloud/drivers/gogrid/gogrid_driver.rb | 3 +-
.../drivers/mock/data/instances/inst0.yml | 1 +
.../drivers/mock/data/instances/inst1.yml | 1 +
.../drivers/mock/data/instances/inst2.yml | 1 +
server/lib/deltacloud/drivers/mock/mock_driver.rb | 28 ++++++++++++++++
.../drivers/rackspace/rackspace_driver.rb | 34 ++++++++++----------
.../lib/deltacloud/helpers/application_helper.rb | 28 ++++++++++++++++
server/lib/deltacloud/models/instance.rb | 5 +++
server/server.rb | 26 +++++++++++++++
server/views/images/new.html.haml | 14 ++++++++
server/views/images/show.xml.haml | 3 ++
server/views/instances/show.html.haml | 5 +++
server/views/instances/show.xml.haml | 6 +++
14 files changed, 149 insertions(+), 19 deletions(-)
create mode 100644 server/views/images/new.html.haml
diff --git a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
index d657429..3bb91bc 100644
--- a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
+++ b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
@@ -155,6 +155,15 @@ module Deltacloud
end
end
+ def create_image(credentials, opts={})
+ ec2 = new_client(credentials)
+ instance = instance(credentials, :id => opts[:id])
+ safely do
+ new_image_id = ec2.create_image(instance.id, opts[:name],
opts[:description])
+ image(credentials, :id => new_image_id)
+ end
+ end
+
def instances(credentials, opts={})
ec2 = new_client(credentials)
inst_arr = []
@@ -598,6 +607,7 @@ module Deltacloud
end
def convert_instance(instance)
+ can_create_image = 'ebs'.eql?(instance[:root_device_type]) and
'RUNNING'.eql?(convert_state(instance[:aws_state]))
Instance.new(
:id => instance[:aws_instance_id],
:name => instance[:aws_image_id],
@@ -610,7 +620,8 @@ module Deltacloud
:instance_profile =>
InstanceProfile.new(instance[:aws_instance_type]),
:realm_id => instance[:aws_availability_zone],
:private_addresses => instance[:private_dns_name],
- :public_addresses => instance[:dns_name]
+ :public_addresses => instance[:dns_name],
+ :create_image => can_create_image
)
end
diff --git a/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
b/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
index 0b027bd..b769609 100644
--- a/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
+++ b/server/lib/deltacloud/drivers/gogrid/gogrid_driver.rb
@@ -446,7 +446,8 @@ class GogridDriver < Deltacloud::BaseDriver
:public_addresses => [ instance['ip']['ip'] ],
:private_addresses => [],
:username => instance['username'],
- :password => instance['password']
+ :password => instance['password'],
+ :create_image => 'true'.eql?(instance['isSandbox'])
)
end
diff --git a/server/lib/deltacloud/drivers/mock/data/instances/inst0.yml
b/server/lib/deltacloud/drivers/mock/data/instances/inst0.yml
index a5b73be..d5f9fae 100644
--- a/server/lib/deltacloud/drivers/mock/data/instances/inst0.yml
+++ b/server/lib/deltacloud/drivers/mock/data/instances/inst0.yml
@@ -14,3 +14,4 @@
:actions:
- :reboot
- :stop
+:create_image: true
diff --git a/server/lib/deltacloud/drivers/mock/data/instances/inst1.yml
b/server/lib/deltacloud/drivers/mock/data/instances/inst1.yml
index 3544d40..746daa2 100644
--- a/server/lib/deltacloud/drivers/mock/data/instances/inst1.yml
+++ b/server/lib/deltacloud/drivers/mock/data/instances/inst1.yml
@@ -7,3 +7,4 @@
:realm_id: us
:instance_profile: !ruby/object:InstanceProfile
id: m1-small
+:create_image: true
diff --git a/server/lib/deltacloud/drivers/mock/data/instances/inst2.yml
b/server/lib/deltacloud/drivers/mock/data/instances/inst2.yml
index 9a70cb8..662bbb9 100644
--- a/server/lib/deltacloud/drivers/mock/data/instances/inst2.yml
+++ b/server/lib/deltacloud/drivers/mock/data/instances/inst2.yml
@@ -7,3 +7,4 @@
:realm_id: us
:instance_profile: !ruby/object:InstanceProfile
id: m1-large
+:create_image: true
diff --git a/server/lib/deltacloud/drivers/mock/mock_driver.rb
b/server/lib/deltacloud/drivers/mock/mock_driver.rb
index fa18d77..7d229c4 100644
--- a/server/lib/deltacloud/drivers/mock/mock_driver.rb
+++ b/server/lib/deltacloud/drivers/mock/mock_driver.rb
@@ -135,6 +135,33 @@ class MockDriver < Deltacloud::BaseDriver
images.sort_by{|e| [e.owner_id,e.description]}
end
+ def create_image(credentials, opts={})
+ check_credentials(credentials)
+ instance = instance(credentials, :id => opts[:instance_id])
+ raise BackendError::new(500, 'CreateImageNotSupported', '', '') unless
instance.can_create_image?
+ ids = Dir[ "#{@storage_root}/images/*.yml" ].collect{|e| File.basename( e,
".yml" )}
+ count = 0
+ while true
+ next_id = "img#{count}"
+ break if not ids.include?(next_id)
+ count += 1
+ end
+ safely do
+ image = {
+ :name => opts[:name],
+ :owner_id => 'root',
+ :description => opts[:description],
+ :architecture => 'i386',
+ :state => 'UP'
+ }
+ File.open( "#{@storage_root}/images/#{next_id}.yml", 'w' ) do |f|
+ YAML.dump( image, f )
+ end
+ image[:id] = next_id
+ Image.new(image)
+ end
+ end
+
#
# Instances
#
@@ -197,6 +224,7 @@ class MockDriver < Deltacloud::BaseDriver
:private_addresses=>["#{image_id}.#{next_id}.private.com"],
:instance_profile => InstanceProfile.new(hwp.name, opts),
:realm_id=>realm_id,
+ :create_image=>true,
:actions=>instance_actions_for( 'RUNNING' )
}
File.open( "#{@storage_root}/instances/#{next_id}.yml", 'w' ) {|f|
diff --git a/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
b/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
index 1851c6b..a4272e1 100644
--- a/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
+++ b/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
@@ -91,23 +91,21 @@ class RackspaceDriver < Deltacloud::BaseDriver
result
end
- # TODO: This action is reserved for create image from instance
- #
- #def create_image(credentials, opts={})
- # rs = new_client(credentials)
- # safely do
- # server = rs.get_server(opts[:id].to_i)
- # image = server.create_image(opts[:name])
- # Image.new(
- # :id => image.id.to_s,
- # :name => image.name,
- # :description => image.name,
- # :owner_id => credentials.user,
- # :state => image.status,
- # :architecture => 'x86_64'
- # )
- # end
- #end
+ def create_image(credentials, opts={})
+ rs = new_client(credentials)
+ safely do
+ server = rs.get_server(opts[:id].to_i)
+ image = server.create_image(opts[:name])
+ Image.new(
+ :id => image.id.to_s,
+ :name => image.name,
+ :description => image.name,
+ :owner_id => credentials.user,
+ :state => image.status,
+ :architecture => 'x86_64'
+ )
+ end
+ end
def run_on_instance(credentials, opts={})
target = instance(credentials, :id => opts[:id])
@@ -359,6 +357,7 @@ private
:password => password ? password : nil
)
inst.actions = instance_actions_for(inst.state)
+ inst.create_image = 'RUNNING'.eql?(inst.state)
inst
end
@@ -376,6 +375,7 @@ private
:public_addresses => server[:addresses][:public],
:private_addresses => server[:addresses][:private]
)
+ inst.create_image = 'RUNNING'.eql?(inst.state)
inst.actions = instance_actions_for(inst.state)
inst
end
diff --git a/server/lib/deltacloud/helpers/application_helper.rb
b/server/lib/deltacloud/helpers/application_helper.rb
index 191a0c9..342b0a0 100644
--- a/server/lib/deltacloud/helpers/application_helper.rb
+++ b/server/lib/deltacloud/helpers/application_helper.rb
@@ -198,4 +198,32 @@ module ApplicationHelper
"#{text[0..(length/2)]}#{end_string}"
end
+ # This will produce params block for links in XML
+ # Format:
+ #
+ # - generate_action_params(:images, :create) do |param|
+ # = param.call(:instance_id => @instance.id)
+ #
+ # =>
+ #
+ # <link href="http://localhost:3001/api/images" method="post"
rel="create_image">
+ # <param name="description" type="string"/>
+ # <param name="name" type="string"/>
+ # <param name="instance_id" required="required" type="string"
value="i-e90ead85"/>
+ # </link>
+ #
+ # Then param.call() will set a default value for parameters specified in the
+ # Hash
+ #
+ def generate_action_params(collection, operation, &block)
+ collections[collection].operations[operation].params.each do |name, param|
+ tag = Proc.new { |config|
+ capture_haml do
+ value = config[name] ? config[name] : nil
+ haml_tag :param, :name => name, :required =>
'required'.eql?(param.type.to_s), :type => param.klass, :value => value
+ end
+ }
+ yield tag
+ end
+ end
end
diff --git a/server/lib/deltacloud/models/instance.rb
b/server/lib/deltacloud/models/instance.rb
index 6345590..38807bc 100644
--- a/server/lib/deltacloud/models/instance.rb
+++ b/server/lib/deltacloud/models/instance.rb
@@ -32,6 +32,11 @@ class Instance < BaseModel
attr_accessor :authn_error
attr_accessor :username
attr_accessor :password
+ attr_accessor :create_image
+
+ def can_create_image?
+ self.create_image
+ end
def to_s
name
diff --git a/server/server.rb b/server/server.rb
index fe723c5..e146704 100644
--- a/server/server.rb
+++ b/server/server.rb
@@ -140,6 +140,13 @@ END
end
+get "/api/images/new" do
+ @instance = Instance.new( :id => params[:instance_id] )
+ respond_to do |format|
+ format.html { haml :"images/new" }
+ end
+end
+
collection :images do
description <<END
An image is a platonic form of a machine. Images are not directly executable,
@@ -165,6 +172,25 @@ END
control { show(:image) }
end
+ operation :create do
+ description 'Create image from instance'
+ with_capability :create_image
+ param :instance_id, :string, :required
+ param :name, :string, :optional
+ param :description, :string, :optional
+ control do
+ @image = driver.create_image(credentials, {
+ :id => params[:instance_id],
+ :name => params[:name],
+ :description => params[:description]
+ })
+ respond_to do |format|
+ format.xml { haml :"images/show" }
+ format.html { haml :"images/show" }
+ end
+ end
+ end
+
end
collection :instance_states do
diff --git a/server/views/images/new.html.haml
b/server/views/images/new.html.haml
new file mode 100644
index 0000000..728fa5d
--- /dev/null
+++ b/server/views/images/new.html.haml
@@ -0,0 +1,14 @@
+%h1 Create image from #{@instance.id}
+
+%form{ :action => images_url, :method => :post, :class => :new_instance }
+ %input{ :name => :instance_id, :type => :hidden, :value => @instance.id }/
+ %p
+ %label
+ Name:
+ %input{ :name => :name, :size => 30, :type => :text }/
+ %p
+ %label
+ Description:
+ %textarea{ :name => :description, :cols => 70, :rows => 20}
+ %p
+ %input{ :type => :submit, :value => 'Create' }
diff --git a/server/views/images/show.xml.haml
b/server/views/images/show.xml.haml
index c3e2cc4..8d50913 100644
--- a/server/views/images/show.xml.haml
+++ b/server/views/images/show.xml.haml
@@ -3,3 +3,6 @@
- @image.attributes.select{ |attr| attr!=:id }.each do |attribute|
- haml_tag(attribute, :<) do
- haml_concat @image.send(attribute)
+ %link{ :rel => 'create_instance', :method => :post, :href => instances_url}
+ - generate_action_params(:instances, :create) do |param|
+ = param.call(:image_id => @image.id)
diff --git a/server/views/instances/show.html.haml
b/server/views/instances/show.html.haml
index 76d77ba..9fc0916 100644
--- a/server/views/instances/show.html.haml
+++ b/server/views/instances/show.html.haml
@@ -50,3 +50,8 @@
%dd
[email protected] do |action|
=link_to_action action, self.send(:"#{action}_instance_url",
@instance.id), instance_action_method(action)
+ %dt
+ %dd
+ - if @instance.can_create_image?
+ =link_to_action 'Create Image',
url_for("/api/images/new?instance_id=#{@instance.id}"), :get
+
diff --git a/server/views/instances/show.xml.haml
b/server/views/instances/show.xml.haml
index ca7e0c6..5e1b974 100644
--- a/server/views/instances/show.xml.haml
+++ b/server/views/instances/show.xml.haml
@@ -23,6 +23,12 @@
%link{:rel => instance_action, :method =>
instance_action_method(instance_action), :href =>
self.send("#{instance_action}_instance_url", @instance.id)}
- if driver.respond_to?(:run_on_instance)
%link{:rel => 'run', :method => :post, :href =>
run_instance_url(@instance.id)}
+ - generate_action_params(:instances, :run) do |param|
+ = param.call(:id => @instance.id, :password => @instance.password)
+ - if @instance.can_create_image?
+ %link{:rel => 'create_image', :method => :post, :href =>
create_image_url}
+ - generate_action_params(:images, :create) do |param|
+ = param.call(:instance_id => @instance.id)
- if @instance.instance_variables.include?("@launch_time")
%launch_time<
[email protected]_time
--
1.7.4