slicehost-tools 0.0.12
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +22 -0
- data/README.markdown +43 -0
- data/Rakefile +42 -0
- data/bin/slicehost-dns +3 -0
- data/bin/slicehost-slice +3 -0
- data/lib/slicehost-tools/resources/dns.rb +26 -0
- data/lib/slicehost-tools/resources/slice.rb +28 -0
- data/lib/slicehost-tools/resources.rb +12 -0
- data/lib/slicehost-tools/tools/dns.rb +205 -0
- data/lib/slicehost-tools/tools/slice.rb +131 -0
- data/lib/slicehost-tools/tools.rb +35 -0
- data/lib/slicehost-tools.rb +12 -0
- data/slicehost-tools.gemspec +34 -0
- metadata +90 -0
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2008 Cameron Cox <cameroncox@gmail.com>
|
4
|
+
"SliceHost" and "slice" are trademarks of Slicehost, LLC.
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
8
|
+
in the Software without restriction, including without limitation the rights
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
14
|
+
all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
+
THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# slicehost-tools
|
2
|
+
|
3
|
+
Manage Slicehost Slices and DNS records/zones from the command line.
|
4
|
+
|
5
|
+
## WARNING
|
6
|
+
|
7
|
+
I am not responsible if this eats your data or destroys your life. YOU HAVE BEEN WARNED.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
gem sources -a http://gems.github.com
|
12
|
+
|
13
|
+
sudo gem install thor
|
14
|
+
sudo gem install booster-slicehost-tools
|
15
|
+
|
16
|
+
## Usage
|
17
|
+
|
18
|
+
slicehost-dns
|
19
|
+
|
20
|
+
add [DOMAIN] [IP] add a domain for the given ip
|
21
|
+
google_apps [DOMAIN] [IP] configure Google Apps for the given domain (new or existing)
|
22
|
+
add_a [DOMAIN] [NAME] [IP] add a A record to an existing domain
|
23
|
+
add_assets [DOMAIN] [IP] add a 4 assets hosts (assets0..assets3) to an existing domain
|
24
|
+
add_cname [DOMAIN] [NAME] [CNAME] add a CNAME record to an existing domain
|
25
|
+
list lists all zones and their associated records
|
26
|
+
delete [DOMAIN] removes a domain
|
27
|
+
apikey [APIKEY] set your Slicehost API Key and save it to ~/.slicehost-tools
|
28
|
+
to_zonefile [DOMAIN] output a zone file for the given domain
|
29
|
+
help [TASK] describe available tasks or one specific task
|
30
|
+
|
31
|
+
slicehost-slice
|
32
|
+
|
33
|
+
add [SLICE NAME] [--force] add a new slice
|
34
|
+
delete [SLICE] delete a slice
|
35
|
+
list list slices
|
36
|
+
hard_reboot [SLICE] perform a hard reboot
|
37
|
+
soft_reboot [SLICE] perform a soft reboot
|
38
|
+
apikey [APIKEY] set your Slicehost API Key and save it to ~/.slicehost-tools
|
39
|
+
help [TASK] describe available tasks or one specific task
|
40
|
+
|
41
|
+
## Contributing
|
42
|
+
|
43
|
+
Feel free to fork and send pull requests via github.
|
data/Rakefile
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
|
5
|
+
gem_spec = Gem::Specification.new do |s|
|
6
|
+
s.name = %q{slicehost-tools}
|
7
|
+
s.version = "0.0.12"
|
8
|
+
|
9
|
+
s.specification_version = 2 if s.respond_to? :specification_version=
|
10
|
+
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
|
+
s.authors = ["Cameron Cox", "Bobby Uhlenbrock", "Corey Martella"]
|
13
|
+
s.date = %q{2008-09-10}
|
14
|
+
s.summary = %q{tools utilizing the slicehost api}
|
15
|
+
s.email = %q{cameroncox@gmail.com}
|
16
|
+
s.executables = ["slicehost-dns", "slicehost-slice"]
|
17
|
+
s.extra_rdoc_files = ["README.markdown", "LICENSE"]
|
18
|
+
s.files = Dir['**/**'].reject{ |f| f =~ /pkg/i }
|
19
|
+
s.has_rdoc = false
|
20
|
+
s.homepage = %q{http://github.com/booster/slicehost-tools/}
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
s.rubygems_version = %q{1.1.1}
|
23
|
+
s.add_dependency("thor", ">= 0.9.8")
|
24
|
+
s.add_dependency("activeresource", ">= 2.1.1")
|
25
|
+
end
|
26
|
+
|
27
|
+
Rake::GemPackageTask.new(gem_spec) do |p|
|
28
|
+
p.gem_spec = gem_spec
|
29
|
+
p.need_tar = true
|
30
|
+
p.need_zip = true
|
31
|
+
end
|
32
|
+
|
33
|
+
namespace :gem do
|
34
|
+
namespace :spec do
|
35
|
+
desc "Update slicehost-tools.gemspec"
|
36
|
+
task :generate do
|
37
|
+
File.open("slicehost-tools.gemspec", "w") do |f|
|
38
|
+
f.puts(gem_spec.to_ruby)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/bin/slicehost-dns
ADDED
data/bin/slicehost-slice
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
class Zone < Resource
|
2
|
+
|
3
|
+
def records(reload = false)
|
4
|
+
@records = nil if reload
|
5
|
+
@records ||= Record.find(:all, :params => { :zone_id => self.id })
|
6
|
+
end
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def find_by_origin(origin)
|
10
|
+
find(:first, :params => { :origin => "#{origin}." })
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Record < Resource
|
16
|
+
def to_zone_rr
|
17
|
+
options = { :name => name, :ttl => ttl, :type => type, :data => data }
|
18
|
+
options[:id] = id unless new_record?
|
19
|
+
self.class.to_zone_rr(options)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.to_zone_rr(options = {})
|
23
|
+
id = "; ID=#{options[:id]}" if options[:id]
|
24
|
+
"%-20s %-10s IN %-10s %-25s %s" % [options[:name], options[:ttl], options[:type], options[:data], id]
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class Address < String
|
2
|
+
end
|
3
|
+
|
4
|
+
class Slice < Resource
|
5
|
+
class << self
|
6
|
+
def find_by_name(name)
|
7
|
+
find(:first, :params => { :name => name })
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def flavor
|
12
|
+
Flavor.find(flavor_id)
|
13
|
+
end
|
14
|
+
|
15
|
+
def image
|
16
|
+
Image.find(image_id)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Flavor < Resource
|
21
|
+
def to_s; self.name;
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Image < Resource
|
26
|
+
def to_s; self.name;
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
|
2
|
+
if File.exists? File.join(ENV['HOME'], ".slicehost-tools")
|
3
|
+
load File.join(ENV['HOME'], ".slicehost-tools")
|
4
|
+
else
|
5
|
+
require File.expand_path(File.dirname(__FILE__) + "/tools")
|
6
|
+
Tools::Default.start(['apikey'])
|
7
|
+
exit
|
8
|
+
end
|
9
|
+
|
10
|
+
class Resource < ActiveResource::Base
|
11
|
+
self.site = "https://#{SlicehostSecretKey}@api.slicehost.com" if defined?(SlicehostSecretKey)
|
12
|
+
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../resources/dns"
|
2
|
+
|
3
|
+
module Tools
|
4
|
+
class DNS < Default
|
5
|
+
|
6
|
+
map "-L" => :list
|
7
|
+
|
8
|
+
desc "add [DOMAIN] [IP]", "add a domain for the given ip"
|
9
|
+
def add(domain = nil, ip = nil)
|
10
|
+
unless domain
|
11
|
+
puts "Please give a domain to add:"
|
12
|
+
domain = STDIN.gets.chomp
|
13
|
+
end
|
14
|
+
|
15
|
+
unless ip
|
16
|
+
puts "Please give the IP to use for this domain:"
|
17
|
+
ip = STDIN.gets.chomp
|
18
|
+
end
|
19
|
+
|
20
|
+
zone = Zone.new( :origin => "#{domain}.", :ttl => 3660, :active => "Y" )
|
21
|
+
|
22
|
+
if zone.save
|
23
|
+
Record.new( :record_type => 'NS', :zone_id => zone.id, :name => "#{domain}.", :data => "ns1.slicehost.net" ).save
|
24
|
+
Record.new( :record_type => 'NS', :zone_id => zone.id, :name => "#{domain}.", :data => "ns2.slicehost.net" ).save
|
25
|
+
Record.new( :record_type => 'NS', :zone_id => zone.id, :name => "#{domain}.", :data => "ns3.slicehost.net" ).save
|
26
|
+
Record.new( :record_type => 'A', :zone_id => zone.id, :name => "#{domain}.", :data => "#{ip}" ).save
|
27
|
+
Record.new( :record_type => 'CNAME', :zone_id => zone.id, :name => "www", :data => "#{domain}.").save
|
28
|
+
Record.new( :record_type => 'CNAME', :zone_id => zone.id, :name => "ftp", :data => "#{domain}.").save
|
29
|
+
puts "#{domain} added successfully."
|
30
|
+
else
|
31
|
+
puts "\n#{domain} could not be added."
|
32
|
+
puts zone.errors.full_messages.to_yaml
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
desc "google_apps [DOMAIN] [IP]", "cofigure Google Apps for the given domain (new or existing)"
|
37
|
+
def google_apps(domain = nil, ip = nil)
|
38
|
+
unless domain
|
39
|
+
puts "Please give a domain to configure:"
|
40
|
+
domain = STDIN.gets.chomp
|
41
|
+
end
|
42
|
+
unless zone = Zone.find(:first, :params => { :origin => "#{domain}." })
|
43
|
+
add(domain, ip)
|
44
|
+
zone = Zone.find(:first, :params => { :origin => "#{domain}." })
|
45
|
+
end
|
46
|
+
|
47
|
+
Record.new( :record_type => 'CNAME', :zone_id => zone.id, :name => "mail", :data => "ghs.google.com." ).save
|
48
|
+
Record.new( :record_type => 'MX', :zone_id => zone.id, :name => "#{domain}.", :data => "ASPMX.L.GOOGLE.COM.", :aux => "1" ).save
|
49
|
+
Record.new( :record_type => 'MX', :zone_id => zone.id, :name => "#{domain}.", :data => "ALT1.ASPMX.L.GOOGLE.COM.", :aux => "5" ).save
|
50
|
+
Record.new( :record_type => 'MX', :zone_id => zone.id, :name => "#{domain}.", :data => "ALT2.ASPMX.L.GOOGLE.COM.", :aux => "5" ).save
|
51
|
+
Record.new( :record_type => 'MX', :zone_id => zone.id, :name => "#{domain}.", :data => "ASPMX2.GOOGLEMAIL.COM.", :aux => "10" ).save
|
52
|
+
Record.new( :record_type => 'MX', :zone_id => zone.id, :name => "#{domain}.", :data => "ASPMX3.GOOGLEMAIL.COM.", :aux => "10" ).save
|
53
|
+
puts "#{domain} configured for Google Apps."
|
54
|
+
end
|
55
|
+
|
56
|
+
desc "list [DOMAIN]", "lists all zones and their associated records"
|
57
|
+
def list(domain = nil)
|
58
|
+
list_params = { :origin => "#{domain}." } unless domain.nil?
|
59
|
+
list_params ||= {}
|
60
|
+
Zone.find(:all, :params => list_params).each do |zone|
|
61
|
+
puts "+ #{zone.origin}"
|
62
|
+
zone.records.each do |record|
|
63
|
+
puts [' -', "[#{record.record_type}]".ljust(7, ' '), "#{record.name}"].join(' ')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
desc "to_zonefile [DOMAIN]", "output a zone file for the given domain"
|
69
|
+
def to_zonefile(domain = nil)
|
70
|
+
abort "You must give a domain" if domain.nil?
|
71
|
+
zone = Zone.find_by_origin(domain)
|
72
|
+
|
73
|
+
puts "\$ORIGIN #{zone.origin.sub(/\.$/, '')}"
|
74
|
+
puts "\$TTL #{zone.ttl}"
|
75
|
+
puts "@ IN SOA ns.slicehost.net. hostmaster.#{zone.origin} ("
|
76
|
+
puts " %-14s ; serial number" % Time.now.strftime('%Y%m%d%H%M%S')
|
77
|
+
puts " %-14s ; time to refresh" % '1d'
|
78
|
+
puts " %-14s ; time to retry" % '1d'
|
79
|
+
puts " %-14s ; time to expire" % '4w'
|
80
|
+
puts " %-14s ; minimum ttl" % '1h'
|
81
|
+
puts ")"
|
82
|
+
puts ""
|
83
|
+
[1,2,3].each do |i|
|
84
|
+
puts Record.to_zone_rr(:name => '@',
|
85
|
+
:type => 'NS',
|
86
|
+
:data => "ns#{i}.slicehost.net")
|
87
|
+
end
|
88
|
+
|
89
|
+
records_by_type = {}
|
90
|
+
zone.records.each do |r|
|
91
|
+
records_by_type[r.record_type] ||= []
|
92
|
+
records_by_type[r.record_type] << r
|
93
|
+
end
|
94
|
+
|
95
|
+
['NS', 'MX', 'TXT', 'SRV', 'A', 'PTR', 'AAAA', 'CNAME'].each do |type|
|
96
|
+
next if records_by_type[type].nil?
|
97
|
+
puts ""
|
98
|
+
records_by_type[type].sort {|a,b| a.name == zone.origin ? -1 : a.name <=> b.name}.each do |record|
|
99
|
+
name = record.name == zone.origin ? '@' : record.name
|
100
|
+
ttl = '' if record.ttl == zone.ttl
|
101
|
+
aux = ''
|
102
|
+
data = record.data
|
103
|
+
case record.record_type
|
104
|
+
when 'MX'
|
105
|
+
data = "#{record.aux} #{data}"
|
106
|
+
when 'SRV'
|
107
|
+
data = "#{record.aux} #{data}"
|
108
|
+
when 'TXT'
|
109
|
+
data = "\"#{record.data}\""
|
110
|
+
end
|
111
|
+
puts Record.to_zone_rr(:id => record.id,
|
112
|
+
:name => name,
|
113
|
+
:ttl => ttl,
|
114
|
+
:type => record.record_type,
|
115
|
+
:data => data)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
desc "delete [DOMAIN]", "removes a domain"
|
121
|
+
def delete(domain = nil)
|
122
|
+
abort "You must give a domain" if domain.nil?
|
123
|
+
|
124
|
+
puts "Type the phrase \"I am sure\" to remove this zone"
|
125
|
+
@sure = false
|
126
|
+
case STDIN.gets.chomp
|
127
|
+
when "I am sure"
|
128
|
+
@sure = true
|
129
|
+
end
|
130
|
+
|
131
|
+
if @sure && domain
|
132
|
+
Zone.find_by_origin(domain).destroy
|
133
|
+
puts "#{domain} is no more."
|
134
|
+
else
|
135
|
+
puts "aborting"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
desc "add_a [DOMAIN] [NAME] [IP]", "Add an A record to an existing domain"
|
140
|
+
def add_a(domain=nil,name=nil,ip=nil)
|
141
|
+
unless domain
|
142
|
+
puts "Please give a domain to configure:"
|
143
|
+
domain = STDIN.gets.chomp
|
144
|
+
end
|
145
|
+
#lookup the zone
|
146
|
+
unless zone = Zone.find(:first, :params => { :origin => "#{domain}." })
|
147
|
+
error "Zone #{domain} does not exist, use slicetool-dns add #{domain} IP first!"
|
148
|
+
end
|
149
|
+
unless name
|
150
|
+
puts "Please give a name to configure:"
|
151
|
+
name = STDIN.gets.chomp
|
152
|
+
end
|
153
|
+
unless ip
|
154
|
+
puts "Please give a IP to map:"
|
155
|
+
ip = STDIN.gets.chomp
|
156
|
+
end
|
157
|
+
Record.new( :record_type => 'A', :zone_id => zone.id, :name => name, :data => "#{ip}" ).save
|
158
|
+
puts "Added #{name} ==> #{ip} to #{domain}"
|
159
|
+
end
|
160
|
+
desc "add_cname [DOMAIN] [NAME] [CNAME]", "Add a CNAME record to an existing domain"
|
161
|
+
def add_cname(domain,name,cname)
|
162
|
+
unless domain
|
163
|
+
puts "Please give a domain to configure:"
|
164
|
+
domain = STDIN.gets.chomp
|
165
|
+
end
|
166
|
+
#lookup the zone
|
167
|
+
unless zone = Zone.find(:first, :params => { :origin => "#{domain}." })
|
168
|
+
error "Zone #{domain} does not exist, use slicetool-dns add #{domain} IP first!"
|
169
|
+
end
|
170
|
+
unless name
|
171
|
+
puts "Please give a name to configure:"
|
172
|
+
name = STDIN.gets.chomp
|
173
|
+
end
|
174
|
+
unless cname
|
175
|
+
puts "Please give a CNAME to map:"
|
176
|
+
cname = STDIN.gets.chomp
|
177
|
+
end
|
178
|
+
Record.new( :record_type => 'CNAME', :zone_id => zone.id, :name => name, :data => cname ).save
|
179
|
+
puts "Added #{name} ==> #{cname} to #{domain}"
|
180
|
+
end
|
181
|
+
desc "add_assets [DOMAIN] [IP]", "Add a assets0..3 to an existing domain"
|
182
|
+
|
183
|
+
def add_assets(domain,ip)
|
184
|
+
unless domain
|
185
|
+
puts "Please give a domain to configure:"
|
186
|
+
domain = STDIN.gets.chomp
|
187
|
+
end
|
188
|
+
#lookup the zone
|
189
|
+
unless zone = Zone.find(:first, :params => { :origin => "#{domain}." })
|
190
|
+
error "Zone #{domain} does not exist, use slicetool-dns add #{domain} IP first!"
|
191
|
+
end
|
192
|
+
unless ip
|
193
|
+
puts "Please give a IP to map:"
|
194
|
+
cname = STDIN.gets.chomp
|
195
|
+
end
|
196
|
+
0.upto(3) do |i|
|
197
|
+
Record.new( :record_type => 'A', :zone_id => zone.id, :name => "assets#{i}" , :data => ip).save
|
198
|
+
end
|
199
|
+
puts "Added 4 assets hosts at ip to #{domain}"
|
200
|
+
end
|
201
|
+
# init Thor
|
202
|
+
start
|
203
|
+
|
204
|
+
end
|
205
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../resources/slice"
|
2
|
+
|
3
|
+
module Tools
|
4
|
+
class Slice < Default
|
5
|
+
|
6
|
+
map "-L" => :list
|
7
|
+
|
8
|
+
desc "add [SLICE NAME]", "add a new slice"
|
9
|
+
method_options :force => :boolean
|
10
|
+
def add(slice_name)
|
11
|
+
images = ::Image.find(:all)
|
12
|
+
flavors = ::Flavor.find(:all)
|
13
|
+
|
14
|
+
puts "Available Images: "
|
15
|
+
image_id = select_image_from(images)
|
16
|
+
|
17
|
+
puts "Available Flavors: "
|
18
|
+
flavor_id = select_flavor_from(flavors)
|
19
|
+
|
20
|
+
@add = false
|
21
|
+
# confirm you want to do this, it does cost money
|
22
|
+
unless options[:force]
|
23
|
+
print "Are you sure you want do this? [y/N]: "
|
24
|
+
case STDIN.gets.chomp
|
25
|
+
when /y/i
|
26
|
+
@add = true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
if @add
|
31
|
+
slice = ::Slice.new(:name => slice_name, :flavor_id => flavor_id, :image_id => image_id)
|
32
|
+
slice.save
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "delete [SLICE]", "delete a slice"
|
38
|
+
def delete(slice_name = nil)
|
39
|
+
slice_name = select_slice.name if slice_name.nil?
|
40
|
+
|
41
|
+
@abort = true
|
42
|
+
slice = ::Slice.find_by_name(slice_name)
|
43
|
+
puts "Please type 'I understand this is not undoable' to proceed: "
|
44
|
+
case STDIN.gets.chomp
|
45
|
+
when "I understand this is not undoable"
|
46
|
+
@abort = false
|
47
|
+
end
|
48
|
+
|
49
|
+
unless @abort
|
50
|
+
puts "You have 5 seconds to change your mind (CTRL+C)"
|
51
|
+
sleep 5
|
52
|
+
puts "Say goodnight gracie."
|
53
|
+
slice.destroy
|
54
|
+
sleep 3
|
55
|
+
puts "Goodnight gracie."
|
56
|
+
else
|
57
|
+
puts "Your slice has not been nuked. (I hope)"
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
desc "list", "list slices"
|
63
|
+
def list
|
64
|
+
::Slice.find(:all).each do |slice|
|
65
|
+
puts "+ #{slice.name} (#{slice.addresses})"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
desc "status [SLICENAME]", "get information about a slice"
|
70
|
+
def status(slice_name = nil)
|
71
|
+
slice_name = select_slice.name if slice_name.nil?
|
72
|
+
|
73
|
+
slice = ::Slice.find_by_name(slice_name)
|
74
|
+
puts "Name: #{slice.name} (#{slice.addresses})"
|
75
|
+
puts "Flavor: #{slice.flavor} (#{slice.image})"
|
76
|
+
puts "Status: #{slice.status}"
|
77
|
+
puts "Bandwidth (in/out): #{slice.bw_in}/#{slice.bw_out}"
|
78
|
+
end
|
79
|
+
|
80
|
+
desc "hard_reboot [SLICE]", "perform a hard reboot"
|
81
|
+
def hard_reboot(slice_name = nil)
|
82
|
+
slice_name = select_slice.name if slice_name.nil?
|
83
|
+
|
84
|
+
puts "(hard) rebooting #{slice_name}"
|
85
|
+
reboot(:hard_reboot, slice_name)
|
86
|
+
end
|
87
|
+
|
88
|
+
desc "soft_reboot [SLICE]", "perform a soft reboot"
|
89
|
+
def soft_reboot(slice_name = nil)
|
90
|
+
slice_name = select_slice.name if slice_name.nil?
|
91
|
+
|
92
|
+
puts "(soft) rebooting #{slice_name}"
|
93
|
+
reboot(:reboot, slice_name)
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
protected
|
98
|
+
|
99
|
+
def select_slice
|
100
|
+
slices = ::Slice.find(:all)
|
101
|
+
slices.each_index { |i| puts "[#{i}] #{slices[i].name}" }
|
102
|
+
print "Select a Slice by #: "
|
103
|
+
input = STDIN.gets.chomp.to_i
|
104
|
+
slices[input]
|
105
|
+
end
|
106
|
+
|
107
|
+
def select_image_from(images)
|
108
|
+
images.each_index { |i| puts "[#{i}] #{images[i].name}" }
|
109
|
+
print "Select an Image by #: "
|
110
|
+
input = STDIN.gets.chomp.to_i
|
111
|
+
images[input].id
|
112
|
+
end
|
113
|
+
|
114
|
+
def select_flavor_from(flavors)
|
115
|
+
flavors.each_index { |i| puts "[#{i}] #{flavors[i].name} (#{flavors[i].ram}mb) ($#{flavors[i].price}/month)" }
|
116
|
+
print "Select an Image by #: "
|
117
|
+
input = STDIN.gets.chomp.to_i
|
118
|
+
flavors[input].id
|
119
|
+
end
|
120
|
+
|
121
|
+
def reboot(type, slice_name)
|
122
|
+
slice = ::Slice.find_by_name(slice_name)
|
123
|
+
slice.put(type)
|
124
|
+
end
|
125
|
+
|
126
|
+
public
|
127
|
+
|
128
|
+
# init thor
|
129
|
+
start
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Tools
|
2
|
+
|
3
|
+
class Default < Thor
|
4
|
+
|
5
|
+
desc "apikey [APIKEY]",
|
6
|
+
"set your Slicehost API Key and save it to ~/.slicehost-tools"
|
7
|
+
def apikey(apikey = nil)
|
8
|
+
@write_file = false
|
9
|
+
unless File.exists? File.join(ENV['HOME'], '.slicehost-tools')
|
10
|
+
@write_file = true
|
11
|
+
else
|
12
|
+
# it does exist, ask.
|
13
|
+
print "This will replace the stored key, are you sure? [y/N] "
|
14
|
+
case STDIN.gets.chomp
|
15
|
+
when /y/i
|
16
|
+
@write_file = true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# ask for api key if none is given
|
21
|
+
if apikey.nil? && @write_file
|
22
|
+
puts "Please enter your API key since you did not provide one: "
|
23
|
+
apikey = STDIN.gets.chomp
|
24
|
+
end
|
25
|
+
|
26
|
+
# write the api key to file
|
27
|
+
if @write_file
|
28
|
+
File.open( File.join(ENV['HOME'], '.slicehost-tools'), File::RDWR|File::TRUNC|File::CREAT, 0664 ) do |f|
|
29
|
+
f.puts "SlicehostSecretKey = '#{apikey}'"
|
30
|
+
f.close
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
%w( rubygems thor activeresource fileutils ).each do |dep|
|
2
|
+
begin
|
3
|
+
require dep
|
4
|
+
rescue LoadError
|
5
|
+
abort "#{dep} is required for the slicehost-tools suite to run."
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
require File.dirname(__FILE__) + "/slicehost-tools/resources"
|
10
|
+
require File.dirname(__FILE__) + "/slicehost-tools/tools"
|
11
|
+
|
12
|
+
trap('INT') { exit }
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{slicehost-tools}
|
5
|
+
s.version = "0.0.12"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Cameron Cox", "Bobby Uhlenbrock", "Corey Martella"]
|
9
|
+
s.date = %q{2008-09-10}
|
10
|
+
s.email = %q{cameroncox@gmail.com}
|
11
|
+
s.executables = ["slicehost-dns", "slicehost-slice"]
|
12
|
+
s.extra_rdoc_files = ["README.markdown", "LICENSE"]
|
13
|
+
s.files = ["bin", "bin/slicehost-dns", "bin/slicehost-slice", "lib", "lib/slicehost-tools", "lib/slicehost-tools/resources", "lib/slicehost-tools/resources/dns.rb", "lib/slicehost-tools/resources/slice.rb", "lib/slicehost-tools/resources.rb", "lib/slicehost-tools/tools", "lib/slicehost-tools/tools/dns.rb", "lib/slicehost-tools/tools/slice.rb", "lib/slicehost-tools/tools.rb", "lib/slicehost-tools.rb", "LICENSE", "Rakefile", "README.markdown", "slicehost-tools.gemspec"]
|
14
|
+
s.homepage = %q{http://github.com/cameroncox/slicehost-tools/}
|
15
|
+
s.require_paths = ["lib"]
|
16
|
+
s.rubygems_version = %q{1.3.1}
|
17
|
+
s.summary = %q{tools utilizing the slicehost api}
|
18
|
+
|
19
|
+
if s.respond_to? :specification_version then
|
20
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
21
|
+
s.specification_version = 2
|
22
|
+
|
23
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
24
|
+
s.add_runtime_dependency(%q<thor>, [">= 0.9.8"])
|
25
|
+
s.add_runtime_dependency(%q<activeresource>, [">= 2.1.1"])
|
26
|
+
else
|
27
|
+
s.add_dependency(%q<thor>, [">= 0.9.8"])
|
28
|
+
s.add_dependency(%q<activeresource>, [">= 2.1.1"])
|
29
|
+
end
|
30
|
+
else
|
31
|
+
s.add_dependency(%q<thor>, [">= 0.9.8"])
|
32
|
+
s.add_dependency(%q<activeresource>, [">= 2.1.1"])
|
33
|
+
end
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: slicehost-tools
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.12
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cameron Cox
|
8
|
+
- Bobby Uhlenbrock
|
9
|
+
- Corey Martella
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
|
14
|
+
date: 2008-09-10 00:00:00 -04:00
|
15
|
+
default_executable:
|
16
|
+
dependencies:
|
17
|
+
- !ruby/object:Gem::Dependency
|
18
|
+
name: thor
|
19
|
+
type: :runtime
|
20
|
+
version_requirement:
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
requirements:
|
23
|
+
- - ">="
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: 0.9.8
|
26
|
+
version:
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activeresource
|
29
|
+
type: :runtime
|
30
|
+
version_requirement:
|
31
|
+
version_requirements: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 2.1.1
|
36
|
+
version:
|
37
|
+
description:
|
38
|
+
email: cameroncox@gmail.com
|
39
|
+
executables:
|
40
|
+
- slicehost-dns
|
41
|
+
- slicehost-slice
|
42
|
+
extensions: []
|
43
|
+
|
44
|
+
extra_rdoc_files:
|
45
|
+
- README.markdown
|
46
|
+
- LICENSE
|
47
|
+
files:
|
48
|
+
- bin/slicehost-dns
|
49
|
+
- bin/slicehost-slice
|
50
|
+
- lib/slicehost-tools/resources/dns.rb
|
51
|
+
- lib/slicehost-tools/resources/slice.rb
|
52
|
+
- lib/slicehost-tools/resources.rb
|
53
|
+
- lib/slicehost-tools/tools/dns.rb
|
54
|
+
- lib/slicehost-tools/tools/slice.rb
|
55
|
+
- lib/slicehost-tools/tools.rb
|
56
|
+
- lib/slicehost-tools.rb
|
57
|
+
- LICENSE
|
58
|
+
- Rakefile
|
59
|
+
- README.markdown
|
60
|
+
- slicehost-tools.gemspec
|
61
|
+
has_rdoc: true
|
62
|
+
homepage: http://github.com/booster/slicehost-tools/
|
63
|
+
licenses: []
|
64
|
+
|
65
|
+
post_install_message:
|
66
|
+
rdoc_options: []
|
67
|
+
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: "0"
|
75
|
+
version:
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: "0"
|
81
|
+
version:
|
82
|
+
requirements: []
|
83
|
+
|
84
|
+
rubyforge_project:
|
85
|
+
rubygems_version: 1.3.5
|
86
|
+
signing_key:
|
87
|
+
specification_version: 2
|
88
|
+
summary: tools utilizing the slicehost api
|
89
|
+
test_files: []
|
90
|
+
|