rumm 0.0.23 → 0.0.24

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +8 -8
  2. data/README.md +11 -3
  3. data/app.rb +13 -0
  4. data/app/controllers/authentication_controller.rb +12 -11
  5. data/app/controllers/railsifications_controller.rb +24 -21
  6. data/app/controllers/servers_controller.rb +14 -4
  7. data/app/controllers/users_controller.rb +15 -0
  8. data/app/forms/servers/update_form.rb +7 -0
  9. data/app/forms/volumes/create_form.rb +1 -2
  10. data/app/help/create_container.txt +0 -1
  11. data/app/help/create_dbinstance.txt +1 -1
  12. data/app/help/create_server.txt +1 -1
  13. data/app/help/destroy_node_on_loadbalancer.txt +1 -1
  14. data/app/help/railsify_server.txt +1 -1
  15. data/app/help/show_attachment_on_server.txt +4 -4
  16. data/app/help/show_server.txt +1 -1
  17. data/app/help/update_server.txt +19 -0
  18. data/app/providers/configuration_provider.rb +118 -0
  19. data/app/providers/credentials_provider.rb +4 -4
  20. data/app/providers/login_information_provider.rb +34 -0
  21. data/app/providers/users_provider.rb +13 -0
  22. data/app/routes.rb +1 -0
  23. data/app/views/authentication/login.txt.erb +1 -1
  24. data/app/views/help/show.txt.erb +1 -1
  25. data/app/views/servers/update.txt.erb +1 -0
  26. data/app/views/users/create.txt.erb +1 -1
  27. data/app/views/users/destroy.txt.erb +1 -0
  28. data/app/views/users/show.txt.erb +1 -0
  29. data/lib/rumm/exceptions.rb +5 -0
  30. data/lib/rumm/version.rb +1 -1
  31. data/rumm.gemspec +1 -2
  32. data/spec/features/attachments_spec.rb +1 -1
  33. data/spec/features/configuration_spec.rb +143 -0
  34. data/spec/features/containers_spec.rb +1 -1
  35. data/spec/features/databases_spec.rb +1 -1
  36. data/spec/features/dbinstances_spec.rb +1 -1
  37. data/spec/features/files_spec.rb +1 -1
  38. data/spec/features/help_spec.rb +1 -1
  39. data/spec/features/loadbalancers_spec.rb +1 -1
  40. data/spec/features/login_spec.rb +47 -33
  41. data/spec/features/nodes_spec.rb +1 -1
  42. data/spec/features/servers_spec.rb +1 -1
  43. data/spec/features/users_spec.rb +28 -0
  44. data/spec/features/volumes_spec.rb +1 -1
  45. data/spec/fixtures/cassettes/authentication/successful-login.yml +9 -5
  46. data/spec/fixtures/cassettes/authentication/unsuccessful-login.yml +5 -3
  47. data/spec/fixtures/cassettes/users/create.yml +122 -0
  48. data/spec/fixtures/cassettes/users/destroy.yml +200 -0
  49. data/spec/fixtures/cassettes/users/show-all.yml +122 -0
  50. data/spec/fixtures/cassettes/users/show.yml +165 -0
  51. data/spec/spec_helper.rb +19 -11
  52. metadata +25 -19
  53. data/app/providers/user_provider.rb +0 -23
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NGFlNzA2ZWMyM2RmMjBkZWNlZTk5MzVmMzRkNjFmMGVkNGZiNjQ4Mw==
4
+ YmQzNjJhOTY2NWQwYjdlZTg2ZGRlNWRjZDE1MTczMmRhMWE0ZWQyNg==
5
5
  data.tar.gz: !binary |-
