From 77d1558131ec5725efa0c19d450281e23e7998e0 Mon Sep 17 00:00:00 2001 From: marcinbunsch Date: Mon, 21 Sep 2009 17:47:40 +0200 Subject: [PATCH] changes to allow multiple projects per snail instance --- README.textile | 11 +- config/snail.yml.sample | 3 + lib/actions/general.rb | 7 ++ lib/actions/groups.rb | 30 ++++++ lib/actions/images.rb | 25 +++++ lib/actions/instances.rb | 21 ++++ lib/actions/ips.rb | 30 ++++++ lib/actions/keys.rb | 16 +++ lib/actions/s3.rb | 19 ++++ snail.rb | 203 ++++------------------------------- views/_layout_navigation.erb | 28 ++--- views/instances.erb | 8 +- views/output.erb | 2 +- views/projects.erb | 1 + views/s3_keys.erb | 6 +- 15 files changed, 204 insertions(+), 206 deletions(-) create mode 100644 config/snail.yml.sample create mode 100644 lib/actions/general.rb create mode 100644 lib/actions/groups.rb create mode 100644 lib/actions/images.rb create mode 100644 lib/actions/instances.rb create mode 100644 lib/actions/ips.rb create mode 100644 lib/actions/keys.rb create mode 100644 lib/actions/s3.rb create mode 100644 views/projects.erb diff --git a/README.textile b/README.textile index b5bc982..1b7e123 100644 --- a/README.textile +++ b/README.textile @@ -8,17 +8,18 @@ h2. Dependencies h2. Installing and Running -* git clone git://github.com/moomerman/snail.git +* git clone git://github.com/marcinbunsch/snail.git * cd snail -* create snail.yml with your aws key and secret key in (see below) +* create config/snail.yml with your aws key and secret key in (see below) * ./snail.rb * go to http://localhost:4567/ -h2. Configuration (snail.yml) +h2. Configuration (config/snail.yml)
 
