cameroncox-slicehost-tools 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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,40 @@
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, destroys your life, and sleeps with your wife. YOU HAVE BEEN WARNED.
8
+
9
+ ## Installation
10
+
11
+ gem sources -a http://gems.github.com
12
+
13
+ sudo gem install wycats-thor
14
+ sudo gem install uhlenbrock-slicehost-tools
15
+
16
+ ## Usage
17
+
18
+ slicehost-dns
19
+
20
+ add [DOMAIN] [IP] add a domain for the given ip
21
+ list lists all zones and their associated records
22
+ delete [DOMAIN] removes a domain
23
+ apikey [APIKEY] set your Slicehost API Key and save it to ~/.slicehost-tools
24
+ help [TASK] describe available tasks or one specific task
25
+
26
+ slicehost-slice
27
+
28
+ add [SLICE NAME] [--force] add a new slice
29
+ delete [SLICE] delete a slice
30
+ list list slices
31
+ hard_reboot [SLICE] perform a hard reboot
32
+ soft_reboot [SLICE] perform a soft reboot
33
+ apikey [APIKEY] set your Slicehost API Key and save it to ~/.slicehost-tools
34
+ help [TASK] describe available tasks or one specific task
35
+
36
+
37
+ ## TODO
38
+
39
+ [DONE] Finish up the slice tool
40
+ Multiple Slicehost accounts? (not likely, but an idea)
data/Rakefile ADDED
@@ -0,0 +1,30 @@
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.3"
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"]
13
+ s.date = %q{2008-07-1}
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/cameroncox/slicehost-tools/}
21
+ s.require_paths = ["lib"]
22
+ s.rubygems_version = %q{1.1.1}
23
+ s.add_dependency("wycats-thor", ">= 0.9.2")
24
+ end
25
+
26
+ Rake::GemPackageTask.new(gem_spec) do |p|
27
+ p.gem_spec = gem_spec
28
+ p.need_tar = true
29
+ p.need_zip = true
30
+ end
data/bin/slicehost-dns ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + "/../lib/slicehost-tools"
3
+ require :"slicehost-tools" / :tools / :dns
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + "/../lib/slicehost-tools"
3
+ require :"slicehost-tools" / :tools / :slice
@@ -0,0 +1,16 @@
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
+ # add the current directory to the search path...
10
+ $: << File.expand_path( File.dirname(__FILE__) )
11
+
12
+ require 'slicehost-tools/extlib'
13
+ require :"slicehost-tools" / :resources
14
+ require :"slicehost-tools" / :tools
15
+
16
+ trap('INT') { exit }
@@ -0,0 +1,2 @@
1
+ require File.join( File.expand_path(File.dirname(__FILE__)), "extlib", "symbol" )
2
+ require File.join( File.expand_path(File.dirname(__FILE__)), "extlib", "string" )
@@ -0,0 +1,5 @@
1
+ class String
2
+ def /(path)
3
+ File.join(self.to_s, path.to_s)
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Symbol
2
+ def /(path)
3
+ File.join(self.to_s, path.to_s)
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+
2
+ if File.exists? ENV['HOME'] / :".slicehost-tools"
3
+ load ENV['HOME'] / :".slicehost-tools"
4
+ else
5
+ require :"slicehost-tools" / :tools
6
+ Tools::Default.start(['apikey'])
7
+ exit
8
+ end
9
+
10
+ module Resources
11
+ class Base < ActiveResource::Base
12
+ self.site = "http://#{SlicehostSecretKey}@api.slicehost.com" if defined?(SlicehostSecretKey)
13
+ end
14
+ end
@@ -0,0 +1,18 @@
1
+ module Resources
2
+ class Zone < Base
3
+
4
+ def records(reload = false)
5
+ @records = nil if reload
6
+ @records ||= Record.find(:all, :params => { :zone_id => self.id })
7
+ end
8
+
9
+ class << self
10
+ def find_by_origin(origin)
11
+ find(:first, :params => { :origin => "#{origin}." })
12
+ end
13
+ end
14
+ end
15
+
16
+ class Record < Base
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ module Resources
2
+ class Slice < Base
3
+ class << self
4
+ def find_by_name(name)
5
+ find(:first, :params => { :name => name })
6
+ end
7
+ end
8
+ end
9
+
10
+ class Flavor < Base
11
+ def to_s; self.name;
12
+ end
13
+ end
14
+
15
+ class Image < Base
16
+ def to_s; self.name;
17
+ end
18
+ end
19
+ 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? 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( 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,71 @@
1
+ require :"slicehost-tools" / :resources / :dns
2
+ module Tools
3
+ class DNS < Default
4
+
5
+ map "-L" => :list
6
+
7
+ desc "add [DOMAIN] [IP]", "add a domain for the given ip"
8
+ def add(domain = nil, ip = nil)
9
+ unless domain
10
+ puts "Please give a domain to add:"
11
+ domain = STDIN.gets.chomp
12
+ end
13
+
14
+ unless ip
15
+ puts "Please give the IP to use for this domain"
16
+ ip = STDIN.gets.chomp
17
+ end
18
+
19
+ zone = Resources::Zone.new( :origin => "#{domain}.", :ttl => 3660, :active => "Y" )
20
+
21
+ if zone.save
22
+
23
+ Resources::Record.new( :record_type => 'NS', :zone_id => zone.id, :name => "#{domain}.", :data => "ns1.slicehost.net" ).save
24
+ Resources::Record.new( :record_type => 'NS', :zone_id => zone.id, :name => "#{domain}.", :data => "ns2.slicehost.net" ).save
25
+ Resources::Record.new( :record_type => 'NS', :zone_id => zone.id, :name => "#{domain}.", :data => "ns3.slicehost.net" ).save
26
+ Resources::Record.new( :record_type => 'A', :zone_id => zone.id, :name => "#{domain}.", :data => "#{ip}" ).save
27
+ Resources::Record.new( :record_type => 'CNAME', :zone_id => zone.id, :name => "www", :data => "#{domain}.").save
28
+ Resources::Record.new( :record_type => 'CNAME', :zone_id => zone.id, :name => "ftp", :data => "#{domain}.").save
29
+
30
+ puts "#{domain} added successfully."
31
+ else
32
+ puts "\n#{domain} could not be added."
33
+ puts zone.errors.full_messages.to_yaml
34
+ end
35
+ end
36
+
37
+ desc "list", "lists all zones and their associated records"
38
+ def list(domain = nil)
39
+ list_params = { :origin => "#{domain}." } unless domain.nil?
40
+ list_params ||= {}
41
+ Resources::Zone.find(:all, :params => list_params).each do |zone|
42
+ puts "+ #{zone.origin}"
43
+ zone.records.each do |record|
44
+ puts [' -', "[#{record.record_type}]".ljust(7, ' '), "#{record.name}"].join(' ')
45
+ end
46
+ end
47
+ end
48
+
49
+ desc "delete [DOMAIN]", "removes a domain"
50
+ def delete(domain = nil)
51
+ abort "You must give a domain" if domain.nil?
52
+
53
+ puts "Type the phrase \"I am sure\" to remove this zone"
54
+ @sure = false
55
+ case STDIN.gets.chomp
56
+ when "I am sure"
57
+ @sure = true
58
+ end
59
+
60
+ if @sure && domain
61
+ Resources::Zone.find_by_origin(domain).destroy
62
+ puts "#{domain} is no more."
63
+ else
64
+ puts "aborting"
65
+ end
66
+ end
67
+
68
+ # init Thor
69
+ start
70
+ end
71
+ end
@@ -0,0 +1,119 @@
1
+ require :"slicehost-tools" / :resources / :slice
2
+ module Tools
3
+ class Slice < Default
4
+
5
+ map "-L" => :list
6
+
7
+ desc "add [SLICE NAME]", "add a new slice"
8
+ method_options :force => :boolean
9
+ def add(slice_name, opts)
10
+ images = Resources::Image.find(:all)
11
+ flavors = Resources::Flavor.find(:all)
12
+
13
+ puts "Available Images: "
14
+ image_id = select_image_from(images)
15
+
16
+ puts "Available Flavors: "
17
+ flavor_id = select_flavor_from(flavors)
18
+
19
+ @add = false
20
+ # confirm you want to do this, it does cost money
21
+ unless opts[:force]
22
+ print "Are you sure you want do this? [y/N]: "
23
+ case STDIN.gets.chomp
24
+ when /y/i
25
+ @add = true
26
+ end
27
+ end
28
+
29
+ if @add
30
+ slice = Resources::Slice.new(:name => slice_name, :flavor_id => flavor_id, :image_id => image_id)
31
+ slice.save
32
+ end
33
+
34
+ end
35
+
36
+ desc "delete [SLICE]", "delete a slice"
37
+ def delete(slice_name = nil)
38
+ slice_name = select_slice.name if slice_name.nil?
39
+
40
+ @abort = true
41
+ slice = Resources::Slice.find_by_name(slice_name)
42
+ puts "Please type 'I understand this is not undoable' to proceed: "
43
+ case STDIN.gets.chomp
44
+ when "I understand this is not undoable"
45
+ @abort = false
46
+ end
47
+
48
+ unless @abort
49
+ puts "You have 5 seconds to change your mind (CTRL+C)"
50
+ sleep 5
51
+ puts "Say goodnight gracie."
52
+ slice.destroy
53
+ sleep 3
54
+ puts "Goodnight gracie."
55
+ else
56
+ puts "Your slice has not been nuked. (I hope)"
57
+ end
58
+
59
+ end
60
+
61
+ desc "list", "list slices"
62
+ def list
63
+ Resources::Slice.find(:all).each do |slice|
64
+ puts "+ #{slice.name} (#{slice.ip_address})"
65
+ end
66
+ end
67
+
68
+ desc "hard_reboot [SLICE]", "perform a hard reboot"
69
+ def hard_reboot(slice_name = nil)
70
+ slice_name = select_slice.name if slice_name.nil?
71
+
72
+ puts "(hard) rebooting #{slice_name}"
73
+ reboot(:hard_reboot, slice_name)
74
+ end
75
+
76
+ desc "soft_reboot [SLICE]", "perform a soft reboot"
77
+ def soft_reboot(slice_name = nil)
78
+ slice_name = select_slice.name if slice_name.nil?
79
+
80
+ puts "(soft) rebooting #{slice_name}"
81
+ reboot(:reboot, slice_name)
82
+ end
83
+
84
+
85
+ protected
86
+
87
+ def select_slice
88
+ slices = Resources::Slice.find(:all)
89
+ slices.each_index { |i| puts "[#{i}] #{slices[i].name}" }
90
+ print "Select a Slice by #: "
91
+ input = STDIN.gets.chomp.to_i
92
+ slices[input]
93
+ end
94
+
95
+ def select_image_from(images)
96
+ images.each_index { |i| puts "[#{i}] #{images[i].name}" }
97
+ print "Select an Image by #: "
98
+ input = STDIN.gets.chomp.to_i
99
+ images[input].id
100
+ end
101
+
102
+ def select_flavor_from(flavors)
103
+ flavors.each_index { |i| puts "[#{i}] #{flavors[i].name} (#{flavors[i].ram}mb) ($#{flavors[i].price}/month)" }
104
+ print "Select an Image by #: "
105
+ input = STDIN.gets.chomp.to_i
106
+ flavors[input].id
107
+ end
108
+
109
+ def reboot(type, slice_name)
110
+ slice = Resources::Slice.find_by_name(slice_name)
111
+ slice.put(type)
112
+ end
113
+
114
+ public
115
+
116
+ # init thor
117
+ start
118
+ end
119
+ end
@@ -0,0 +1,20 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{slicehost-tools}
3
+ s.version = "0.0.3"
4
+
5
+ s.specification_version = 2 if s.respond_to? :specification_version=
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Cameron Cox"]
9
+ s.date = %q{2008-07-1}
10
+ s.summary = %q{tools utilizing the slicehost api}
11
+ s.email = %q{cameroncox@gmail.com}
12
+ s.executables = ["slicehost-dns", "slicehost-slice"]
13
+ s.extra_rdoc_files = ["README.markdown", "LICENSE"]
14
+ s.files = ["bin", "bin/slicehost-dns", "bin/slicehost-slice", "lib", "lib/slicehost-tools", "lib/slicehost-tools/extlib", "lib/slicehost-tools/extlib/string.rb", "lib/slicehost-tools/extlib/symbol.rb", "lib/slicehost-tools/extlib.rb", "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"]
15
+ # s.has_rdoc = false
16
+ s.homepage = %q{http://github.com/cameroncox/slicehost-tools/}
17
+ s.require_paths = ["lib"]
18
+ s.rubygems_version = %q{1.1.1}
19
+ s.add_dependency("wycats-thor", ">= 0.9.2")
20
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cameroncox-slicehost-tools
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Cameron Cox
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-07-01 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: wycats-thor
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.9.2
23
+ version:
24
+ description:
25
+ email: cameroncox@gmail.com
26
+ executables:
27
+ - slicehost-dns
28
+ - slicehost-slice
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.markdown
33
+ - LICENSE
34
+ files:
35
+ - bin
36
+ - bin/slicehost-dns
37
+ - bin/slicehost-slice
38
+ - lib
39
+ - lib/slicehost-tools
40
+ - lib/slicehost-tools/extlib
41
+ - lib/slicehost-tools/extlib/string.rb
42
+ - lib/slicehost-tools/extlib/symbol.rb
43
+ - lib/slicehost-tools/extlib.rb
44
+ - lib/slicehost-tools/resources
45
+ - lib/slicehost-tools/resources/dns.rb
46
+ - lib/slicehost-tools/resources/slice.rb
47
+ - lib/slicehost-tools/resources.rb
48
+ - lib/slicehost-tools/tools
49
+ - lib/slicehost-tools/tools/dns.rb
50
+ - lib/slicehost-tools/tools/slice.rb
51
+ - lib/slicehost-tools/tools.rb
52
+ - lib/slicehost-tools.rb
53
+ - LICENSE
54
+ - Rakefile
55
+ - README.markdown
56
+ - slicehost-tools.gemspec
57
+ has_rdoc: false
58
+ homepage: http://github.com/cameroncox/slicehost-tools/
59
+ post_install_message:
60
+ rdoc_options: []
61
+
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ version:
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: "0"
75
+ version:
76
+ requirements: []
77
+
78
+ rubyforge_project:
79
+ rubygems_version: 1.2.0
80
+ signing_key:
81
+ specification_version: 2
82
+ summary: tools utilizing the slicehost api
83
+ test_files: []
84
+