dreamy 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,159 @@
1
+ What is it?
2
+ ===========
3
+
4
+ [Dreamy][1] is Ruby library and command line tool for interfacing with [DreamHost's API][2]. The API itself is still very young so this is by no means a comprehensive library. Please fork and contribute!
5
+
6
+
7
+ Install
8
+ =======
9
+
10
+ Grab the gem from GitHub
11
+
12
+ gem sources -a http://gems.github.com
13
+ gem install sant0sk1-dreamy
14
+
15
+ Library Usage
16
+ =============
17
+
18
+ DreamHost requires a username (email or webID) and API key (available from your DH Panel) to make API requests. When creating a Dreamy instance you'll need to provide this data. The Dreamy command line tool (dh) gathers the necessary info from a configuration file or environment variables, but you can do it however you'd like.
19
+
20
+ To get started with the library, just require the gem:
21
+
22
+ require 'rubygems'
23
+ require 'dreamy'
24
+
25
+ Create a new object using your username and API key.
26
+
27
+ account = Dreamy::Base.new(username,api_key)
28
+
29
+ Fetch an array of Dreamy::Domain objects:
30
+
31
+ account.domains
32
+
33
+ Now that you have an array you can have your way with the data:
34
+
35
+ account.domains.each do |d|
36
+ puts d.domain
37
+ puts d.type
38
+ puts d.home
39
+ end
40
+
41
+ Same goes with Users, DNS records, announcement list subscribers, MySQL databases, MySQL hosts, and MySQL users
42
+
43
+ # fetch an array of Dreamy::User objects
44
+ account.users
45
+
46
+ # fetch an array of Dreamy::Dns objects
47
+ account.dns
48
+
49
+ # fetch an array of Dreamy::AnnounceList objects
50
+ account.announce_lists
51
+
52
+ # fetch an array of Dreamy::Subscribers to an announcement list
53
+ account.announce_list(listname,domain)
54
+
55
+ # fetch an array of Dreamy::MysqlUser objects
56
+ account.mysql_users
57
+
58
+ You can interact with announcement lists by adding and removing subscribers
59
+
60
+ # add a new subscriber to an announcement list
61
+ account.announce_add(listname,domain,email)
62
+
63
+ # remove a subscriber from an announcement list
64
+ account.announce_remove(listname,domain,email)
65
+
66
+ You can interact with DNS by adding and removing records
67
+
68
+ # add a new A record for a subdomain of an hosted domain
69
+ account.dns_add(subdomain,"A","123.321.123.321")
70
+
71
+ # remove the A record just created
72
+ account.dns_remove(subdomain,"A","123.321.123.321")
73
+
74
+ You can interact with your Private Server in many different ways
75
+
76
+ # change a private server setting
77
+ account.ps_set(ps_name,setting,value)
78
+
79
+ # set the memory size (MB)
80
+ account.ps_size_set(ps_name,"200")
81
+
82
+ # reboot the server
83
+ account.ps_reboot!(ps_name)
84
+
85
+ Check the base class for all the different API calls.
86
+
87
+ More and more functions will be added as time allows. If there's something missing that you want in, please:
88
+
89
+ fork -> commit -> pull request
90
+
91
+ Command Line Usage
92
+ ==================
93
+
94
+ The Dreamy gem will install an executable called "dh". In order to use it, you'll need to set your DreamHost account username and API key. You can acquire an API key from the DreamHost panel. "dh" will fetch your API credentials from 2 places, respectively:
95
+
96
+ 1) A file called .dreamyrc in your $HOME directory with username on line 1, api key on line 2
97
+
98
+ An example ~/.dreamyrc would look like:
99
+
100
+ dh_user@gmail.com
101
+ 34TGGGKBRG3YD1EA
102
+
103
+ 2) Environment variables DH\_USER and DH\_KEY. You can set these by typing this in your shell:
104
+
105
+ export DH_USER=dh_user@gmail.com
106
+ export DH_KEY=34TGGGKBRG3YD1EA
107
+
108
+ If you want to make those environment variables permanent, add those 2 lines to the bottom of your ~/.bashrc
109
+
110
+
111
+ Run this from the command line to print the usage:
112
+
113
+ dh help
114
+
115
+ === Commands
116
+
117
+ announce # list announce lists
118
+ announce:list <list> # list all subscribers to <name> list
119
+ announce:add <list> <email> # add subscriber with <email> to <list>
120
+ announce:remove <list> <email> # remove subscriber with <email> from <list>
121
+
122
+ dns # list DNS records
123
+ dns <name> # list DNS records for <name>
124
+ dns:add <record> <type> <value> # add DNS record
125
+ dns:remove <record> <type> <value> # remove DNS record
126
+
127
+ domains:http # list HTTP domain details
128
+ domains:mysql # list MySQL domains
129
+ domains:status # check availability of all domains (pingability)
130
+
131
+ mysql:dbs # list MySQL database details
132
+ mysql:hosts # list MySQL database hostnames
133
+ mysql:users # list MySQL user details
134
+
135
+ ps # list private servers
136
+ ps:add <web|mysql> <yes|no> # adds a private server of type <web|mysql>. Yes = move data
137
+ ps:pending # list private servers scheduled to be created
138
+ ps:reboots <name> # list historical reboots for <name>
139
+ ps:reboot <name> now! # reboot <name> now! (proceed with caution)
140
+ ps:remove # removes all pending private servers
141
+ ps:settings <name> # list settings for private server <name>
142
+ ps:set <name> <setting> <value> # change <setting> on <name> to <value>
143
+ ps:size <name> # list historical memory sizes for <name>
144
+ ps:size <name> <value> # set new memory <value> for <name>
145
+ ps:usage <name> # list historical memory & CPU usage for <name>
146
+
147
+ users # list user accounts: details
148
+ users:pw # list user accounts: usernames & passwords
149
+
150
+
151
+ That's it for now. New commands should be springing up as Dreamy and the DreamHost API mature!
152
+
153
+ TODO
154
+ ====
155
+
156
+ * add real rdocs
157
+
158
+ [1]:http://github.com/sant0sk1/dreamy
159
+ [2]:http://wiki.Dreamy.com/API
@@ -0,0 +1,28 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ task :default => [:test_units]
5
+
6
+ desc "Run basic tests"
7
+ Rake::TestTask.new("test_units") { |t|
8
+ t.pattern = 'test/*_test.rb'
9
+ t.verbose = true
10
+ t.warning = true
11
+ }
12
+
13
+ begin
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gemspec|
16
+ gemspec.name = "dreamy"
17
+ gemspec.summary = "A Ruby library and command line tool for accessing DreamHost's API"
18
+ gemspec.email = "jerod.santo@gmail.com"
19
+ gemspec.homepage = "http://github.com/sant0sk1/dreamy"
20
+ gemspec.authors = ["Jerod Santo"]
21
+ gemspec.add_dependency('visionmedia-terminal-table', '>= 1.0.5')
22
+ gemspec.add_dependency('hpricot', '>= 0.7')
23
+ gemspec.add_dependency('uuid', '>= 2.0.1')
24
+ gemspec.files.exclude 'test/credentials.yml'
25
+ end
26
+ rescue LoadError
27
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
28
+ end
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 5
3
+ :patch: 1
4
+ :major: 0
data/bin/dh ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
6
+
7
+ require 'dreamy'
8
+ require 'dreamy/command'
9
+
10
+ args = ARGV.dup
11
+ ARGV.clear
12
+ command = args.shift.strip rescue 'help'
13
+
14
+ Dreamy::Command.run(command, args)
@@ -0,0 +1,27 @@
1
+ require 'uri'
2
+ require 'net/https'
3
+ require 'yaml'
4
+ require 'rubygems'
5
+ require 'hpricot'
6
+ require 'uuid'
7
+
8
+
9
+ $:.unshift(File.dirname(__FILE__) + "/dreamy")
10
+ require 'dreamy/core_extensions'
11
+ require 'dreamy/easy_class_maker'
12
+ require 'dreamy/base'
13
+ require 'dreamy/domain'
14
+ require 'dreamy/dns'
15
+ require 'dreamy/announce_list'
16
+ require 'dreamy/private_server'
17
+ require 'dreamy/subscriber'
18
+ require 'dreamy/user'
19
+ require 'dreamy/mysql/db'
20
+ require 'dreamy/mysql/host'
21
+ require 'dreamy/mysql/user'
22
+
23
+ module Dreamy
24
+ class CantConnect < StandardError; end
25
+ class Unavailable < StandardError; end
26
+ class ApiError < StandardError; end
27
+ end
@@ -0,0 +1,19 @@
1
+ module Dreamy
2
+ class AnnounceList
3
+ include EasyClassMaker
4
+
5
+ attributes :account_id, :name, :domain, :short_name, :start_date, :max_bounces, :subscribers
6
+
7
+ def self.new_from_xml(xml)
8
+ l = new
9
+ l.account_id = (xml).at('account_id').innerHTML.to_i
10
+ l.short_name = (xml).at('listname').innerHTML
11
+ l.domain = (xml).at('domain').innerHTML
12
+ l.name = (xml).at('name').innerHTML
13
+ l.start_date = (xml).at('start_date').innerHTML
14
+ l.max_bounces = (xml).at('max_bounces').innerHTML.to_i
15
+ l.subscribers = (xml).at('num_subscribers').innerHTML.to_i
16
+ l
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,234 @@
1
+ module Dreamy
2
+ class Base
3
+
4
+ @@host = "api.dreamhost.com"
5
+
6
+ def initialize(username, key)
7
+ @username = username
8
+ @key = key
9
+ end
10
+
11
+ # returns an array of domain objects
12
+ def domains
13
+ doc = request("domain-list_domains")
14
+ api_error?(doc)
15
+ (doc/:data).inject([]) { |domains, domain| domains << Domain.new_from_xml(domain); domains }
16
+ end
17
+
18
+ # returns an array of user objects
19
+ def users(passwords=false)
20
+ if passwords
21
+ doc = request("user-list_users")
22
+ else
23
+ doc = request("user-list_users_no_pw")
24
+ end
25
+ api_error?(doc)
26
+ (doc/:data).inject([]) { |users, user| users << User.new_from_xml(user); users }
27
+ end
28
+
29
+ # returns an array of dns objects
30
+ def dns
31
+ doc = request("dns-list_records")
32
+ api_error?(doc)
33
+ (doc/:data).inject([]) { |records, dns| records << Dns.new_from_xml(dns); records }
34
+ end
35
+
36
+ def dns_add(record,type,value)
37
+ doc = request("dns-add_record", {"record" => record, "type" => type, "value" => value})
38
+ api_error?(doc)
39
+ true
40
+ end
41
+
42
+ def dns_remove(record,type,value)
43
+ doc = request("dns-remove_record", {"record" => record, "type" => type, "value" => value})
44
+ api_error?(doc)
45
+ true
46
+ end
47
+
48
+ def announce_lists
49
+ doc = request("announcement_list-list_lists")
50
+ api_error?(doc)
51
+ (doc/:data).inject([]) { |lists, list| lists << AnnounceList.new_from_xml(list); lists }
52
+ end
53
+
54
+ # returns an array of subscriber objects
55
+ def announce_list(listname,domain)
56
+ doc = request("announcement_list-list_subscribers",{ "listname" => listname, "domain" => domain})
57
+ api_error?(doc)
58
+ (doc/:data).inject([]) { |subs, sub| subs << Subscriber.new_from_xml(sub); subs }
59
+ end
60
+
61
+ # adds new subscriber to announce list
62
+ def announce_add(listname,domain,email,name="")
63
+ doc = request("announcement_list-add_subscriber",
64
+ {"listname" => listname, "domain" => domain, "email" => email, "name" => name})
65
+ api_error?(doc)
66
+ true
67
+ end
68
+
69
+ def announce_remove(listname,domain,email)
70
+ doc = request("announcement_list-remove_subscriber",
71
+ {"listname" => listname, "domain" => domain, "email" => email})
72
+ api_error?(doc)
73
+ true
74
+ end
75
+
76
+ # options:
77
+ # stamp - the time to send the message, like "2009-05-28" or "2009-05-28 14:24:36"
78
+ # charset - the character set in which the message is encoded
79
+ # type - the format of the message, either "text" or "html"
80
+ # duplicate_ok - whether to allow duplicate messages to be sent, like 1 or 0
81
+ def announce_post(listname,domain,subject,message,name,options={})
82
+ values = {
83
+ "listname" => listname,
84
+ "domain" => domain,
85
+ "subject" => subject,
86
+ "message" => message,
87
+ "name" => name
88
+ }.merge(options)
89
+ doc = request("announcement_list-post_announcement", values, true)
90
+ api_error?(doc)
91
+ true
92
+ end
93
+
94
+ def mysql_dbs
95
+ doc = request("mysql-list_dbs")
96
+ api_error?(doc)
97
+ (doc/:data).inject([]) { |dbs, db| dbs << MysqlDb.new_from_xml(db); dbs }
98
+ end
99
+
100
+ def mysql_hosts
101
+ doc = request("mysql-list_hostnames")
102
+ api_error?(doc)
103
+ (doc/:data).inject([]) { |hosts, host| hosts << MysqlHost.new_from_xml(host); hosts }
104
+ end
105
+
106
+ def mysql_users
107
+ doc = request("mysql-list_users")
108
+ api_error?(doc)
109
+ (doc/:data).inject([]) { |users, user| users << MysqlUser.new_from_xml(user); users }
110
+ end
111
+
112
+ def ps
113
+ doc = request("dreamhost_ps-list_ps")
114
+ api_error?(doc)
115
+ (doc/:data).inject([]) { |servers, server| servers << PrivateServer.new_from_xml(server); servers }
116
+ end
117
+
118
+ def ps_settings(name)
119
+ doc = request("dreamhost_ps-list_settings", {"ps" => name})
120
+ api_error?(doc)
121
+ PrivateServer.settings_from_xml(doc)
122
+ end
123
+
124
+ def ps_set(name,setting,value)
125
+ doc = request("dreamhost_ps-set_settings", {"ps" => name, setting => value})
126
+ api_error?(doc)
127
+ true
128
+ end
129
+
130
+ def ps_size_history(name)
131
+ doc = request("dreamhost_ps-list_size_history", {"ps" => name})
132
+ api_error?(doc)
133
+ (doc/:data).inject([]) { |sizes, size| sizes << PrivateServer.size_from_xml(size); sizes }
134
+ end
135
+
136
+ def ps_size_set(name,size)
137
+ doc = request("dreamhost_ps-set_size", {"ps" => name, "size" => size})
138
+ api_error?(doc)
139
+ true
140
+ end
141
+
142
+ def ps_reboot_history(name)
143
+ doc = request("dreamhost_ps-list_reboot_history", {"ps" => name})
144
+ api_error?(doc)
145
+ (doc/:data).inject([]) { |reboots,reboot| reboots << reboot.at('stamp').innerHTML; reboots }
146
+ end
147
+
148
+ def ps_reboot!(name)
149
+ doc = request("dreamhost_ps-reboot", {"ps" => name})
150
+ api_error?(doc)
151
+ true
152
+ end
153
+
154
+ def ps_usage(name)
155
+ doc = request("dreamhost_ps-list_usage", {"ps" => name})
156
+ api_error?(doc)
157
+ (doc/:data).inject([]) { |usages, usage| usages << PrivateServer.usage_from_xml(usage); usages }
158
+ end
159
+
160
+ def ps_add(type,movedata="no")
161
+ doc = request("dreamhost_ps-add_ps", {"type" => type, "movedata" => movedata})
162
+ api_error?(doc)
163
+ true
164
+ end
165
+
166
+ def ps_remove
167
+ doc = request("dreamhost_ps-remove_pending_ps")
168
+ api_error?(doc)
169
+ true
170
+ end
171
+
172
+ def ps_pending
173
+ doc = request("dreamhost_ps-list_pending_ps")
174
+ api_error?(doc)
175
+ (doc/:data).inject([]) { |pends, pend| pends << PrivateServer.pending_from_xml(pend); pends }
176
+ end
177
+
178
+ private
179
+
180
+ def api_error?(doc)
181
+ raise ApiError, (doc/:data).innerHTML if (doc/:result).innerHTML == "error"
182
+ end
183
+
184
+ def request(cmd,values={},use_post=false)
185
+ handle_response!(response(cmd,values,use_post))
186
+ end
187
+
188
+ def response(cmd,values={},use_post=false)
189
+ values = {
190
+ "username" => @username,
191
+ "key" => @key,
192
+ "cmd" => cmd,
193
+ "format" => "xml",
194
+ "unique_id" => UUID.new.generate
195
+ }.merge(values)
196
+
197
+ http = Net::HTTP.new(@@host, 443)
198
+ http.use_ssl = true
199
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
200
+
201
+ begin
202
+ # puts path
203
+ response = if use_post
204
+ request = Net::HTTP::Post.new("/")
205
+ request.form_data = values
206
+ http.request(request)
207
+ else
208
+ path = "/?#{values.to_param_array.join("&")}"
209
+ http.get(path)
210
+ end
211
+ rescue => error
212
+ raise CantConnect, error.message
213
+ end
214
+ end
215
+
216
+ def handle_response!(response)
217
+ if %w[200 304].include?(response.code)
218
+ response = parse(response.body)
219
+ elsif response.code == '503'
220
+ raise Unavailable, response.message
221
+ elsif response.code == '401'
222
+ raise CantConnect, 'Authentication failed. Check your username and password'
223
+ else
224
+ raise CantConnect, "Dreamy is returning a #{response.code}: #{response.message}"
225
+ end
226
+ end
227
+
228
+ # Converts a string response into an Hpricot xml element.
229
+ def parse(response)
230
+ Hpricot.XML(response || '')
231
+ end
232
+
233
+ end
234
+ end