-aws_key: YOUR_KEY
-aws_secret: YOUR_SECRET_KEY
+project_name:
+  aws_key: YOUR_KEY
+  aws_secret: YOUR_SECRET_KEY
 
 
\ No newline at end of file diff --git a/config/snail.yml.sample b/config/snail.yml.sample new file mode 100644 index 0000000..1657996 --- /dev/null +++ b/config/snail.yml.sample @@ -0,0 +1,3 @@ +project_name: + aws_key: YOUR_KEY + aws_secret: YOUR_SECRET \ No newline at end of file diff --git a/lib/actions/general.rb b/lib/actions/general.rb new file mode 100644 index 0000000..528f7be --- /dev/null +++ b/lib/actions/general.rb @@ -0,0 +1,7 @@ +get '/' do + redirect '/projects' +end + +get '/projects' do + erb :projects +end diff --git a/lib/actions/groups.rb b/lib/actions/groups.rb new file mode 100644 index 0000000..060cbf1 --- /dev/null +++ b/lib/actions/groups.rb @@ -0,0 +1,30 @@ +# Security Groups + +get '/:project/groups' do + @groups = @ec2.describe_security_groups + erb :groups +end + +get '/:project/group/:group_name/delete' do + @ec2.delete_security_group(params[:group_name]) + redirect '/groups' +end + +get '/:project/group/:group_name/revoke' do + if params[:group] + @ec2.revoke_security_group_named_ingress(params[:group_name], params[:owner], params[:group]) + else + @ec2.revoke_security_group_IP_ingress(params[:group_name], params[:from], params[:to], params[:protocol], params[:ip]) + end + redirect '/groups' +end + +post '/:project/group/:group_name/authorize' do + @ec2.authorize_security_group_IP_ingress(params[:group_name], params[:from], params[:to], params[:protocol], params[:ip]) + redirect '/groups' +end + +post '/:project/group' do + @ec2.create_security_group(params[:name], params[:description]) + redirect '/groups' +end \ No newline at end of file diff --git a/lib/actions/images.rb b/lib/actions/images.rb new file mode 100644 index 0000000..46b5683 --- /dev/null +++ b/lib/actions/images.rb @@ -0,0 +1,25 @@ +# Images + +get '/:project/images' do + @@images ||= @ec2.describe_images.find_all{|x| x[:aws_image_type] == 'machine'} + @i386 = @@images.find_all{|x| x[:aws_architecture] == 'i386'}.sort {|x,y| x[:aws_location] <=> y[:aws_location] } + @x86_64 = @@images.find_all{|x| x[:aws_architecture] == 'x86_64'}.sort {|x,y| x[:aws_location] <=> y[:aws_location] } + erb :images +end + +get '/:project/images/:image_id/launch' do + @ec2.launch_instances(params[:image_id], :group_ids => 'default', + :user_data => "Woohoo!!!", + :addressing_type => "public", + :key_name => "default", + :availability_zone => "us-east-1c") + redirect '/instances' +end + +get '/:project/images/search*' do + params[:query] ||= request.path_info.split('/')[3] + redirect '/images' if params[:query].empty? + @i386 = @@images.find_all{|x| x[:aws_architecture] == 'i386' and x.inspect =~ /#{params[:query]}/i}.sort {|x,y| x[:aws_location] <=> y[:aws_location] } + @x86_64 = @@images.find_all{|x| x[:aws_architecture] == 'x86_64' and x.inspect =~ /#{params[:query]}/i}.sort {|x,y| x[:aws_location] <=> y[:aws_location] } + erb :images +end \ No newline at end of file diff --git a/lib/actions/instances.rb b/lib/actions/instances.rb new file mode 100644 index 0000000..19b31b5 --- /dev/null +++ b/lib/actions/instances.rb @@ -0,0 +1,21 @@ +# Instances + +get '/:project/instances' do + @instances = @ec2.describe_instances.reverse + erb :instances +end + +get '/:project/instance/:instance_id/terminate' do + @output = @ec2.terminate_instances(params[:instance_id]) + redirect '/instances' +end + +get '/:project/instance/:instance_id/output' do + @output = @ec2.get_console_output(params[:instance_id]) + erb :output +end + +get '/:project/instance/:instance_id/reboot' do + @ec2.reboot_instances([params[:instance_id]]) + redirect '/instances' +end diff --git a/lib/actions/ips.rb b/lib/actions/ips.rb new file mode 100644 index 0000000..721a1e7 --- /dev/null +++ b/lib/actions/ips.rb @@ -0,0 +1,30 @@ +# Elastic IP addresses + +get '/:project/addresses' do + @addresses = @ec2.describe_addresses + @instances = @ec2.describe_instances.reverse + erb :addresses +end + +get '/:project/addresses/allocate' do + @ec2.allocate_address + redirect '/addresses' +end + +get '/:project/address/*/release' do + ip_address = request.path_info.split('/')[2] + @ec2.release_address(ip_address) + redirect '/addresses' +end + +post '/:project/address/*/associate' do + ip_address = request.path_info.split('/')[2] + @ec2.associate_address(params[:instance_id], ip_address) + redirect '/addresses' +end + +get '/:project/address/*/disassociate' do + ip_address = request.path_info.split('/')[2] + @ec2.disassociate_address(ip_address) + redirect '/addresses' +end \ No newline at end of file diff --git a/lib/actions/keys.rb b/lib/actions/keys.rb new file mode 100644 index 0000000..13ae292 --- /dev/null +++ b/lib/actions/keys.rb @@ -0,0 +1,16 @@ +# SSH Key Pairs + +get '/:project/keys' do + @keys = @ec2.describe_key_pairs + erb :keys +end + +get '/:project/key/:key_name/delete' do + @ec2.delete_key_pair(params[:key_name]) + redirect '/keys' +end + +post '/:project/key' do + output = @ec2.create_key_pair(params[:key_name]) + "
" + output[:aws_material] + "
" +end \ No newline at end of file diff --git a/lib/actions/s3.rb b/lib/actions/s3.rb new file mode 100644 index 0000000..d1774b8 --- /dev/null +++ b/lib/actions/s3.rb @@ -0,0 +1,19 @@ +# S3 + +get '/:project/buckets' do + @buckets = @s3.buckets.map{|b| b.name} + erb :buckets +end + +get '/:project/bucket/:bucket_name/keys' do + @bucket = @s3.bucket(params[:bucket_name]) + @keys = @bucket.keys + erb :s3_keys +end + +get '/:project/bucket/*/key/*' do + bucket_name = request.path_info.split('/')[2] + key_name = request.path_info.split('/')[4] + @bucket = @s3.bucket(bucket_name) + send_data(@bucket.get(key_name)) +end \ No newline at end of file diff --git a/snail.rb b/snail.rb index 26923a3..b7619c1 100755 --- a/snail.rb +++ b/snail.rb @@ -1,199 +1,40 @@ #!/usr/bin/env ruby require 'rubygems' +# make sure we're using the right version of gems +gem 'sinatra', :version => '0.9.4' +gem 'right_aws', :version =>'1.10.0' require 'sinatra' require 'right_aws' require 'yaml' +require 'ruby-debug' +# load all files in lib Dir["lib/*.rb"].each { |x| load x } +# load actions +Dir["lib/actions/*.rb"].each { |x| load x } + +# set s3_config +config_file = YAML.load_file("config/snail.yml") +set :config, config_file +set :projects, config_file.keys configure do - set_option :sessions, true - @@session_keys = {} - @@config = YAML.load_file("snail.yml") rescue nil || false + set :sessions, true end before do - if @@config and !session[:key] - @@session_keys[@@config['aws_key']] ||= { - :ec2 => RightAws::Ec2.new(@@config['aws_key'], @@config['aws_secret']), - :s3 => RightAws::S3.new(@@config['aws_key'], @@config['aws_secret']) - } - session[:key] = @@config['aws_key'] - end - unless session[:key] - redirect '/setup' unless request.path_info =~ /\/setup/ or request.path_info =~ /.css/ - end - if session[:key] and @@session_keys[session[:key]] - @ec2 = @@session_keys[session[:key]][:ec2] - @s3 = @@session_keys[session[:key]][:s3] + @projects = options.projects + first = request.path.split('/')[1] + if config = options.config[first] + @project = first + @ec2 = RightAws::Ec2.new(config['aws_key'], config['aws_secret']) + @s3 = RightAws::S3.new(config['aws_key'], config['aws_secret']) + else + redirect '/projects' if first != 'projects' and !File.exists?("public#{request.path}") end end helpers do include Helpers -end - -get '/setup' do - erb :setup -end - -post '/setup' do - @@session_keys[params[:key]] = { - :ec2 => RightAws::Ec2.new(params[:key], params[:secret]), - :s3 => RightAws::S3.new(params[:key], params[:secret]) - } - session[:key] = params[:key] - redirect '/instances' -end - -get '/' do - redirect '/instances' -end - -# Instances - -get '/instances' do - @instances = @ec2.describe_instances.reverse - erb :instances -end - -get '/instance/:instance_id/terminate' do - @output = @ec2.terminate_instances(params[:instance_id]) - redirect '/instances' -end - -get '/instance/:instance_id/output' do - @output = @ec2.get_console_output(params[:instance_id]) - erb :output -end - -get '/instance/:instance_id/reboot' do - @ec2.reboot_instances([params[:instance_id]]) - redirect '/instances' -end - -# Images - -get '/images' do - @@images ||= @ec2.describe_images.find_all{|x| x[:aws_image_type] == 'machine'} - @i386 = @@images.find_all{|x| x[:aws_architecture] == 'i386'}.sort {|x,y| x[:aws_location] <=> y[:aws_location] } - @x86_64 = @@images.find_all{|x| x[:aws_architecture] == 'x86_64'}.sort {|x,y| x[:aws_location] <=> y[:aws_location] } - erb :images -end - -get '/images/:image_id/launch' do - @ec2.launch_instances(params[:image_id], :group_ids => 'default', - :user_data => "Woohoo!!!", - :addressing_type => "public", - :key_name => "default", - :availability_zone => "us-east-1c") - redirect '/instances' -end - -get '/images/search*' do - params[:query] ||= request.path_info.split('/')[3] - redirect '/images' if params[:query].empty? - @i386 = @@images.find_all{|x| x[:aws_architecture] == 'i386' and x.inspect =~ /#{params[:query]}/i}.sort {|x,y| x[:aws_location] <=> y[:aws_location] } - @x86_64 = @@images.find_all{|x| x[:aws_architecture] == 'x86_64' and x.inspect =~ /#{params[:query]}/i}.sort {|x,y| x[:aws_location] <=> y[:aws_location] } - erb :images -end - -# Elastic IP addresses - -get '/addresses' do - @addresses = @ec2.describe_addresses - @instances = @ec2.describe_instances.reverse - erb :addresses -end - -get '/addresses/allocate' do - @ec2.allocate_address - redirect '/addresses' -end - -get '/address/*/release' do - ip_address = request.path_info.split('/')[2] - @ec2.release_address(ip_address) - redirect '/addresses' -end - -post '/address/*/associate' do - ip_address = request.path_info.split('/')[2] - @ec2.associate_address(params[:instance_id], ip_address) - redirect '/addresses' -end - -get '/address/*/disassociate' do - ip_address = request.path_info.split('/')[2] - @ec2.disassociate_address(ip_address) - redirect '/addresses' -end - -# Security Groups - -get '/groups' do - @groups = @ec2.describe_security_groups - erb :groups -end - -get '/group/:group_name/delete' do - @ec2.delete_security_group(params[:group_name]) - redirect '/groups' -end - -get '/group/:group_name/revoke' do - if params[:group] - @ec2.revoke_security_group_named_ingress(params[:group_name], params[:owner], params[:group]) - else - @ec2.revoke_security_group_IP_ingress(params[:group_name], params[:from], params[:to], params[:protocol], params[:ip]) - end - redirect '/groups' -end - -post '/group/:group_name/authorize' do - @ec2.authorize_security_group_IP_ingress(params[:group_name], params[:from], params[:to], params[:protocol], params[:ip]) - redirect '/groups' -end - -post '/group' do - @ec2.create_security_group(params[:name], params[:description]) - redirect '/groups' -end - -# SSH Key Pairs - -get '/keys' do - @keys = @ec2.describe_key_pairs - erb :keys -end - -get '/key/:key_name/delete' do - @ec2.delete_key_pair(params[:key_name]) - redirect '/keys' -end - -post '/key' do - output = @ec2.create_key_pair(params[:key_name]) - "
" + output[:aws_material] + "
" -end - -# S3 - -get '/buckets' do - @buckets = @s3.buckets.map{|b| b.name} - erb :buckets -end - -get '/bucket/:bucket_name/keys' do - @bucket = @s3.bucket(params[:bucket_name]) - @keys = @bucket.keys - erb :s3_keys -end - -get '/bucket/*/key/*' do - bucket_name = request.path_info.split('/')[2] - key_name = request.path_info.split('/')[4] - @bucket = @s3.bucket(bucket_name) - send_data(@bucket.get(key_name)) -end +end \ No newline at end of file diff --git a/views/_layout_navigation.erb b/views/_layout_navigation.erb index d3f0bf8..a6d8a6f 100644 --- a/views/_layout_navigation.erb +++ b/views/_layout_navigation.erb @@ -1,23 +1,25 @@ +

