incubator-deltacloud-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mfoj...@redhat.com
Subject [PATCH core] Added Image creation from Instances (EC2, Mock, GoGrid, Rackspace)
Date Wed, 02 Mar 2011 11:05:37 GMT
From: Michal Fojtik <mfojtik@redhat.com>

---
 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
       -@instance.actions.each 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<
       =@instance.launch_time
-- 
1.7.4


Mime
View raw message