6
- NWIwMWU3MjNhNjAxYTQ5MDVkNmNjMmMwM2MwYTBkZDkzZDk5ZDI2Zg==
6
+ OTQ1MTFmNzRmMzI0NDliYmFjMDYxZmY5YTMwNTllNTAyMDQ5NTZjYg==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- NzljYjhkYTc1ZDg3ZDNhZGI0NDMyNWNjOTIyN2I1M2JkNWU4NDY1OTI4NzI4
10
- ZjU0NzMwMzk3ZTA5MDQ4NzViNThjNTQwZTQ2ZWUzNmNjYTFiNzliNGE3N2U0
11
- MTkwM2U1ZDgwMTg0NjA2YjQ3NjczMTQ1OWNiOWVlODYzZDlkZmY=
9
+ ZDEwOTk4MGFiMzQ1N2Y1ZmJlZTExNjU5MzAwNDBkY2VlZDY0MjY2NjBhNzhl
10
+ MzEzZDgzYzdiMTBkMDFiMTVhNTNhZjYzMDZhZmY2MzIwN2M3YTllMWYzNzU4
11
+ NGI0YjRmNGQyN2ZlY2QyZGEyZmUzYWFhYmJlNjdjMDdkZWYxYmE=
12
12
  data.tar.gz: !binary |-
