dreamy 0.5.1

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.
@@ -0,0 +1,57 @@
1
+ require 'commands/base'
2
+
3
+ module Dreamy
4
+ module Command
5
+ class InvalidCommand < RuntimeError; end
6
+
7
+ class << self
8
+ def run(command, args)
9
+ run_internal(command, args)
10
+ rescue InvalidCommand
11
+ error "Unknown command. Run 'dh help' for usage information."
12
+ rescue ApiError => e
13
+ error "DreamHost returned this error: #{e}"
14
+ rescue Interrupt => e
15
+ error "\n[canceled]"
16
+ end
17
+
18
+ def run_internal(command, args)
19
+ namespace, command = parse(command)
20
+ require "commands/#{namespace}"
21
+ klass = Dreamy::Command.const_get(namespace.capitalize).new(args)
22
+ raise InvalidCommand unless klass.respond_to?(command)
23
+ klass.send(command)
24
+ end
25
+
26
+ def error(msg)
27
+ STDERR.puts(msg)
28
+ exit 1
29
+ end
30
+
31
+ def parse(command)
32
+ parts = command.split(':')
33
+ case parts.size
34
+ when 1
35
+ if namespaces.include? command
36
+ return command, 'index'
37
+ else
38
+ raise InvalidCommand
39
+ end
40
+ when 2
41
+ raise InvalidCommand unless namespaces.include? parts[0]
42
+ return parts
43
+ else
44
+ raise InvalidCommand
45
+ end
46
+ end
47
+
48
+ def namespaces
49
+ @@namespaces ||= Dir["#{File.dirname(__FILE__)}/commands/*"].map do |namespace|
50
+ namespace.gsub(/.*\//, '').gsub(/\.rb/, '')
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,73 @@
1
+ module Dreamy::Command
2
+ class Announce < Base
3
+
4
+ def index
5
+ lists = @account.announce_lists
6
+
7
+ if lists.empty?
8
+ display "No announcement lists on this account"
9
+ else
10
+ list_table = table do |t|
11
+ t.headings = 'Name', 'Short Name', 'Domain', 'Subscribers', 'Max Bounces', 'Start Date'
12
+ lists.each { |l| t << [l.name, l.short_name, l.domain, l.subscribers, l.max_bounces, l.start_date]}
13
+ end
14
+ display list_table
15
+ end
16
+ end
17
+
18
+ def list
19
+ if args.length >= 1
20
+ listname, domain = extract_values(args.shift)
21
+ subscribers = @account.announce_list(listname,domain)
22
+ if subscribers.empty?
23
+ display "No subscribers to this list"
24
+ else
25
+ subscriber_table = table do |t|
26
+ t.headings = 'email', 'name', 'subscribe_date', 'bounces'
27
+ subscribers.each { |s| t << [s.email, s.name, s.subscribe_date, s.num_bounces] }
28
+ end
29
+ display subscriber_table
30
+ display "#{subscribers.size} total subscribers"
31
+ end
32
+ else
33
+ display "Usage: dh announce:list my_list@example.com"
34
+ end
35
+ end
36
+
37
+ def add
38
+ if args.length >= 2
39
+ listname, domain = extract_values(args.shift)
40
+ email = args.shift
41
+ if @account.announce_add(listname,domain,email)
42
+ display "Successfully added #{email} to #{listname} list"
43
+ else
44
+ display "Failed to add #{email} to #{listname} list"
45
+ end
46
+ else
47
+ display "Usage: dh announce:add my_list@example.com new_guy@gmail.com"
48
+ end
49
+ end
50
+
51
+ def remove
52
+ if args.length >= 2
53
+ listname, domain = extract_values(args.shift)
54
+ email = args.shift
55
+ if @account.announce_remove(listname,domain,email)
56
+ display "Successfully removed #{email} from #{listname} list"
57
+ else
58
+ display "Failed to remove #{email} from #{listname} list"
59
+ end
60
+ else
61
+ display "Usage: dh announce:remove my_list@example.com new_guy@gmail.com"
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def extract_values(arg)
68
+ arg =~ /^(.*)@(.*)$/
69
+ return $1, $2
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,96 @@
1
+ require 'terminal-table/import'
2
+
3
+ module Dreamy::Command
4
+ class Base
5
+
6
+ attr_accessor :args
7
+ def initialize(args)
8
+ @args = args
9
+ @account = configure_account
10
+ end
11
+
12
+ def display(msg, newline=true)
13
+ if newline
14
+ puts(msg)
15
+ else
16
+ print(msg)
17
+ STDOUT.flush
18
+ end
19
+ end
20
+
21
+ def ask
22
+ gets.strip
23
+ end
24
+
25
+ def shell(cmd)
26
+ `cd '#{Dir.pwd}' && #{cmd}`
27
+ end
28
+
29
+ def extract_option(options, default=true)
30
+ values = options.is_a?(Array) ? options : [options]
31
+ return unless opt_index = args.select { |a| values.include? a }.first
32
+ opt_position = args.index(opt_index) + 1
33
+ if args.size > opt_position && opt_value = args[opt_position]
34
+ if opt_value.include?('--')
35
+ opt_value = nil
36
+ else
37
+ args.delete_at(opt_position)
38
+ end
39
+ end
40
+ opt_value ||= default
41
+ args.delete(opt_index)
42
+ block_given? ? yield(opt_value) : opt_value
43
+ end
44
+
45
+ def home_directory
46
+ running_on_windows? ? ENV['USERPROFILE'] : ENV['HOME']
47
+ end
48
+
49
+ def running_on_windows?
50
+ RUBY_PLATFORM =~ /mswin32/
51
+ end
52
+
53
+ private
54
+
55
+ def configure_account
56
+ Dreamy::Base.new(user,key)
57
+ end
58
+
59
+ def user
60
+ get_credentials
61
+ @credentials[0]
62
+ end
63
+
64
+ def key
65
+ get_credentials
66
+ @credentials[1]
67
+ end
68
+
69
+ def credentials_file
70
+ "#{home_directory}/.dreamyrc"
71
+ end
72
+
73
+ def read_credentials
74
+ if File.exists? credentials_file
75
+ return File.read(credentials_file).split("\n")
76
+ end
77
+ end
78
+
79
+ def get_credentials
80
+ return if @credentials
81
+ unless @credentials = read_credentials
82
+ @credentials = [ENV['DH_USER'], ENV['DH_KEY']]
83
+ end
84
+ if @credentials[0].nil? || @credentials[1].nil?
85
+ display "\nYou need to set your API credentials. You can do this 2 ways:\n"
86
+ display "\n1) set environment variables 'DH_USER' and 'DH_KEY'"
87
+ display "2) create ~/.dreamyrc with user on first line and key on second\n\n"
88
+ exit 1
89
+ end
90
+ @credentials
91
+ end
92
+
93
+
94
+ end
95
+
96
+ end
@@ -0,0 +1,48 @@
1
+ module Dreamy::Command
2
+ class Dns < Base
3
+
4
+ def list
5
+ dns = @account.dns
6
+
7
+ if args.length > 0
8
+ filter = args.shift.downcase
9
+ dns = dns.select { |d| d.zone.match(filter) }
10
+ end
11
+
12
+ if dns.empty?
13
+ display "No DNS records for this account or requested zone not found"
14
+ else
15
+ dns_table = table do |t|
16
+ t.headings = 'Record', 'Type', 'Value'
17
+ dns.each { |d| t << [d.record,d.type,d.value] if d.type != "TXT" }
18
+ end
19
+ display "NOTE: TXT records not displayed (too long)"
20
+ display dns_table
21
+ end
22
+ end
23
+ alias :index :list
24
+
25
+ def add
26
+ if args.length == 3
27
+ record, type, value = args[0], args[1], args[2]
28
+ @account.dns_add(record,type,value)
29
+ display "Successfully added #{type} record of #{value} to #{record}"
30
+ display "Please wait for DNS to propagate"
31
+ else
32
+ display "Usage: dh dns:add [new record] [type] [value]"
33
+ end
34
+ end
35
+
36
+ def remove
37
+ if args.length == 3
38
+ record, type, value = args[0], args[1], args[2]
39
+ @account.dns_remove(record,type,value)
40
+ display "Successfully removed #{type} record of #{value} to #{record}"
41
+ display "Please wait for DNS to propagate"
42
+ else
43
+ display "Usage: dh dns:remove [new record] [type] [value]"
44
+ end
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,61 @@
1
+ require 'ping'
2
+
3
+ module Dreamy::Command
4
+ class Domains < Base
5
+
6
+ def index
7
+ http
8
+ end
9
+
10
+ def http
11
+ domains = @account.domains.reject { |d| d.type != 'http'}
12
+
13
+ if domains.empty?
14
+ display "No HTTP domains on this account"
15
+ else
16
+ domain_table = table do |t|
17
+ t.headings = 'Domain Name', 'Server', 'Type', 'User', 'WWW or Not'
18
+ domains.each { |d| t << [d.domain,d.short_home,d.hosting_type,d.user,d.www_or_not]}
19
+ end
20
+ display domain_table
21
+ end
22
+ end
23
+
24
+ def mysql
25
+ domains = @account.domains.reject { |d| d.type != 'mysqldns'}
26
+
27
+ if domains.empty?
28
+ display "No MySQL domains on this account"
29
+ else
30
+ domain_table = table do |t|
31
+ t.headings = 'Domain Name', 'Server'
32
+ domains.each { |d| t << [d.domain,d.short_home]}
33
+ end
34
+ display domain_table
35
+ end
36
+ end
37
+
38
+ def status
39
+ domains = @account.domains
40
+ domains.each do |d|
41
+ if host_available?(d.domain)
42
+ display "#{d.domain} is up"
43
+ else
44
+ display "#{d.domain} is down!"
45
+ if host_available?(d.home)
46
+ display " But its host server (#{d.home}) is up"
47
+ else
48
+ display " And its host server (#{d.home}) is down"
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ protected
55
+
56
+ def host_available?(host)
57
+ Ping.pingecho host
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,48 @@
1
+ module Dreamy::Command
2
+ class Help < Base
3
+ def index
4
+ display usage
5
+ end
6
+
7
+ def usage
8
+ usage = <<EOTXT
9
+
10
+ === Commands
11
+
12
+ announce # list announce lists
13
+ announce:list <list> # list all subscribers to <name> list
14
+ announce:add <list> <email> # add subscriber with <email> to <list>
15
+ announce:remove <list> <email> # remove subscriber with <email> from <list>
16
+
17
+ dns # list DNS records
18
+ dns <name> # list DNS records for <name>
19
+ dns:add <record> <type> <value> # add DNS record
20
+ dns:remove <record> <type> <value> # remove DNS record
21
+
22
+ domains:http # list HTTP domain details
23
+ domains:mysql # list MySQL domains
24
+ domains:status # check availability of all domains (pingability)
25
+
26
+ mysql:dbs # list MySQL database details
27
+ mysql:hosts # list MySQL database hostnames
28
+ mysql:users # list MySQL user details
29
+
30
+ ps # list private servers
31
+ ps:add <web|mysql> <yes|no> # adds a private server of type <web|mysql>. Yes = move data
32
+ ps:pending # list private servers scheduled to be created
33
+ ps:reboots <name> # list historical reboots for <name>
34
+ ps:reboot <name> now! # reboot <name> now! (proceed with caution)
35
+ ps:remove # removes all pending private servers
36
+ ps:settings <name> # list settings for private server <name>
37
+ ps:set <name> <setting> <value> # change <setting> on <name> to <value>
38
+ ps:size <name> # list historical memory sizes for <name>
39
+ ps:size <name> <value> # set new memory <value> for <name>
40
+ ps:usage <name> # list historical memory & CPU usage for <name>
41
+
42
+ users # list user accounts: details
43
+ users:pw # list user accounts: usernames & passwords
44
+
45
+ EOTXT
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,45 @@
1
+ module Dreamy::Command
2
+ class Mysql < Base
3
+
4
+ def dbs
5
+ dbs = @account.mysql_dbs
6
+ if dbs.empty?
7
+ display "No MySQL databases on this account"
8
+ else
9
+ db_table = table do |t|
10
+ t.headings = 'Name', 'Home', 'Description', 'Disk used (MB)'
11
+ dbs.each { |db| t << [db.name,db.home,db.description,db.disk_usage_mb] }
12
+ end
13
+ display db_table
14
+ end
15
+ end
16
+ alias :index :dbs
17
+
18
+ def hosts
19
+ hosts = @account.mysql_hosts
20
+ if hosts.empty?
21
+ display "No MySQL hosts on this account"
22
+ else
23
+ host_table = table do |t|
24
+ t.headings = 'Domain Name','Home'
25
+ hosts.each { |host| t << [host.domain,host.home] }
26
+ end
27
+ display host_table
28
+ end
29
+ end
30
+
31
+ def users
32
+ users = @account.mysql_users
33
+ if users.empty?
34
+ display "No MySQL users on this account"
35
+ else
36
+ user_table = table do |t|
37
+ t.headings = 'Username', 'Database', 'Sel', 'Ins', 'Upd', 'Del', 'Cre', 'Drop', 'Ind', 'Alt'
38
+ users.each { |u| t << [u.username,u.db,u.select,u.insert,u.update,u.delete,u.create,u.drop,u.index,u.alter] }
39
+ end
40
+ display user_table
41
+ end
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,136 @@
1
+ module Dreamy::Command
2
+ class Ps < Base
3
+
4
+ def list
5
+ servers = @account.ps
6
+
7
+ if servers.empty?
8
+ display "No private servers for this account"
9
+ else
10
+ servers_table = table do |t|
11
+ t.headings = 'Name', 'Type', 'Memory (MB)', 'Start Date'
12
+ servers.each { |ps| t << [ps.name,ps.type,ps.memory,ps.start_date] }
13
+ end
14
+ display servers_table
15
+ end
16
+ end
17
+ alias :index :list
18
+
19
+ def settings
20
+ if args.length == 1
21
+ settings = @account.ps_settings(args[0])
22
+ settings_table = table do |t|
23
+ t.headings = 'Setting', 'Value'
24
+ settings.each { |k,v| t << [k,v] }
25
+ end
26
+ display settings_table
27
+ else
28
+ display "Usage: dh ps:settings [ps name]"
29
+ end
30
+ end
31
+
32
+ def set
33
+ if args.length == 3
34
+ name, setting, value = args[0], args[1], args[2]
35
+ @account.ps_set(name,setting,value)
36
+ display "Successfully set #{setting} to #{value} for #{name}"
37
+ else
38
+ display "Usage: dh ps:set [ps name] [setting] [value]"
39
+ end
40
+ end
41
+
42
+ def size
43
+ case args.length
44
+ when 1
45
+ sizes = @account.ps_size_history(args[0])
46
+ sizes_table = table do |t|
47
+ t.headings = 'Time', 'Memory (MB)', 'Duration (Seconds)', 'Cost (Period)', 'Cost (Monthly)'
48
+ sizes.each { |s| t << [s["stamp"],s["memory_mb"],s["period_seconds"],s["period_cost"],s["monthy_cost"]] }
49
+ end
50
+ display sizes_table
51
+ when 2
52
+ name, new_size = args[0], args[1]
53
+ @account.ps_size_set(name,new_size)
54
+ display "Successfully set memory size to #{new_size} for #{name}"
55
+ else
56
+ display "Usage: dh ps:size [ps name] [new size (optional)]"
57
+ end
58
+ end
59
+
60
+ def reboots
61
+ if args.length == 1
62
+ reboots = @account.ps_reboot_history(args[0])
63
+ reboots_table = table do |t|
64
+ t.headings = 'Count', 'Reboot Time'
65
+ reboots.each_with_index { |r,i| t << [i + 1,r] }
66
+ end
67
+ display reboots_table
68
+ else
69
+ display "Usage: dh ps:reboots [ps name]"
70
+ end
71
+ end
72
+
73
+ def reboot
74
+ if args.length == 2
75
+ if args[1] == "now!"
76
+ @account.ps_reboot!(args[0])
77
+ display "Successfully sent reboot command for #{args[0]}"
78
+ else
79
+ display "Are you sure?? If yes, finish the command with 'now!'"
80
+ end
81
+ else
82
+ display "Usage: dh ps:reboot [ps name] now! (WARNING: this will reboot your server)"
83
+ end
84
+ end
85
+
86
+ def usage
87
+ if args.length == 1
88
+ usages = @account.ps_usage(args[0])
89
+ usage_table = table do |t|
90
+ t.headings = 'Time', 'Memory (MB)', 'CPU Load'
91
+ usages.each { |u| t << [u["stamp"], u["memory_mb"],u["load"]] }
92
+ end
93
+ display usage_table
94
+ else
95
+ display "Usage: dh ps:usage [ps name]"
96
+ end
97
+ end
98
+
99
+ def add
100
+ case args.length
101
+ when 1
102
+ if args[0] == "web"
103
+ display "you must specify 'yes' or 'no' for whether or not to move data to new server"
104
+ else
105
+ @account.ps_add(args[0])
106
+ display "Successfully requested new private mysql server"
107
+ end
108
+ when 2
109
+ type, move = args[0], args[1]
110
+ @account.ps_add(type,move)
111
+ display "Successfully requested new private server"
112
+ else
113
+ display "Usage: dh ps:add <web|mysql> <yes|no>"
114
+ end
115
+ end
116
+
117
+ def remove
118
+ @account.ps_remove
119
+ display "Successfully removed all pending private server requests"
120
+ end
121
+
122
+ def pending
123
+ pendings = @account.ps_pending
124
+ if pendings.empty?
125
+ display "You have no pending server creations"
126
+ else
127
+ pending_table = table do |t|
128
+ t.headings = 'Account', 'IP Address', 'Type', 'Time'
129
+ pendings.each { |p| t << [p["account_id"],p["ip"],p["type"],p["stamp"]]}
130
+ end
131
+ display pending_table
132
+ end
133
+ end
134
+
135
+ end
136
+ end