You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@deltacloud.apache.org by Mohammed Morsi <mm...@redhat.com> on 2010/08/04 22:04:47 UTC

[PATCH] added ability to scp one or more files to a running instance (rev 2)

  requires 'arbitrary command execution on instances' and
  'support array request param types with ability to specify
  type of array elements' patches to work
---
 server/deltacloud-core.gemspec                    |    1 +
 server/lib/deltacloud/base_driver/features.rb     |    4 ++
 server/lib/deltacloud/drivers/ec2/ec2_driver.rb   |    1 +
 server/lib/deltacloud/drivers/mock/mock_driver.rb |    1 +
 server/lib/deltacloud/models/instance.rb          |   12 +++++++
 server/server.rb                                  |   32 ++++++++++++++++++
 server/views/instances/copy_files.html.haml       |   36 +++++++++++++++++++++
 server/views/instances/copy_files.xml.haml        |   11 ++++++
 8 files changed, 98 insertions(+), 0 deletions(-)
 create mode 100644 server/views/instances/copy_files.html.haml
 create mode 100644 server/views/instances/copy_files.xml.haml

diff --git a/server/deltacloud-core.gemspec b/server/deltacloud-core.gemspec
index 53571e4..59b2444 100644
--- a/server/deltacloud-core.gemspec
+++ b/server/deltacloud-core.gemspec
@@ -66,6 +66,7 @@ require 'rake'
   s.add_dependency('rerun', '>= 0.5.2')
   s.add_dependency('json', '>= 1.2.3')
   s.add_dependency('net-ssh', '>= 2.0.23')
+  s.add_dependency('net-scp', '>= 1.0.2')
   s.add_development_dependency('compass', '>= 0.8.17')
   s.add_development_dependency('nokogiri', '>= 1.4.1')
   s.add_development_dependency('rack-test', '>= 0.5.3')
diff --git a/server/lib/deltacloud/base_driver/features.rb b/server/lib/deltacloud/base_driver/features.rb
index 2addbf5..895bdd2 100644
--- a/server/lib/deltacloud/base_driver/features.rb
+++ b/server/lib/deltacloud/base_driver/features.rb
@@ -160,5 +160,9 @@ module Deltacloud
       description "Run an arbitrary command against an instance"
     end
 
+    declare_feature :instances, :copy_files do
+      description "One or more files may be securely copied to an instance"
+    end
+
   end
 end
diff --git a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
index 5ad930b..7957b56 100644
--- a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
+++ b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
@@ -38,6 +38,7 @@ class EC2Driver < Deltacloud::BaseDriver
   feature :instances, :user_data
   feature :instances, :authentication_key
   feature :instances, :run_command
+  feature :instances, :copy_files
 
   define_hardware_profile('m1.small') do
     cpu                1
diff --git a/server/lib/deltacloud/drivers/mock/mock_driver.rb b/server/lib/deltacloud/drivers/mock/mock_driver.rb
index b8302c7..c400e9e 100644
--- a/server/lib/deltacloud/drivers/mock/mock_driver.rb
+++ b/server/lib/deltacloud/drivers/mock/mock_driver.rb
@@ -78,6 +78,7 @@ class MockDriver < Deltacloud::BaseDriver
 
   feature :instances, :user_name
   feature :instances, :run_command
+  feature :instances, :copy_files
 
   def initialize
     if ENV["DELTACLOUD_MOCK_STORAGE"]
diff --git a/server/lib/deltacloud/models/instance.rb b/server/lib/deltacloud/models/instance.rb
index c2c9ff4..e0cd7a6 100644
--- a/server/lib/deltacloud/models/instance.rb
+++ b/server/lib/deltacloud/models/instance.rb
@@ -17,6 +17,7 @@
 # under the License.
 
 require 'net/ssh'
+require 'net/scp'
 
 class Instance < BaseModel
 
@@ -53,4 +54,15 @@ class Instance < BaseModel
     return output
   end
 
+  def copy_files(files, destination, username='', opts={})
+    files = [files] unless files.is_a? Array
+    hostname = self.public_addresses.first
+    return "No hostname/IP address specified" unless hostname
+    Net::SCP.start(hostname, username || 'root', opts) do |session|
+      files.each { |f|
+        session.upload! f, destination
+      }
+    end
+  end
+
 end
diff --git a/server/server.rb b/server/server.rb
index 7f9f603..43fada1 100644
--- a/server/server.rb
+++ b/server/server.rb
@@ -167,6 +167,12 @@ get "/api/instances/:id/run" do
   end
 end
 
+get "/api/instances/:id/copy_files" do
+  respond_to do |format|
+    format.html { haml :"instances/copy_files"}
+  end
+end
+
 collection :instances do
   description <<END
   An instance is a concrete machine realized from an image.
@@ -256,6 +262,32 @@ END
     end
   end
 
+  operation :copy_files, :method => :post, :member => true do
+    description "Securely copy one or more files to an instance"
+    param :id,           :string,          :required
+    param :files,        :array,  :string, :required
+    param :destination,  :string,          :required
+    param :private_key,  :string
+    param :username,     :string
+    control do
+      @instance = driver.instance(credentials, { :id => params[:id] })
+      private_key = store_private_key(params[:id], params[:private_key])
+      begin
+        params[:files].delete_if { |f| f.nil? || f == "" }
+        @instance.copy_files(params[:files], params[:destination], params[:username], { :keys => private_key })
+        @output = "Files copied successfully"
+      rescue Exception => e
+        @failed = true
+        @output = "#{e.message}\n#{e.backtrace.join("\n")}"
+      ensure
+        remove_private_key(private_key)
+      end
+      respond_to do |format|
+        format.xml { haml :"instances/copy_files" }
+      end
+    end
+  end
+
 end
 
 collection :hardware_profiles do
diff --git a/server/views/instances/copy_files.html.haml b/server/views/instances/copy_files.html.haml
new file mode 100644
index 0000000..dbced55
--- /dev/null
+++ b/server/views/instances/copy_files.html.haml
@@ -0,0 +1,36 @@
+%h1 Run command
+
+%form{ :action => "/api/instances/#{params[:id]}/copy_files", :method => :post}
+  %label
+    Source File(s):
+  %br
+  %input{ :name => 'files[]', :size => 30}/
+  %br
+  %input{ :name => 'files[]', :size => 30}/
+  %br
+  %input{ :name => 'files[]', :size => 30}/
+  %br
+  %input{ :name => 'files[]', :size => 30}/
+  %br
+  %input{ :name => 'files[]', :size => 30}/
+  %br
+  %br
+
+  %label
+    Destination File or Directory:
+  %br
+  %br
+  %input{ :name => 'destination', :size => 30}/
+  %br
+  %br
+
+  %label
+    Paste private key here:
+  %p
+    %textarea{ :name => 'private_key', :cols => 30}
+  %br
+  %label
+    Username:
+  %input{ :name => 'username', :size => 30}
+  %br/
+  %input{ :type => 'submit', :value => "Run"}
diff --git a/server/views/instances/copy_files.xml.haml b/server/views/instances/copy_files.xml.haml
new file mode 100644
index 0000000..9205094
--- /dev/null
+++ b/server/views/instances/copy_files.xml.haml
@@ -0,0 +1,11 @@
+!!! XML
+%instance{:href => instance_url(@instance.id)}
+  %id<
+    =@instance.id
+  %name<
+    =@instance.name
+  %status
+    =@failed ? "FAILED" : "SUCCESS"
+  %output<
+    =cdata do
+      =@output
-- 
1.7.2