13
- MzgyNGNjMmIxYzRkOTZlM2EwYmQ1YWE3Y2FmMmIyNzZmOTYzOTUxM2MyZjNl
14
- MDZiMDlmOWRlYmVhZTIzN2QxN2JjOWVkOTQ3ZGZjYjc2N2JmOTQxMGFjN2E1
15
- ZTNkOWRjZmM1ZDNmMDRjODE3Y2I2ZTgyY2RlMjYyMWI4MjZhNjI=
13
+ ZjQyNWMwYzgxMjU2MmU3MDVkMTcyZWEzMWFlNjM3NGIwYjFiYTY0Mzk0Mzg2
14
+ Zjk5MzE5MjUxZDQwMzBkYjAzODkyZjkyZTZjZDU1MTcyZGE4YTJjMDdlZmM5
15
+ ODMyZmUxMGZjZWI0NTQxZGM4NDdlYTJlNmMwZmVmZGViYjM5MjE=
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  ## Rumm: a tasty tool for hackers and pirates
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/rumm.png)](http://badge.fury.io/rb/rumm)
4
- [![Build Status](https://travis-ci.org/rackerlabs/rumm.png?branch=master)](https://travis-ci.org/rackerlabs/rumm)
5
- [![Dependency Status](https://gemnasium.com/rackerlabs/rumm.png)](https://gemnasium.com/rackerlabs/rumm)
4
+ [![Build Status](https://travis-ci.org/rackspace/rumm.png?branch=master)](https://travis-ci.org/rackspace/rumm)
5
+ [![Dependency Status](https://gemnasium.com/rackspace/rumm.png)](https://gemnasium.com/rackspace/rumm)
6
6
 
7
7
 
8
8
  Rumm is a command line interface and API to rackspace. You can use it
@@ -16,7 +16,9 @@ Authenticate with rackspace using your cloud credentials as follows:
16
16
  rumm login
17
17
  username: joe
18
18
  password: ****
19
- logged in, credentials written to ~/.netrc
19
+ Default Region (Enter for ord):
20
+
21
+ logged in as joe, credentials written to ~/.rummrc
20
22
 
21
23
 
22
24
  Now we can see the list of servers we have available:
@@ -35,6 +37,12 @@ For further help, including a full listing of commands, type:
35
37
 
36
38
  rumm help
37
39
 
40
+ To access servers outside of your default region, you can prefix your rumm command with REGION=<region name>.
41
+
42
+ For example to list servers in IAD you would execute the following:
43
+
44
+ REGION=iad rumm show servers
45
+
38
46
  ## Further Reading
39
47
 
40
48
  See the [official rumm website][1] for more information, including documentation.
data/app.rb CHANGED
@@ -1,8 +1,21 @@
1
1
  require "mvcli/app"
2
2
  require "rumm/version"
3
+ require "rumm/exceptions"
3
4
 
4
5
  module Rumm
5
6
  class App < MVCLI::App
6
7
  self.root = Pathname(__FILE__).dirname
8
+
9
+ def main(argv = ARGV.dup, input = $stdin, output = $stdout, log = $stderr, env = ENV.dup)
10
+ super.tap do |code|
11
+
12
+ # HACK: print out usage information if we can't the the command
13
+ if code == MVCLI::Middleware::ExitStatus::EX_USAGE
14
+ puts "\n"
15
+ super(%w[help commands], input, output, log, env) rescue code
16
+ end
17
+ end
18
+ end
19
+
7
20
  end
8
21
  end
@@ -1,19 +1,21 @@
1
1
  require "net/https"
2
2
  require "json"
3
- require "netrc"
4
3
  require "excon"
5
4
 
6
5
  class AuthenticationController < MVCLI::Controller
7
6
 
8
7
  requires :user
8
+ requires :configuration
9
+ requires :login_information
9
10
 
10
11
  def login
11
- login_info = user
12
+ login_info = login_information
12
13
  username = login_info.name
13
14
  password = login_info.password
14
15
 
15
- connection = Excon.new('https://identity.api.rackspacecloud.com')
16
-
16
+ uri = URI.parse(configuration.auth_endpoint)
17
+ connection = Excon.new(uri.to_s)
18
+
17
19
  headers = {'Content-Type' => 'application/json'}
18
20
  body = {auth: {passwordCredentials: {username: username, password: password}}}
19
21
 
@@ -30,16 +32,15 @@ class AuthenticationController < MVCLI::Controller
30
32
 
31
33
  user_credentials = Map(JSON.parse response.body)
32
34
 
33
- netrc = Netrc.read
34
- netrc['api.rackspace.com'] = username, user_credentials["RAX-KSKEY:apiKeyCredentials"].apiKey
35
- netrc.save
36
-
35
+ configuration.username = username
36
+ configuration.api_key = user_credentials["RAX-KSKEY:apiKeyCredentials"].apiKey
37
+ configuration.region = login_info.region
38
+ configuration.save
39
+
37
40
  user_info
38
41
  end
39
42
 
40
43
  def logout
41
- n = Netrc.read
42
- n.delete 'api.rackspace.com'
43
- n.save
44
+ configuration.delete
44
45
  end
45
46
  end
@@ -1,5 +1,6 @@
1
1
  require "tmpdir"
2
2
  require "open3"
3
+ require "bundler"
3
4
 
4
5
  class RailsificationsController < MVCLI::Controller
5
6
  requires :compute
@@ -13,29 +14,31 @@ class RailsificationsController < MVCLI::Controller
13
14
  tmpdir = Pathname(Dir.tmpdir).join 'chef_kitchen'
14
15
  FileUtils.mkdir_p tmpdir
15
16
  Dir.chdir tmpdir do
16
- File.open('Gemfile', 'w') do |f|
17
- f.puts 'source "https://rubygems.org"'
18
- f.puts 'gem "knife-solo", ">= 0.3.0pre3"'
19
- f.puts 'gem "berkshelf"'
20
- end
21
- execute "bundle install --binstubs"
22
- execute "bin/knife solo init ."
23
- File.open 'Berksfile', 'w' do |f|
24
- f.puts "site :opscode"
25
- f.puts ""
26
- f.puts "cookbook 'runit', '>= 1.1.2'"
27
- f.puts "cookbook 'rackbox', github: 'hayesmp/rackbox-cookbook'"
28
- end
29
- execute "bin/berks install --path cookbooks/"
30
- execute "bin/knife solo prepare root@#{server.ipv4_address}"
31
- File.open('nodes/host.json', 'w') do |f|
32
- f.puts('{"run_list":["rackbox"],"rackbox":{"apps":{"unicorn":[{"appname":"app1","hostname":"app1"}]},"ruby":{"global_version":"2.0.0-p195","versions":["2.0.0-p195"]}}}')
33
- end
17
+ Bundler.with_clean_env do
18
+ File.open('Gemfile', 'w') do |f|
19
+ f.puts 'source "https://rubygems.org"'
20
+ f.puts 'gem "knife-solo", ">= 0.3.0pre3"'
21
+ f.puts 'gem "berkshelf"'
22
+ end
23
+ execute "bundle install --binstubs"
24
+ execute "bin/knife solo init ."
25
+ File.open 'Berksfile', 'w' do |f|
26
+ f.puts "site :opscode"
27
+ f.puts ""
28
+ f.puts "cookbook 'runit', '>= 1.1.2'"
29
+ f.puts "cookbook 'rackbox', github: 'hayesmp/rackbox-cookbook'"
30
+ end
31
+ execute "bin/berks install --path cookbooks/"
32
+ execute "bin/knife solo prepare root@#{server.ipv4_address}"
33
+ File.open('nodes/host.json', 'w') do |f|
34
+ f.puts('{"run_list":["rackbox"],"rackbox":{"apps":{"unicorn":[{"appname":"app1","hostname":"app1"}]},"ruby":{"global_version":"2.0.0-p195","versions":["2.0.0-p195"]}}}')
35
+ end
34
36
 
35
- FileUtils.rm_rf "#{server.ipv4_address}.json"
36
- FileUtils.mv "nodes/host.json", "nodes/#{server.ipv4_address}.json"
37
+ FileUtils.rm_rf "#{server.ipv4_address}.json"
38
+ FileUtils.mv "nodes/host.json", "nodes/#{server.ipv4_address}.json"
37
39
 
38
- execute "bin/knife solo cook root@#{server.ipv4_address}"
40
+ execute "bin/knife solo cook root@#{server.ipv4_address}"
41
+ end
39
42
  end
40
43
  return server
41
44
  end
@@ -31,6 +31,20 @@ class ServersController < MVCLI::Controller
31
31
  return server
32
32
  end
33
33
 
34
+ def update
35
+ template = Servers::UpdateForm
36
+ argv = MVCLI::Argv.new command.argv
37
+ form = template.new argv.options
38
+ form.validate!
39
+
40
+ unupdated_server = server
41
+ unupdated_server.name = form.name unless form.name == nil
42
+ unupdated_server.ipv4_address = form.ipv4 unless form.ipv4 == nil
43
+ unupdated_server.ipv6_address = form.ipv6 unless form.ipv6 == nil
44
+
45
+ unupdated_server.update
46
+ end
47
+
34
48
  def destroy
35
49
  server.tap do |s|
36
50
  s.destroy
@@ -43,10 +57,6 @@ class ServersController < MVCLI::Controller
43
57
  index.find {|s| s.name == params[:id]} or fail Fog::Errors::NotFound
44
58
  end
45
59
 
46
- def generate_name
47
- 'divine-reef'
48
- end
49
-
50
60
  def ssh
51
61
  test = server
52
62
  ip_address = test.ipv4_address
@@ -1,5 +1,6 @@
1
1
  class UsersController < MVCLI::Controller
2
2
  requires :instances
3
+ requires :users
3
4
  requires :command
4
5
 
5
6
  def index
@@ -14,6 +15,20 @@ class UsersController < MVCLI::Controller
14
15
  instance.users.create form.value
15
16
  end
16
17
 
18
+ def show
19
+ list = users
20
+ list.instance = instance
21
+ list.all.find { |u| u.name == params[:id] } or fail Fog::Errors::NotFound
22
+ end
23
+
24
+ def destroy
25
+ list = users
26
+ list.instance = instance
27
+ user = list.all.find { |u| u.name == params[:id] }
28
+ user.destroy or fail Fog::Errors::NotFound
29
+ end
30
+
31
+
17
32
  private
18
33
 
19
34
  def instance
@@ -0,0 +1,7 @@
1
+ class Servers::UpdateForm < MVCLI::Form
2
+ requires :naming
3
+
4
+ input :name, String, default: nil
5
+ input :ipv4, String, decode: ->(s) { URI('').hostname = s }
6
+ input :ipv6, String, decode: ->(s) { URI('').hostname = s }
7
+ end
@@ -5,6 +5,5 @@ class Volumes::CreateForm < MVCLI::Form
5
5
  input :type, String, default: "SATA"
6
6
  input :size, Integer, default: 100
7
7
 
8
- validates(:type, "must either be SATA or SSD"){ |type| type == "SATA" or "SSD" }
9
- validates(:size, "must be between 100 and 1024"){ |size| (100..1024) === size }
8
+ validates(:type, "must either be SATA or SSD") { |type| type == "SATA" or "SSD" }
10
9
  end
@@ -3,7 +3,6 @@ Usage:
3
3
 
4
4
  Options:
5
5
  -n, --name STRING # Name to give the new container
6
- none
7
6
 
8
7
  Arguments:
9
8
  none
@@ -2,7 +2,7 @@ Usage:
2
2
  rumm create dbinstance [--name STRING]
3
3
 
4
4
  Options:
5
- -n, --name STRING # Name to give the new server
5
+ -n, --name STRING # Name to give the new dbinstance
6
6
 
7
7
  Arguments:
8
8
  none
@@ -1,5 +1,5 @@
1
1
  Usage:
2
- rumm create server [--name STRING] [--image-id STRING] [--flavor-id STRING] [--ssh-private STRING] [--ssh-publinc STRING]
2
+ rumm create server [--name STRING] [--image-id STRING] [--flavor-id STRING] [--ssh-private STRING] [--ssh-public STRING]
3
3
 
4
4
  Options:
5
5
  -n, --name STRING # Name to give the new server
@@ -5,7 +5,7 @@ Options:
5
5
  none
6
6
 
7
7
  Arguments:
8
- ID: STRING # ID of the node to show
8
+ ID: STRING # ID of the node to destroy
9
9
  LOADBALANCER_ID: STRING # Name of the loadbalancer that contains the node requested
10
10
 
11
11
  Description:
@@ -1,5 +1,5 @@
1
1
  Usage:
2
- rumm railsify server id
2
+ rumm railsify server ID
3
3
 
4
4
  Options:
5
5
  none
@@ -1,14 +1,14 @@
1
1
  Usage:
2
- rumm show attachment on server SERVER_ID
2
+ rumm show attachment on server SERVER_ID --volume STRING
3
3
 
4
4
  Options:
5
- -v, --volume STRING # Name of the volume to attach
5
+ -v, --volume STRING # Name of the attached volume
6
6
 
7
7
  Arguments:
8
- SERVER_ID: STRING # The name of the server the volume is to be detached from
8
+ SERVER_ID: STRING # The name of the attached server
9
9
 
10
10
  Description:
11
- Detaches the specified volume from the named server.
11
+ Shows details about the specified attachment.
12
12
 
13
13
  Examples:
14
14
  rumm show attachment on server superordinate-struthioniformes --volume colorful-caterpillar
@@ -5,7 +5,7 @@ Options:
5
5
  none
6
6
 
7
7
  Arguments:
8
- ID: STRING # Name of the server to play
8
+ ID: STRING # Name of the server to show
9
9
 
10
10
  Description:
11
11
  Shows the attributes of the sever with the name specified by ID.
@@ -0,0 +1,19 @@
1
+ Usage:
2
+ rumm update server ID [--name STRING] [--ipv4 IPV4] [--ipv6 IPV6]
3
+
4
+
5
+ Arguments:
6
+ ID: STRING # Name of the server to update
7
+
8
+ Options:
9
+ --name: STRING # The name you want to change the server to
10
+ --ipv4: IPV4 # The ip you want to change the server to
11
+ --ipv6: IPV6 # The ip you want to change the server to
12
+
13
+ Description:
14
+ Updates the given server to the new values by updating and changing the
15
+ name, ipv4, or ipv6. It only updates the values if they're given in the
16
+ command.
17
+
18
+ Examples:
19
+ rumm update server silly-saffron --name sad-saffron
@@ -0,0 +1,118 @@
1
+ require 'singleton'
2
+ require 'json'
3
+ require 'rbconfig'
4
+ require 'fog'
5
+
6
+ class ConfigurationProvider
7
+
8
+ def value
9
+ self
10
+ end
11
+
12
+ def initialize
13
+ @config = defaults
14
+ reload
15
+ end
16
+
17
+ def [](key)
18
+ @config["environments"]["default"][key.to_s] rescue nil
19
+ end
20
+
21
+ def []=(key, value)
22
+ @config["environments"]["default"][key.to_s] = value
23
+ end
24
+
25
+ [:username, :api_key, :region].each do |sym|
26
+ class_eval <<-META
27
+ def #{sym}
28
+ self['#{sym}']
29
+ end
30
+
31
+ def #{sym}=(value)
32
+ self['#{sym}'] = value
33
+ end
34
+
35
+ META
36
+ end
37
+
38
+ def region
39
+ region_to_str(ENV['REGION'] || self['region'])
40
+ end
41
+
42
+ def lon_region?
43
+ region == "lon"
44
+ end
45
+
46
+ def auth_endpoint
47
+ # Note: You can authenticate against any endpoint regardless of the location of your cloud account, however, to locate the proper service endpoints
48
+ # you must authenticate against the correct cloud endpoint
49
+ self.lon_region? ? Fog::Rackspace::UK_AUTH_ENDPOINT : Fog::Rackspace::US_AUTH_ENDPOINT
50
+ end
51
+
52
+ def reload
53
+ return false unless File.exists? default_path
54
+
55
+ begin
56
+ File.open default_path do |f|
57
+ h = JSON.load f
58
+ @config.merge! h
59
+ true
60
+ end
61
+ rescue => e
62
+ fail "Unable to read #{default_path} - #{e.inspect}"
63
+ end
64
+ end
65
+
66
+ def save
67
+ begin
68
+ File.open default_path, 'w' do |f|
69
+ JSON.dump @config, f
70
+ true
71
+ end
72
+ rescue => e
73
+ fail "Unable to write #{default_path} - #{e.inspect}"
74
+ end
75
+ end
76
+
77
+
78
+ def delete
79
+ @config = defaults
80
+ File.delete(default_path) if File.exists? default_path
81
+ true
82
+ rescue => e
83
+ fail "Unable to delete #{default_path} - #{e.inspect}"
84
+ end
85
+
86
+ def default_path
87
+ if windows? && !cygwin?
88
+ File.join(ENV['USERPROFILE'].gsub("\\","/"), ".rummrc")
89
+ else
90
+ File.join((ENV["HOME"] || "./"), ".rummrc")
91
+ end
92
+ end
93
+
94
+ private
95
+
96
+ def region_to_str(str)
97
+ str ? str.to_s.downcase : nil
98
+ end
99
+
100
+ def defaults
101
+ { "environments" => {
102
+ "default" => {
103
+ "region" => :ord
104
+ }
105
+ }
106
+ }
107
+ end
108
+
109
+ # see http://stackoverflow.com/questions/4871309/what-is-the-correct-way-to-detect-if-ruby-is-running-on-windows
110
+ def windows?
111
+ RbConfig::CONFIG["host_os"] =~ /mswin|mingw|cygwin/
112
+ end
113
+
114
+ def cygwin?
115
+ RbConfig::CONFIG["host_os"] =~ /cygwin/
116
+ end
117
+
118
+ end