Projects

+ + +<% if @project %>

EC2

S3

-

Links

- - \ No newline at end of file +<% end %> \ No newline at end of file diff --git a/views/instances.erb b/views/instances.erb index 50ab3b4..16b5b61 100644 --- a/views/instances.erb +++ b/views/instances.erb @@ -15,17 +15,17 @@ launched <%= time_ago_or_time_stamp(Time.parse(instance[:aws_launch_time])) %> - <%= link_to(image_tag('info.png', :alt => 'Console Output'), "/instance/#{instance[:aws_instance_id]}/output") %> + <%= link_to(image_tag('info.png', :alt => 'Console Output'), "/#{@project}/instance/#{instance[:aws_instance_id]}/output") %> <% if instance[:aws_state] == 'running' %> - <%= link_to image_tag('reboot.png', :alt => 'Reboot Instance'), "/instance/#{instance[:aws_instance_id]}/reboot", :onclick => "return confirm('Reboot: Are you sure?')" %> - <%= link_to image_tag('minus.png', :alt => 'Terminate Instance'), "/instance/#{instance[:aws_instance_id]}/terminate", :onclick => "return confirm('Terminate: Are you sure?')" %> + <%= link_to image_tag('reboot.png', :alt => 'Reboot Instance'), "/#{@project}/instance/#{instance[:aws_instance_id]}/reboot", :onclick => "return confirm('Reboot: Are you sure?')" %> + <%= link_to image_tag('minus.png', :alt => 'Terminate Instance'), "/#{@project}/instance/#{instance[:aws_instance_id]}/terminate", :onclick => "return confirm('Terminate: Are you sure?')" %> <% end %>
Type: <%= instance[:aws_instance_type] %>, Groups: <% instance[:aws_groups].each do |group| %><%= link_to group, "/groups##{group}" %><% end %>, - Key: <%= link_to instance[:ssh_key_name], "/keys##{instance[:ssh_key_name]}" %>, Zone: <%= instance[:aws_availability_zone] %> + Key: <%= link_to instance[:ssh_key_name], "/#{@project}/keys##{instance[:ssh_key_name]}" %>, Zone: <%= instance[:aws_availability_zone] %>
diff --git a/views/output.erb b/views/output.erb index cc5e278..4b07f20 100644 --- a/views/output.erb +++ b/views/output.erb @@ -1,4 +1,4 @@ -

<%= link_to '< Back', '/instances' %>

+

<%= link_to '< Back', "/#{@project}/instances" %>

<%= @output[:aws_timestamp] %> diff --git a/views/projects.erb b/views/projects.erb new file mode 100644 index 0000000..e2c4970 --- /dev/null +++ b/views/projects.erb @@ -0,0 +1 @@ +

Please select a project from the list on the left

\ No newline at end of file diff --git a/views/s3_keys.erb b/views/s3_keys.erb index 7617aff..b366553 100644 --- a/views/s3_keys.erb +++ b/views/s3_keys.erb @@ -1,3 +1,5 @@ + <% @keys.each do |key| %> - <%= key.name %> <%= link_to('link', key.public_link) %> <%= link_to 'download', "/bucket/#{@bucket.name}/key/#{key.name}" %>
-<% end %> \ No newline at end of file + +<% end %> +
<%= key.name %><%= link_to('link', key.public_link) %> <%= link_to 'download', "/#{@project}/bucket/#{@bucket.name}/key/#{key.name}" %>
\ No newline at end of file