nephele 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.autotest +26 -0
- data/Gemfile +18 -0
- data/LICENSE +24 -0
- data/README.md +16 -0
- data/Rakefile +126 -0
- data/VERSION +1 -0
- data/bin/nephele +90 -0
- data/lib/nephele/base.rb +43 -0
- data/lib/nephele/node.rb +23 -0
- data/lib/nephele/rackspace.rb +122 -0
- data/lib/nephele.rb +30 -0
- data/nephele.gemspec +91 -0
- data/test/helper.rb +7 -0
- data/test/tc_base.rb +22 -0
- metadata +251 -0
data/.autotest
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
begin
|
2
|
+
require 'autotest/growl'
|
3
|
+
require 'autotest/fsevent'
|
4
|
+
require 'autotest/restart'
|
5
|
+
#require 'redgreen/autotest'
|
6
|
+
rescue LoadError
|
7
|
+
end
|
8
|
+
|
9
|
+
Autotest.add_hook :initialize do |autotest|
|
10
|
+
%w{.git .svn .hg .DS_Store ._* vendor tmp log doc}.each do |exception|
|
11
|
+
autotest.add_exception(exception)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Override autotest default magic to rerun all tests every time a
|
16
|
+
# change is detected on the file system.
|
17
|
+
class Autotest
|
18
|
+
def get_to_green
|
19
|
+
begin
|
20
|
+
rerun_all_tests
|
21
|
+
wait_for_changes unless all_good
|
22
|
+
end until all_good
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
Autotest::Growl::show_modified_files = true
|
data/Gemfile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
source :rubygems
|
2
|
+
|
3
|
+
gem 'rake'
|
4
|
+
gem 'cloudservers', :tag => 'v0.4.0'
|
5
|
+
gem 'awesome_print'
|
6
|
+
gem 'optitron'
|
7
|
+
|
8
|
+
group :development do
|
9
|
+
gem 'wirble'
|
10
|
+
gem 'shoulda'
|
11
|
+
gem 'mocha'
|
12
|
+
gem 'autotest'
|
13
|
+
gem 'autotest-fsevent'
|
14
|
+
gem 'autotest-growl'
|
15
|
+
gem 'bundler'
|
16
|
+
gem 'jeweler', '~>1.5.2'
|
17
|
+
end
|
18
|
+
|
data/LICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
(The MIT License)
|
2
|
+
|
3
|
+
Copyright (c) 2009 - 2010:
|
4
|
+
|
5
|
+
* {Jeffrey O'Dell}[http://github.com/jodell/nephele]
|
6
|
+
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
8
|
+
a copy of this software and associated documentation files (the
|
9
|
+
'Software'), to deal in the Software without restriction, including
|
10
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
11
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
12
|
+
permit persons to whom the Software is furnished to do so, subject to
|
13
|
+
the following conditions:
|
14
|
+
|
15
|
+
The above copyright notice and this permission notice shall be
|
16
|
+
included in all copies or substantial portions of the Software.
|
17
|
+
|
18
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
19
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
20
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
21
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
22
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
23
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
24
|
+
S
|
data/README.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Nephele
|
2
|
+
========
|
3
|
+
|
4
|
+
Nephele is a thin abstraction layer around major cloud service API's.
|
5
|
+
|
6
|
+
Its main goals are simplicity and the unification of common tasks for the sake of working with a set of services.
|
7
|
+
|
8
|
+
Planned support:
|
9
|
+
|
10
|
+
* Rackspace
|
11
|
+
* EC2
|
12
|
+
|
13
|
+
Other Interesting Projects
|
14
|
+
--------------------------
|
15
|
+
* Fog - https://github.com/geemus/fog
|
16
|
+
* EC2 DSL - https://github.com/auser/poolparty
|
data/Rakefile
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'bundler'
|
5
|
+
Bundler.setup(:default, :development)
|
6
|
+
rescue Bundler::BundlerError => e
|
7
|
+
$stderr.puts e.message
|
8
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
9
|
+
exit e.status_code
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'rake'
|
13
|
+
require 'rake/testtask'
|
14
|
+
require 'json'
|
15
|
+
require 'jeweler'
|
16
|
+
require 'ap'
|
17
|
+
require 'irb'
|
18
|
+
$: << File.expand_path(File.dirname(__FILE__) + '/lib')
|
19
|
+
require 'nephele'
|
20
|
+
|
21
|
+
Jeweler::Tasks.new do |gem|
|
22
|
+
gem.name = "nephele"
|
23
|
+
gem.summary = %-Light administration utility for popular cloud services-
|
24
|
+
gem.description = %-Light administration utility for popular cloud services-
|
25
|
+
gem.email = 'jeffrey.odell@gmail.com'
|
26
|
+
gem.authors = ["Jeffrey O'Dell"]
|
27
|
+
gem.executables = ['nephele']
|
28
|
+
gem.homepage = 'https://github.com/jodell/nephele'
|
29
|
+
end
|
30
|
+
|
31
|
+
task :default => :'test:unit'
|
32
|
+
|
33
|
+
task :tags do
|
34
|
+
sh 'ctags -R *'
|
35
|
+
end
|
36
|
+
|
37
|
+
Rake::TestTask.new('test:unit') do |t|
|
38
|
+
t.libs << 'test'
|
39
|
+
t.pattern = 'test/tc_*'
|
40
|
+
t.verbose = true
|
41
|
+
end
|
42
|
+
|
43
|
+
def default
|
44
|
+
@@default ||= Nephele.new :service => :default
|
45
|
+
end
|
46
|
+
|
47
|
+
desc 'List available servers'
|
48
|
+
task :servers do
|
49
|
+
ap default.servers.map { |i| i[:name] }
|
50
|
+
end
|
51
|
+
|
52
|
+
task :list => :servers
|
53
|
+
|
54
|
+
desc 'List available images'
|
55
|
+
task :images do
|
56
|
+
ap default.images.map { |i| i[:name] }
|
57
|
+
end
|
58
|
+
|
59
|
+
desc 'List available flavors'
|
60
|
+
task :flavors do
|
61
|
+
ap default.flavors.map { |i| i[:name] }
|
62
|
+
end
|
63
|
+
|
64
|
+
desc 'Show node statuses'
|
65
|
+
task :status do
|
66
|
+
puts default.status
|
67
|
+
end
|
68
|
+
|
69
|
+
desc 'Key a host'
|
70
|
+
task :key, [:host] do |t, args|
|
71
|
+
host = args[:host] =~ /(.*)@(.*)/ ? args[:host] : "root@#{args[:host]}"
|
72
|
+
user = ENV['user'] || 'root'
|
73
|
+
home = user == 'root' ? '/root' : "~#{user}"
|
74
|
+
cmd = <<-EoC
|
75
|
+
ssh #{host} 'mkdir -p #{home}/.ssh && \
|
76
|
+
echo "#{my_default_key}" >> #{home}/.ssh/authorized_keys && \
|
77
|
+
chown -R #{user}:#{user} #{home}/.ssh'
|
78
|
+
EoC
|
79
|
+
sh cmd
|
80
|
+
end
|
81
|
+
|
82
|
+
desc 'Reset the node password (performs a reoot)'
|
83
|
+
task :password, [:node, :pass] do |t, args|
|
84
|
+
default.server_objs.find { |s| s.name == args[:node] }.update(:adminPass => args[:pass])
|
85
|
+
end
|
86
|
+
|
87
|
+
desc 'Save an image of the node'
|
88
|
+
task :save, [:node, :name] do |t, args|
|
89
|
+
default.server_objs.find { |s| s.name == args[:node] }.create_image args[:name]
|
90
|
+
end
|
91
|
+
|
92
|
+
desc "Creates a node with name, image name, flavor, optional count: `rake create[mybox,oberon,'512 server'] count=4`"
|
93
|
+
task :create, [:name, :image, :flavor] do |t, args|
|
94
|
+
(ENV['count'] || 1).to_i.times do |i|
|
95
|
+
@node = default.create \
|
96
|
+
:name => args[:name] + "#{ENV['count'] ? i + 1 : ''}",
|
97
|
+
:image => Nephele::Rackspace.image_lookup(args[:image]),
|
98
|
+
:flavor => args[:flavor],
|
99
|
+
:personality => Nephele::Rackspace::Util.personality(ENV['personality'] || :default)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
JODELL_CHEF_BOOTSTRAPPER = 'https://github.com/jodell/cookbooks/raw/master/bin/bootstrap.sh'
|
104
|
+
|
105
|
+
desc 'Create a VM and run a chef bootstrapper, optional recipe, bootstrap, cookbooks args'
|
106
|
+
task :bootstrap, [:name, :image, :flavor] => :create do |t, args|
|
107
|
+
puts "Bootstrapping: #{args[:name]}..."
|
108
|
+
bootstrapper = ENV['bootstrap'] || JODELL_CHEF_BOOTSTRAPPER
|
109
|
+
alt = ENV['cookbooks']
|
110
|
+
sh %-time ssh root@#{@node.addresses[:public]} "curl #{bootstrapper} > boot && chmod +x boot && ./boot #{alt}"-
|
111
|
+
sh %{time ssh root@#{@node.addresses[:public]} "cd -P /var/chef/cookbooks && rake run[#{ENV['recipe']}]"} if ENV['recipe']
|
112
|
+
end
|
113
|
+
|
114
|
+
desc 'Destroy, bootstrap'
|
115
|
+
task :restrap, [:name, :image, :flavor] => [:destroy, :bootstrap]
|
116
|
+
|
117
|
+
desc 'Destroy a node with name `rake destroy[foo]`'
|
118
|
+
task :destroy, [:name] do |t, args|
|
119
|
+
puts "Destroying: #{args[:name]}"
|
120
|
+
default.server_objs.find { |s| s.name == args[:name] }.delete!
|
121
|
+
end
|
122
|
+
|
123
|
+
desc 'Start IRB with the relevant env'
|
124
|
+
task :console do
|
125
|
+
ARGV.clear and IRB.start
|
126
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/bin/nephele
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'optitron'
|
5
|
+
begin
|
6
|
+
require 'nephele'
|
7
|
+
rescue LoadError
|
8
|
+
$: << File.expand_path(File.dirname(__FILE__) + '/../lib')
|
9
|
+
require 'nephele'
|
10
|
+
end
|
11
|
+
#require 'ap'
|
12
|
+
|
13
|
+
class Nephele::Runner < Optitron::CLI
|
14
|
+
JODELL_CHEF_BOOTSTRAPPER = 'https://github.com/jodell/cookbooks/raw/master/bin/bootstrap.sh'
|
15
|
+
class_opt 'cookbooks', "optional cookbooks URI", :type => :string
|
16
|
+
class_opt 'personality', 'comma-separated tuple of contents,targetfile to be placed at startup', :type => :string
|
17
|
+
class_opt 'bootstrap', "optional bootstrapper URI, defaults to #{JODELL_CHEF_BOOTSTRAPPER}", :type => :string
|
18
|
+
class_opt 'recipe', "run this recipe after bootstrapping", :type => :string
|
19
|
+
|
20
|
+
desc 'Display a list of servers'
|
21
|
+
def list
|
22
|
+
puts service.servers.map { |i| i[:name] }
|
23
|
+
end
|
24
|
+
|
25
|
+
desc 'Display available images'
|
26
|
+
def images
|
27
|
+
puts default.images.map { |i| i[:name] }
|
28
|
+
end
|
29
|
+
|
30
|
+
desc 'List available flavors'
|
31
|
+
def flavors
|
32
|
+
puts service.flavors.map { |i| i[:name] }
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'Display server status'
|
36
|
+
def status
|
37
|
+
puts service.status
|
38
|
+
end
|
39
|
+
|
40
|
+
desc 'Change a password on given node'
|
41
|
+
def password(node_string, password_string)
|
42
|
+
service.server_objs.find { |s| s.name == node_string }.update(:adminPass => password_string)
|
43
|
+
end
|
44
|
+
|
45
|
+
desc 'Save an image of the node'
|
46
|
+
def save(node_string, savename_string)
|
47
|
+
service.server_objs.find { |s| s.name == node_string }.create_image name_string
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "Creates a node with name, image name, flavor"
|
51
|
+
opt 'count', 'create foo, foo2, foo3, ...', :type => :numeric
|
52
|
+
def create(name, image, flavor)
|
53
|
+
(params['count'] || 1).to_i.times do |i|
|
54
|
+
@node = service.create \
|
55
|
+
:name => name + "#{params['count'] ? i + 1 : ''}",
|
56
|
+
:image => Nephele::Rackspace.image_lookup(image),
|
57
|
+
:flavor => flavor,
|
58
|
+
:personality => Nephele::Rackspace::Util.personality(params['personality'] || :default)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
desc 'Create a VM and run a chef bootstrapper, optional recipe, bootstrap, cookbooks args'
|
63
|
+
def bootstrap(name, image, flavor)
|
64
|
+
puts "Bootstrapping: #{name}..."
|
65
|
+
create name, image, flavor
|
66
|
+
bootstrap = params['bootstrap'] || JODELL_CHEF_BOOTSTRAPPER
|
67
|
+
system %-time ssh root@#{@node.addresses[:public]} "curl #{bootstrap} > boot && chmod +x boot && ./boot #{params['cookbooks'] || ''}"-
|
68
|
+
system %{time ssh root@#{@node.addresses[:public]} "cd -P /var/chef/cookbooks && rake run[#{params['recipe']}]"} if params['recipe']
|
69
|
+
end
|
70
|
+
|
71
|
+
desc 'Destroy and bootstrap'
|
72
|
+
def restrap(name, image, flavor)
|
73
|
+
destroy name
|
74
|
+
bootstrap name, image, flavor
|
75
|
+
end
|
76
|
+
|
77
|
+
desc 'Destroy a given node'
|
78
|
+
def destroy(name_string)
|
79
|
+
if node = service.server_objs.find { |s| s.name == name_string }
|
80
|
+
puts "Destroying: #{name_string}"
|
81
|
+
node.delete!
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def service
|
86
|
+
@@service ||= Nephele.new(:service => :default)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
Nephele::Runner.dispatch
|
data/lib/nephele/base.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
class Nephele::Base
|
2
|
+
attr_accessor :service, :key, :user
|
3
|
+
attr_reader :conn, :nodes
|
4
|
+
|
5
|
+
def initialize(opts = {})
|
6
|
+
@nodes = []
|
7
|
+
@key = opts[:key]
|
8
|
+
@user = opts[:user]
|
9
|
+
@service = opts[:service] || :rackspace
|
10
|
+
end
|
11
|
+
|
12
|
+
# After a verified connection, the service class should call this to
|
13
|
+
# populate the list of nodes
|
14
|
+
#
|
15
|
+
def populate!
|
16
|
+
raise 'Subclass Responsibility'
|
17
|
+
end
|
18
|
+
|
19
|
+
def conn
|
20
|
+
raise 'Subclass Responsibility'
|
21
|
+
end
|
22
|
+
|
23
|
+
def create
|
24
|
+
raise 'Subclass Responsibility'
|
25
|
+
end
|
26
|
+
|
27
|
+
def list
|
28
|
+
@nodes
|
29
|
+
end
|
30
|
+
|
31
|
+
def reset
|
32
|
+
@conn = nil
|
33
|
+
conn
|
34
|
+
end
|
35
|
+
|
36
|
+
def method_missing(meth, *args)
|
37
|
+
if conn.respond_to? meth
|
38
|
+
conn.send meth, *args
|
39
|
+
else
|
40
|
+
super
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/nephele/node.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Might scrap this
|
2
|
+
class Nephele::Node
|
3
|
+
attr_reader :id, :type
|
4
|
+
|
5
|
+
def initialize(opts)
|
6
|
+
if opts.is_a? Hash
|
7
|
+
@id = opts[:id]
|
8
|
+
@type = opts[:type]
|
9
|
+
else
|
10
|
+
@id = opts.id
|
11
|
+
@type = opts.class == CloudServers::Server ? :rackspace : nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def up?
|
16
|
+
# TEMPORARY
|
17
|
+
case @type
|
18
|
+
when :rackspace
|
19
|
+
CloudServers::Server.new(@id).status == 'ACTIVE'
|
20
|
+
else
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
class Nephele::Rackspace < Nephele::Base
|
2
|
+
attr_reader :nodes
|
3
|
+
|
4
|
+
def initialize(opts = {})
|
5
|
+
super
|
6
|
+
populate!
|
7
|
+
end
|
8
|
+
|
9
|
+
def conn
|
10
|
+
@conn ||= CloudServers::Connection.new \
|
11
|
+
:username => @user,
|
12
|
+
:api_key => @key
|
13
|
+
end
|
14
|
+
|
15
|
+
def populate!
|
16
|
+
server_objs.each { |n| register!(n) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def register!(node)
|
20
|
+
@nodes << Nephele::Node.new(node)
|
21
|
+
# methods can't start with a leading digit
|
22
|
+
meth = node.name.match(/^(\d)+/) ? "_#{node.name}" : node.name
|
23
|
+
self.class.send(:define_method, meth.gsub(/\./, '_').to_sym) do
|
24
|
+
CloudServers::Server.new(conn, node.id)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def create(opts)
|
29
|
+
rack_node = conn.create_server \
|
30
|
+
:name => opts[:name],
|
31
|
+
:imageId => images_id_for_name(opts[:image]),
|
32
|
+
:flavorId => flavors_id_for_name(opts[:flavor]),
|
33
|
+
:personality => opts[:personality] || ''
|
34
|
+
puts "Server pass: #{rack_node.adminPass}, ip #{rack_node.addresses[:public]}"
|
35
|
+
register!(rack_node)
|
36
|
+
rack_node
|
37
|
+
end
|
38
|
+
|
39
|
+
def destroy(opts)
|
40
|
+
id = servers_id_for_name(opts[:name])
|
41
|
+
CloudServers::Server.new(conn, id).delete!
|
42
|
+
@nodes.delete_if { |n| n.id == id }
|
43
|
+
end
|
44
|
+
|
45
|
+
def status
|
46
|
+
header = "#{'NAME'.ljust(20)} #{'STATUS'.ljust(6)} #{'-%-'.ljust(3)} #{'Kind'.ljust(10)} Public IP\n"
|
47
|
+
info = server_objs.inject('') do |acc, s|
|
48
|
+
acc += "#{s.name.ljust(20)} #{s.status.ljust(6)} #{s.progress.to_s.ljust(3)} #{s.flavor.name.ljust(10)} #{s.addresses[:public]}\n"
|
49
|
+
end
|
50
|
+
header + info
|
51
|
+
end
|
52
|
+
|
53
|
+
def provisioning?
|
54
|
+
server_objs.any? { |s| s.status != 'ACTIVE' }
|
55
|
+
end
|
56
|
+
|
57
|
+
[:servers, :flavors, :images].each do |sym|
|
58
|
+
define_method "#{sym}_id_for_name" do |name|
|
59
|
+
_id_for_name(sym, name)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def _id_for_name(obj, name)
|
64
|
+
conn.send(obj.to_sym).find { |o| o[:name] == name }[:id]
|
65
|
+
end
|
66
|
+
|
67
|
+
def server_objs
|
68
|
+
conn.servers.inject([]) do |acc, info|
|
69
|
+
acc << CloudServers::Server.new(conn, info[:id]); acc
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def image_objs
|
74
|
+
conn.images.inject([]) do |acc, info|
|
75
|
+
acc << CloudServers::Image.new(conn, info[:id]); acc
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.image_lookup(name)
|
80
|
+
case name
|
81
|
+
when /lucid/
|
82
|
+
"Ubuntu 10.04 LTS (lucid)"
|
83
|
+
else
|
84
|
+
name
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
module Nephele::Rackspace::Util
|
90
|
+
class << self
|
91
|
+
def personality(personality)
|
92
|
+
if personality == :default
|
93
|
+
{ generate_key_file => '/root/.ssh/authorized_keys',
|
94
|
+
known_hosts_file => '/root/.ssh/known_hosts' }
|
95
|
+
else
|
96
|
+
acc = {}
|
97
|
+
personality.split(',').each_slice(2) { |(k, v)| acc[k] = v }
|
98
|
+
acc
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def generate_key_file
|
103
|
+
'/tmp/nephele_key_file'.tap do |file| File.open(file, 'w') { |f| f << my_default_key }; end
|
104
|
+
end
|
105
|
+
|
106
|
+
def my_default_key
|
107
|
+
File.read(File.expand_path('~/.ssh/id_dsa.pub'))
|
108
|
+
end
|
109
|
+
|
110
|
+
def known_hosts_file
|
111
|
+
'/tmp/known_hosts.nephele'.tap do |file| File.open(file, 'w') { |f| f << known_hosts }; end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Github
|
115
|
+
def known_hosts
|
116
|
+
<<-EoS
|
117
|
+
|1|xLwg2PqKMACZR+6X0OH9rx66p1I=|xR01sH66lqU3PejWe+8J0EWulb0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
118
|
+
|1|juutFPHnSpo61K6I1Y7XnKB07yI=|u/ZYrJrAdgQ1G/cd48si2avBHTQ= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
119
|
+
EoS
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
data/lib/nephele.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'cloudservers'
|
2
|
+
|
3
|
+
module Nephele
|
4
|
+
SERVICES = [:rackspace, :ec2].freeze
|
5
|
+
require 'nephele/base'
|
6
|
+
require 'nephele/node'
|
7
|
+
require 'nephele/rackspace'
|
8
|
+
|
9
|
+
# Factory for service objects
|
10
|
+
def self.new(opts)
|
11
|
+
case opts[:service]
|
12
|
+
when :rackspace
|
13
|
+
Nephele::Rackspace.new :key => opts[:key], :user => opts[:user]
|
14
|
+
when :ec2
|
15
|
+
raise 'Not Implemented Yet'
|
16
|
+
when :default
|
17
|
+
Nephele::Rackspace.new default
|
18
|
+
else
|
19
|
+
raise "Unsupported service, expected one of #{SERVICES * ', '}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.default
|
24
|
+
{ :service => ENV['NEPHELE_SERVICE_DEFAULT'] &&
|
25
|
+
ENV['NEPHELE_SERVICE_DEFAULT'].downcase.to_sym ||
|
26
|
+
:rackspace,
|
27
|
+
:user => ENV['RACKSPACE_USER'],
|
28
|
+
:key => ENV['RACKSPACE_KEY'] }
|
29
|
+
end
|
30
|
+
end
|
data/nephele.gemspec
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{nephele}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Jeffrey O'Dell"]
|
12
|
+
s.date = %q{2011-04-07}
|
13
|
+
s.default_executable = %q{nephele}
|
14
|
+
s.description = %q{Light administration utility for popular cloud services}
|
15
|
+
s.email = %q{jeffrey.odell@gmail.com}
|
16
|
+
s.executables = ["nephele"]
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"LICENSE",
|
19
|
+
"README.md"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".autotest",
|
23
|
+
"Gemfile",
|
24
|
+
"LICENSE",
|
25
|
+
"README.md",
|
26
|
+
"Rakefile",
|
27
|
+
"VERSION",
|
28
|
+
"bin/nephele",
|
29
|
+
"lib/nephele.rb",
|
30
|
+
"lib/nephele/base.rb",
|
31
|
+
"lib/nephele/node.rb",
|
32
|
+
"lib/nephele/rackspace.rb",
|
33
|
+
"nephele.gemspec",
|
34
|
+
"test/helper.rb",
|
35
|
+
"test/tc_base.rb"
|
36
|
+
]
|
37
|
+
s.homepage = %q{https://github.com/jodell/nephele}
|
38
|
+
s.require_paths = ["lib"]
|
39
|
+
s.rubygems_version = %q{1.6.1}
|
40
|
+
s.summary = %q{Light administration utility for popular cloud services}
|
41
|
+
s.test_files = [
|
42
|
+
"test/helper.rb",
|
43
|
+
"test/tc_base.rb"
|
44
|
+
]
|
45
|
+
|
46
|
+
if s.respond_to? :specification_version then
|
47
|
+
s.specification_version = 3
|
48
|
+
|
49
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
50
|
+
s.add_runtime_dependency(%q<rake>, [">= 0"])
|
51
|
+
s.add_runtime_dependency(%q<cloudservers>, [">= 0"])
|
52
|
+
s.add_runtime_dependency(%q<awesome_print>, [">= 0"])
|
53
|
+
s.add_runtime_dependency(%q<optitron>, [">= 0"])
|
54
|
+
s.add_development_dependency(%q<wirble>, [">= 0"])
|
55
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
56
|
+
s.add_development_dependency(%q<mocha>, [">= 0"])
|
57
|
+
s.add_development_dependency(%q<autotest>, [">= 0"])
|
58
|
+
s.add_development_dependency(%q<autotest-fsevent>, [">= 0"])
|
59
|
+
s.add_development_dependency(%q<autotest-growl>, [">= 0"])
|
60
|
+
s.add_development_dependency(%q<bundler>, [">= 0"])
|
61
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
|
62
|
+
else
|
63
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
64
|
+
s.add_dependency(%q<cloudservers>, [">= 0"])
|
65
|
+
s.add_dependency(%q<awesome_print>, [">= 0"])
|
66
|
+
s.add_dependency(%q<optitron>, [">= 0"])
|
67
|
+
s.add_dependency(%q<wirble>, [">= 0"])
|
68
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
69
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
70
|
+
s.add_dependency(%q<autotest>, [">= 0"])
|
71
|
+
s.add_dependency(%q<autotest-fsevent>, [">= 0"])
|
72
|
+
s.add_dependency(%q<autotest-growl>, [">= 0"])
|
73
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
74
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
75
|
+
end
|
76
|
+
else
|
77
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
78
|
+
s.add_dependency(%q<cloudservers>, [">= 0"])
|
79
|
+
s.add_dependency(%q<awesome_print>, [">= 0"])
|
80
|
+
s.add_dependency(%q<optitron>, [">= 0"])
|
81
|
+
s.add_dependency(%q<wirble>, [">= 0"])
|
82
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
83
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
84
|
+
s.add_dependency(%q<autotest>, [">= 0"])
|
85
|
+
s.add_dependency(%q<autotest-fsevent>, [">= 0"])
|
86
|
+
s.add_dependency(%q<autotest-growl>, [">= 0"])
|
87
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
88
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
data/test/helper.rb
ADDED
data/test/tc_base.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestNepheleBase < Test::Unit::TestCase
|
4
|
+
context 'sanity' do
|
5
|
+
should 'be sane' do
|
6
|
+
assert_not_nil Nephele
|
7
|
+
assert_not_nil Nephele::Base.new
|
8
|
+
end
|
9
|
+
|
10
|
+
should 'instantiate different services correctly' do
|
11
|
+
Nephele::Rackspace.any_instance.stubs(:populate!).returns(nil)
|
12
|
+
assert_kind_of Nephele::Rackspace,
|
13
|
+
Nephele.new(:service => :rackspace, :user => 'foo', :key => 'bar')
|
14
|
+
assert_raise RuntimeError do
|
15
|
+
Nephele.new(:service => :ec2, :user => 'foo', :key => 'bar')
|
16
|
+
end
|
17
|
+
assert_raise RuntimeError do
|
18
|
+
Nephele.new(:service => 'garbage', :user => 'foo', :key => 'bar')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,251 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nephele
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Jeffrey O'Dell
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-04-07 00:00:00 -05:00
|
19
|
+
default_executable: nephele
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rake
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: cloudservers
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: awesome_print
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :runtime
|
62
|
+
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: optitron
|
65
|
+
prerelease: false
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 3
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
type: :runtime
|
76
|
+
version_requirements: *id004
|
77
|
+
- !ruby/object:Gem::Dependency
|
78
|
+
name: wirble
|
79
|
+
prerelease: false
|
80
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
hash: 3
|
86
|
+
segments:
|
87
|
+
- 0
|
88
|
+
version: "0"
|
89
|
+
type: :development
|
90
|
+
version_requirements: *id005
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: shoulda
|
93
|
+
prerelease: false
|
94
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
hash: 3
|
100
|
+
segments:
|
101
|
+
- 0
|
102
|
+
version: "0"
|
103
|
+
type: :development
|
104
|
+
version_requirements: *id006
|
105
|
+
- !ruby/object:Gem::Dependency
|
106
|
+
name: mocha
|
107
|
+
prerelease: false
|
108
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
hash: 3
|
114
|
+
segments:
|
115
|
+
- 0
|
116
|
+
version: "0"
|
117
|
+
type: :development
|
118
|
+
version_requirements: *id007
|
119
|
+
- !ruby/object:Gem::Dependency
|
120
|
+
name: autotest
|
121
|
+
prerelease: false
|
122
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
hash: 3
|
128
|
+
segments:
|
129
|
+
- 0
|
130
|
+
version: "0"
|
131
|
+
type: :development
|
132
|
+
version_requirements: *id008
|
133
|
+
- !ruby/object:Gem::Dependency
|
134
|
+
name: autotest-fsevent
|
135
|
+
prerelease: false
|
136
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ">="
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
hash: 3
|
142
|
+
segments:
|
143
|
+
- 0
|
144
|
+
version: "0"
|
145
|
+
type: :development
|
146
|
+
version_requirements: *id009
|
147
|
+
- !ruby/object:Gem::Dependency
|
148
|
+
name: autotest-growl
|
149
|
+
prerelease: false
|
150
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
151
|
+
none: false
|
152
|
+
requirements:
|
153
|
+
- - ">="
|
154
|
+
- !ruby/object:Gem::Version
|
155
|
+
hash: 3
|
156
|
+
segments:
|
157
|
+
- 0
|
158
|
+
version: "0"
|
159
|
+
type: :development
|
160
|
+
version_requirements: *id010
|
161
|
+
- !ruby/object:Gem::Dependency
|
162
|
+
name: bundler
|
163
|
+
prerelease: false
|
164
|
+
requirement: &id011 !ruby/object:Gem::Requirement
|
165
|
+
none: false
|
166
|
+
requirements:
|
167
|
+
- - ">="
|
168
|
+
- !ruby/object:Gem::Version
|
169
|
+
hash: 3
|
170
|
+
segments:
|
171
|
+
- 0
|
172
|
+
version: "0"
|
173
|
+
type: :development
|
174
|
+
version_requirements: *id011
|
175
|
+
- !ruby/object:Gem::Dependency
|
176
|
+
name: jeweler
|
177
|
+
prerelease: false
|
178
|
+
requirement: &id012 !ruby/object:Gem::Requirement
|
179
|
+
none: false
|
180
|
+
requirements:
|
181
|
+
- - ~>
|
182
|
+
- !ruby/object:Gem::Version
|
183
|
+
hash: 7
|
184
|
+
segments:
|
185
|
+
- 1
|
186
|
+
- 5
|
187
|
+
- 2
|
188
|
+
version: 1.5.2
|
189
|
+
type: :development
|
190
|
+
version_requirements: *id012
|
191
|
+
description: Light administration utility for popular cloud services
|
192
|
+
email: jeffrey.odell@gmail.com
|
193
|
+
executables:
|
194
|
+
- nephele
|
195
|
+
extensions: []
|
196
|
+
|
197
|
+
extra_rdoc_files:
|
198
|
+
- LICENSE
|
199
|
+
- README.md
|
200
|
+
files:
|
201
|
+
- .autotest
|
202
|
+
- Gemfile
|
203
|
+
- LICENSE
|
204
|
+
- README.md
|
205
|
+
- Rakefile
|
206
|
+
- VERSION
|
207
|
+
- bin/nephele
|
208
|
+
- lib/nephele.rb
|
209
|
+
- lib/nephele/base.rb
|
210
|
+
- lib/nephele/node.rb
|
211
|
+
- lib/nephele/rackspace.rb
|
212
|
+
- nephele.gemspec
|
213
|
+
- test/helper.rb
|
214
|
+
- test/tc_base.rb
|
215
|
+
has_rdoc: true
|
216
|
+
homepage: https://github.com/jodell/nephele
|
217
|
+
licenses: []
|
218
|
+
|
219
|
+
post_install_message:
|
220
|
+
rdoc_options: []
|
221
|
+
|
222
|
+
require_paths:
|
223
|
+
- lib
|
224
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
225
|
+
none: false
|
226
|
+
requirements:
|
227
|
+
- - ">="
|
228
|
+
- !ruby/object:Gem::Version
|
229
|
+
hash: 3
|
230
|
+
segments:
|
231
|
+
- 0
|
232
|
+
version: "0"
|
233
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
234
|
+
none: false
|
235
|
+
requirements:
|
236
|
+
- - ">="
|
237
|
+
- !ruby/object:Gem::Version
|
238
|
+
hash: 3
|
239
|
+
segments:
|
240
|
+
- 0
|
241
|
+
version: "0"
|
242
|
+
requirements: []
|
243
|
+
|
244
|
+
rubyforge_project:
|
245
|
+
rubygems_version: 1.6.1
|
246
|
+
signing_key:
|
247
|
+
specification_version: 3
|
248
|
+
summary: Light administration utility for popular cloud services
|
249
|
+
test_files:
|
250
|
+
- test/helper.rb
|
251
|
+
- test/tc_base.rb
|