dnsmadeeasy 0.1.1 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e64f1077e858bdf6f2f0610f25435d4a5e47ba76
4
- data.tar.gz: b9960e5fc0e030d18bd0cb94688ca7d816ea8547
3
+ metadata.gz: f3fe4a8e5e7490cd827fe1c39b7cb9eec1458ee6
4
+ data.tar.gz: 6b3f939c99808e319bcd77a4f77f34a456a3957f
5
5
  SHA512:
6
- metadata.gz: '08d663e73e365d22490e6066e94342aedc03519ad40a2a7ce99909a7b6369aa5344d6697c0410c5a8e6bb2e4935c3eaabdf78d862a6132be837a43ed4c2311e6'
7
- data.tar.gz: 8f6b7e12f70dafd2ec645ef21edad1dc81af84b69fa8193996060d0dd06dac71ed2bd27c9e23827f4225368408a88b6275b1ec734b4c21ca629bfee44b17ef6f
6
+ metadata.gz: ceed4e0e1ac07e7047ba55b39e723c6203c050add20167419f200ef2be3c513400b6a9b628c496bf7ab5e6177cd52be072213fcaa7edecf231bd0c19772b8613
7
+ data.tar.gz: 5d33110950c9d523d9c7a25bd4f57f3cef57f42a788d8f138374d67dfb1bbf991850f3133b0e994c79c6c08a7ec9bd136b2b48736193a1a08b37550cba80abb9
data/README.md CHANGED
@@ -18,28 +18,28 @@ Once you have the key and the secret, you have several choices:
18
18
 
19
19
  1. Perhaps the most conveniently, you can store them in a small YAML file, that must be placed in a specific location within your home folder: `~/.dnsmadeeasy/credentials.yml`. The file should look like this one below (NOTE: these are not real credentials, btw):
20
20
 
21
- ```yaml
22
- # file: ~/.dnsmadeeasy/credentials.yml
23
- credentials:
24
- api_key: 2062259f-f666b17-b1fa3b48-042ad4030
25
- api_secret: 2265bc3-e31ead-95b286312e-c215b6a0
26
- ```
21
+ ```yaml
22
+ # file: ~/.dnsmadeeasy/credentials.yml
23
+ credentials:
24
+ api_key: 2062259f-f666b17-b1fa3b48-042ad4030
25
+ api_secret: 2265bc3-e31ead-95b286312e-c215b6a0
26
+ ```
27
27
 
28
- With this file existing, you can query right away, by using the shortcut module `DME`, such as
28
+ With this file existing, you can query right away, by using the shortcut module `DME`, such as
29
29
 
30
- ```ruby
31
- require 'dnsmadeeasy/dme' # this loads a `DME` shortcut.
32
- DME.domains.data.first.name #=> 'moo.gamespot.com'
33
- ```
30
+ ```ruby
31
+ require 'dme'
32
+ DME.domains.data.first.name #=> 'moo.gamespot.com'
33
+ ```
34
34
 
35
35
  2. Or, you can directly instantiate a new instance of the `Client` class, by passing your API key and API secrets as arguments:
36
36
 
37
- ```ruby
38
- require 'dnsmadeeasy'
39
- @client = DnsMadeEasy::Api::Client.new(api_key, api_secret)
40
- ```
37
+ ```ruby
38
+ require 'dnsmadeeasy'
39
+ @client = DnsMadeEasy::Api::Client.new(api_key, api_secret)
40
+ ```
41
41
 
42
- The advantage of this method is that you can query multiple DnsMadeEasy accounts from the same Ruby VM. With other methods, only one account can be connected to.
42
+ The advantage of this method is that you can query multiple DnsMadeEasy accounts from the same Ruby VM. With other methods, only one account can be connected to.
43
43
 
44
44
  3. Or, you can use the `DnsMadeEasy.configure` method to configure the key/secret pair, and then use `DnsMadeEasy` namespace to call the methods:
45
45
 
@@ -54,25 +54,40 @@ Once you have the key and the secret, you have several choices:
54
54
  DnsMadeEasy.domains.data.first.name #=> 'moo.gamespot.com'
55
55
  ```
56
56
 
57
- ### Shortcut Module `DME` and `DnsMadeEasy` Namespaces
57
+ ### Which Namespace to Use? What is `DME` versus `DnsMadeEasy`?
58
+
59
+ Since `DnsMadeEasy` is a bit of a mouthful, we decided to offer (in addition to the standard `DnsMadeEasy` namespace) the abbreviated module `DME` that simply forwards all messages to the module `DnsMadeEasy`. If in your Ruby VM there is no conflicting top-level class `DME`, then you can `require 'dnsmadeeasy/dme'` to get all of the DnsMadeEasy client library functionality without having to type the full name once. You can even do `require 'dme'`.
58
60
 
59
- Since `DnsMadeEasy` is a bit of a mouthful, we decided to offer (in addition) the abbreviated module `DME` that simply forwards all method calls to `DnsMadeEasy`. You can now `require 'dme'` to get all of the DnsMadeEasy client library loaded up, assuming it does not clash with any other `dme` file in your project.
61
+ Whenever you require `dme` you also import the `DnsMadeEasy` namespace. **The opposite is not true.**
60
62
 
61
- And then you can use `DME.method(*args)` as you would on `DnsMadeEasy.method(*args)` or on the instance of the actual worker-horse class of this library, the gorgeous blone with a very long name: `DnsMadeEasy::Api::Client`.
63
+ So if you DO have a name clash with another top-level module `DME`, simply do `require 'dnsmadeeasy'` and none of the `DME` module namespace will be loaded.
62
64
 
65
+ In a nutshell you have three ways to access all methods provided by the [`DnsMadeEasy::Api::Client`](http://www.rubydoc.info/gems/dnsmadeeasy/DnsMadeEasy/Api/Client) class:
66
+
67
+ 1. Instantiate and use the client class directly,
68
+ 2. Use the top-level module `DnsMadeEasy` with `require 'dnsmadeeasy'`
69
+ 3. Use the shortened top-level module `DME` with `require 'dnsmadeeasy/dme'`
63
70
 
64
71
  ### Examples
65
72
 
66
- If you are not planning on accessing more than one DnsMadeEasy account from the same Ruby VM, it's recommended to save the credentials in the above mentioned file. **DO NOT check that file into any repository.**
73
+ If you are planning on accessing *only one DnsMadeEasy account from the same Ruby VM*, it's recommended that you save your credentials (the API key and the secret) in the above mentioned file `~/.dnsmadeeasy/credentials.yml`.
67
74
 
68
- Assuming my credentials are stored, I can access everything about my domains as follows (let's pretend that I own a bunch of `gamespot` domains):
75
+ ___
69
76
 
77
+ > **NOTE:**
78
+ >
79
+ > * DO NOT check that file into your repo!
80
+ > * The examples that follow assume credentials have been read from that file.
70
81
 
71
- ```ruby
82
+ ___
72
83
 
84
+ Using the `DME` module (or `DnsMadeEasy` if you prefer) you can access all of your records through the available API method calls, for example:
73
85
 
74
- IRB(main):003:0> require 'dme' #=> true
75
- IRB(main):003:0> DME.domains.data.map(&:name)
86
+ ```ruby
87
+ IRB > require 'dme' #=> true
88
+ # Or you can also do
89
+ IRB > require 'dnsmadeeasy/dme' #=> true
90
+ IRB > DME.domains.data.map(&:name)
76
91
  ⤷ ["demo.gamespot.systems",
77
92
  "dev.gamespot.systems",
78
93
  "gamespot.live",
@@ -80,41 +95,86 @@ IRB(main):003:0> DME.domains.data.map(&:name)
80
95
  "prod.gamespot.systems"
81
96
  ]
82
97
 
83
- IRB(main):008:0> DME.api_key
98
+ # These have been read from the file ~/.dnsmadeeasy/credentials.yml
99
+ IRB > DME.api_key
84
100
  ⤷ "2062259f-f666b17-b1fa3b48-042ad4030"
85
101
 
86
- IRB(main):009:0> DME.api_secret
102
+ IRB > DME.api_secret
87
103
  ⤷ "2265bc3-e31ead-95b286312e-c215b6a0"
104
+
105
+ IRB > DME.domain('gamespot.live').delegateNameServers
106
+ ⤷ #<Hashie::Array ["ns-125-c.gandi.net.", "ns-129-a.gandi.net.", "ns-94-b.gandi.net."]>
88
107
 
89
- IRB(main):010:0> @client = DME.client
108
+ # Let's inspect the Client — after all, all methods are simply delegated to it:
109
+ IRB > @client = DME.client
90
110
  ⤷ #<DnsMadeEasy::Api::Client:0x00007fb6b416a4c8
91
111
  @api_key="2062259f-f666b17-b1fa3b48-042ad4030",
92
112
  @api_secret="2265bc3-e31ead-95b286312e-c215b6a0",
93
113
  @options={},
94
114
  @requests_remaining=149,
95
115
  @request_limit=150,
96
- @base_uri="https://api.dnsmadeeasy.com/V2.0">
116
+ @base_uri="https://api.dnsmadeeasy.com/V2.0">
97
117
  ```
98
118
 
99
- ### Return Values
119
+ Next, let's fetch a particular domain, get it's records and compute the counts for each record type, such as 'A', 'NS', etc.
100
120
 
101
- Whever DnsMadeEasy returns is typically a Hash, but we wrap it in a [`Hashie::Mash`](https://github.com/intridea/hashie) instance, which offers some additional benefits, such as the ability to call nested values via method calls instead of using square brackets. You can always call either `to_hash` or `to_h` on an instance of a `Hashie::Mash` to get a pure hash representation.
121
+ ```ruby
122
+ IRB > records = DME.records_for('gamespot.com')
123
+ IRB > [ records.totalPages, records.totalRecords ]
124
+ ⤷ [1, 33]
125
+ IRB > records.data.select{|f| f.type == 'A' }.map(&:name)
126
+ ⤷ ["www", "vpn-us-east1", "vpn-us-east2", "staging", "yourmom"]
127
+ IRB > types = records.data.map(&:type)
128
+ ⤷ [....]
129
+ IRB > require 'awesome_print'
130
+ IRB > ap Hash[types.group_by {|x| x}.map {|k,v| [k,v.count]}]
131
+ {
132
+ "MX" => 2,
133
+ "TXT" => 1,
134
+ "CNAME" => 3,
135
+ "NS" => 22,
136
+ "A" => 5
137
+ }
138
+ ```
139
+
140
+ ### Return Value Types
141
+
142
+ All public methods of this library return a Hash-like object, that is actually an instance of the class [`Hashie::Mash`](https://github.com/intridea/hashie). `Hashie::Mash` supports the very useful ability to reach deeply nested hash values via a chain of method calls instead of using a train of square brackets. You can always convert it to a regular hash either `to_hash` or `to_h` on an instance of a `Hashie::Mash` to get a pure hash representation.
102
143
 
103
- All return values are the direct JSON responses from DNS Made Easy converted into a Hash.
144
+ > NOTE: `to_hash` converts the entire object to a regular hash, including the deeply nested hashes, while `to_h` only converts the primary object, but not the nested hashes. Here is an example below — in the first instance where we call `to_h` we are still able to call `.value` on the nested object, because only the top-level `Mash` has been converted into a `Hash`. In the second example, this call fails, because this method does not exist, and the value must be accessed via the square brackets:
145
+ >
146
+ > ```ruby
147
+ > IRB > recs.to_h['data'].last.value
148
+ > ⤷ "54.200.26.233"
149
+ > IRB > recs.to_hash['data'].last.value
150
+ > "NoMethodError: undefined method `value` for #<Hash:0x00007fe36fab0f68>"
151
+ > IRB > recs.to_hash['data'].last['value']
152
+ > ⤷ "54.200.26.233"
153
+ > ```
104
154
 
105
155
  For more information on the actual JSON API, please refer to the [following PDF document](http://www.dnsmadeeasy.com/integration/pdf/API-Docv2.pdf).
106
156
 
107
- ## Method Calls
157
+ ## Available Actions
108
158
 
109
159
  Here is the complete of all methods supported by the `DnsMadeEasy::Api::Client`:
110
160
 
111
- * `base_uri=`
161
+ #### Domains
162
+
163
+ * `create_domain`
164
+ * `create_domains`
165
+ * `delete_domain`
166
+ * `domain`
167
+ * `domains`
168
+ * `get_id_by_domain`
169
+
170
+ #### Records
171
+
172
+ * `records_for`
173
+ * `all`
112
174
  * `base_uri`
113
175
  * `create_a_record`
114
176
  * `create_aaaa_record`
115
177
  * `create_cname_record`
116
- * `create_domain`
117
- * `create_domains`
118
178
  * `create_httpred_record`
119
179
  * `create_mx_record`
120
180
  * `create_ns_record`
@@ -124,54 +184,143 @@ Here is the complete of all methods supported by the `DnsMadeEasy::Api::Client`:
124
184
  * `create_srv_record`
125
185
  * `create_txt_record`
126
186
  * `delete_all_records`
127
- * `delete_domain`
128
187
  * `delete_record`
129
188
  * `delete_records`
130
- * `domain`
131
- * `domains`
132
- * `find_record_id`
133
- * `find`
134
- * `get_id_by_domain`
135
- * `records_for`
136
- * `request_limit`
137
- * `requests_remaining`
138
- * `update_record`
139
- * `update_records`
189
+ * `find_all`
190
+ * `find_first`
191
+ * `find_record_ids`
140
192
 
193
+ ## CLI Client
194
+
195
+ This library offers a simple CLI client `dme` that maps the command line arguments to method arguments for corresponding actions:
196
+
197
+ ```bash
198
+ ❯ dme --help
199
+ Usage:
200
+ # Execute an API call:
201
+ dme [ --json | --yaml ] operation [ arg1 arg2 ... ]
202
+
203
+ # Print suported operations:
204
+ dme op[erations]
205
+
206
+ Credentials:
207
+ Store your credentials in a YAML file
208
+ /Users/kig/.dnsmadeeasy/credentials.yml as follows:
209
+
210
+ credentials:
211
+ api_key: XXXX
212
+ api_secret: YYYY
213
+
214
+ Examples:
215
+ dme domain moo.com
216
+ dme --json domain moo.com
217
+ dme find_all moo.com A www
218
+ dme find_first moo.com CNAME vpn-west
219
+ dme --yaml find_first moo.com CNAME vpn-west
220
+ ```
221
+
222
+ You can run `dme operations` to see the supported list of operations:
223
+
224
+ ```bash
225
+ ❯ dme op
226
+ Actions:
227
+ Checkout the README and RubyDoc for the arguments to each operation,
228
+ which is basically a method on a DnsMadeEasy::Api::Client instance.
229
+ http://www.rubydoc.info/gems/dnsmadeeasy/DnsMadeEasy/Api/Client
230
+
231
+ Valid Operations Are:
232
+ all
233
+ base_uri
234
+ create_a_record
235
+ create_aaaa_record
236
+ create_cname_record
237
+ create_domain
238
+ create_domains
239
+ create_httpred_record
240
+ create_mx_record
241
+ create_ns_record
242
+ create_ptr_record
243
+ create_record
244
+ create_spf_record
245
+ create_srv_record
246
+ create_txt_record
247
+ delete_all_records
248
+ delete_domain
249
+ delete_record
250
+ delete_records
251
+ domain
252
+ domains
253
+ find_all
254
+ find_first
255
+ find_record_ids
256
+ get_id_by_domain
257
+ records_for
258
+ update_record
259
+ update_records
260
+ ```
261
+
262
+ For example:
263
+
264
+ ```bash
265
+ ❯ dme domains moo.com
266
+ ```
267
+
268
+ is equivalent to `DME.domains("moo.com")`. You can use any operation listed above, and output the result in either `YAML` or `JSON` (in addition to the default "awesome_print"), for example:
269
+
270
+ ```bash
271
+ ❯ dme --yaml find_all moo.com www CNAME
272
+ ---
273
+ - dynamicDns: false
274
+ failed: false
275
+ gtdLocation: DEFAULT
276
+ hardLink: false
277
+ ttl: 60
278
+ failover: false
279
+ monitor: false
280
+ sourceId: 5861234
281
+ source: 1
282
+ name: www
283
+ value: ec2-54-202-251-7.us-west-2.compute.amazonaws.com
284
+ id: 43509989
285
+ type: CNAME
286
+ ```
141
287
 
142
288
  ### Managing Domains
143
289
 
290
+ > NOTE: below we can be using `@client` instantiated with given key and secret, or
291
+ > `DME` or `DnsMadeEasy` module.
292
+
144
293
  To retrieve all domains:
145
294
 
146
295
  ```ruby
147
- @client.domains
296
+ require 'dnsmadeeasy/dme'
297
+ DME.domains
148
298
  ```
149
299
 
150
300
  To retreive the id of a domain by the domain name:
151
301
 
152
302
  ```ruby
153
- @client.get_id_by_domain('test.io')
303
+ DME.get_id_by_domain('test.io')
154
304
  ```
155
305
 
156
306
  To retrieve the full domain record by domain name:
157
307
 
158
308
  ```ruby
159
- @client.domain('test.io')
309
+ DME.domain('test.io')
160
310
  ```
161
311
 
162
312
  To create a domain:
163
313
 
164
314
  ```ruby
165
- @client.create_domain('test.io')
166
-
315
+ DME.create_domain('test.io')
167
316
  # Multiple domains can be created by:
168
- @client.create_domains(%w[test.io moo.re])
317
+ DME.create_domains(%w[test.io moo.re])
169
318
  ```
170
319
 
171
320
  To delete a domain:
172
321
 
173
322
  ```ruby
174
- @client.delete_domain ('test.io')
323
+ DME.delete_domain ('test.io')
175
324
  ```
176
325
 
177
326
  ### Managing Records
@@ -179,62 +328,68 @@ To delete a domain:
179
328
  To retrieve all records for a given domain name:
180
329
 
181
330
  ```ruby
182
- @client.records_for ('test.io')
331
+ DME.all('test.io')
183
332
  ```
184
333
 
185
334
  To find the record id for a given domain, name, and type:
186
335
 
187
- This finds the id of the A record 'woah.test.io'.
336
+ This finds all of the IDs matching 'woah.test.io' type 'A':
188
337
 
189
338
  ```ruby
190
- @client.find_record_id ('test.io', 'woah', 'A')
339
+ DME.find_record_ids ('test.io', 'woah', 'A')
340
+ # => [ 234234, 2342345 ]
191
341
  ```
192
342
 
193
- To delete a record by domain name and record id (the record id can be retrieved from `find_record_id`:
194
-
195
343
  ```ruby
196
- @client.delete_record ('test.io', 123)
197
-
344
+ # To delete a record by domain name and record id (the record id can be retrieved from `find_record_id`:
345
+ DME.delete_record ('test.io', 123)
198
346
  # To delete multiple records:
199
-
200
- @client.delete_records ('test.io', [123, 143])
201
-
347
+ DME.delete_records ('test.io', [123, 143])
202
348
  # To delete all records in the domain:
349
+ DME.delete_all_records ('test.io')
350
+ ```
203
351
 
204
- @client.delete_all_records ('test.io')
352
+ To create records of various types:
353
+
354
+ ```ruby
355
+ # The generic method:
356
+ DME.create_record ('test.io', 'woah', 'A', '127.0.0.1', { 'ttl' => '60' })
357
+
358
+ # Specialized methods:
359
+ DME.create_a_record ('test.io', 'woah', '127.0.0.1', {})
360
+ DME.create_aaaa_record ('test.io', 'woah', '127.0.0.1', {})
361
+ DME.create_ptr_record ('test.io', 'woah', '127.0.0.1', {})
362
+ DME.create_txt_record ('test.io', 'woah', '127.0.0.1', {})
363
+ DME.create_cname_record ('test.io', 'woah', '127.0.0.1', {})
364
+ DME.create_ns_record ('test.io', 'woah', '127.0.0.1', {})
365
+ DME.create_spf_record ('test.io', 'woah', '127.0.0.1', {})
205
366
  ```
206
367
 
207
- To create a record:
368
+ #### Specialized Record Types
369
+
370
+ Below are the method calls for `MX`, `SRV`, and `HTTPRED` types:
208
371
 
209
372
  ```ruby
210
- @client.create_record ('test.io', 'woah', 'A', '127.0.0.1', { 'ttl' => '60' })
211
- @client.create_a_record ('test.io', 'woah', '127.0.0.1', {})
212
- @client.create_aaaa_record ('test.io', 'woah', '127.0.0.1', {})
213
- @client.create_ptr_record ('test.io', 'woah', '127.0.0.1', {})
214
- @client.create_txt_record ('test.io', 'woah', '127.0.0.1', {})
215
- @client.create_cname_record ('test.io', 'woah', '127.0.0.1', {})
216
- @client.create_ns_record ('test.io', 'woah', '127.0.0.1', {})
217
- @client.create_spf_record ('test.io', 'woah', '127.0.0.1', {})
218
373
  # Arguments are: domain_name, name, priority, value, options = {}
219
- @client.create_mx_record ('test.io', 'woah', 5, '127.0.0.1', {})
374
+ DME.create_mx_record ('test.io', 'woah', 5, '127.0.0.1', {})
220
375
  # Arguments are: domain_name, name, priority, weight, port, value, options = {}
221
- @client.create_srv_record ('test.io', 'woah', 1, 5, 80, '127.0.0.1', {})
222
- # Arguments are: domain_name, name, value, redirectType, description, keywords, title, options = {}
223
- @client.create_httpred_record('test.io', 'woah', '127.0.0.1', 'STANDARD - 302',
376
+ DME.create_srv_record ('test.io', 'woah', 1, 5, 80, '127.0.0.1', {})
377
+ # Arguments are: domain_name, name, value, redirectType,
378
+ DME.create_httpred_record('test.io', 'woah', '127.0.0.1', 'STANDARD - 302',
379
+ # description, keywords, title, options = {}
224
380
  'a description', 'keywords', 'a title', {})
225
381
  ```
226
382
 
227
383
  To update a record:
228
384
 
229
385
  ```ruby
230
- @client.update_record ('test.io', 123, 'woah', 'A', '127.0.1.1',
231
- { 'ttl' => '60' })
386
+ DME.update_record('test.io', 123, 'woah', 'A', '127.0.1.1', { 'ttl' => '60' })
232
387
  ```
233
388
 
234
389
  To update several records:
235
390
 
236
391
  ```ruby
237
- @client.update_records('test.io',
392
+ DME.update_records('test.io',
238
393
  [
239
394
  { 'id' => 123,
240
395
  'name' => 'buddy',
@@ -248,7 +403,7 @@ To update several records:
248
403
  To get the number of API requests remaining after a call:
249
404
 
250
405
  ```ruby
251
- @client.requests_remaining
406
+ DME.requests_remaining
252
407
  #=> 19898
253
408
  ```
254
409
  > NOTE: Information is not available until an API call has been made
@@ -256,10 +411,11 @@ To get the number of API requests remaining after a call:
256
411
  To get the API request total limit after a call:
257
412
 
258
413
  ```ruby
259
- @client.request_limit
414
+ DME.request_limit
260
415
  #=> 2342
261
416
  ```
262
- >Information is not available until an API call has been made
417
+ > NOTE: Information is not available until an API call has been made
418
+
263
419
 
264
420
  ## Installation
265
421
 
@@ -294,7 +450,7 @@ The current maintainer [Konstantin Gredeskoul](https://github.com/kigster) wishe
294
450
 
295
451
  * Arnoud Vermeer for the original `dnsmadeeasy-rest-api` gem
296
452
  * Andre Arko, Paul Henry, James Hart formerly of [Wanelo](wanelo.com) fame, for bringing the REST API gem up to the level.
297
- * Phil Cohen, who graciously transferred the ownership of this gem on RubyGems to the current maintainer.
453
+ * Phil Cohen, who graciously transferred the ownership of the name of this gem on RubyGems.org to the current maintainer.
298
454
 
299
455
 
300
456
  ## Contributing
@@ -304,3 +460,5 @@ Bug reports and pull requests are welcome on GitHub at [https://github.com/kigst
304
460
  ## License
305
461
 
306
462
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
463
+
464
+
@@ -18,6 +18,19 @@ Gem::Specification.new do |spec|
18
18
  spec.email = %w(kigster@gmail.com letuboy@gmail.com hjhart@gmail.com)
19
19
  spec.summary = DnsMadeEasy::DESCRIPTION
20
20
  spec.description = DnsMadeEasy::DESCRIPTION
21
+ spec.post_install_message = <<-EOF
22
+
23
+ Thank you for using the DnsMadeEasy ruby gem, the Ruby client
24
+ API for DnsMadeEasy.com's SDK v2. Please note that this gem
25
+ comes with a command line utility 'dme' which you can use
26
+ instead of the ruby API if you prefer. Run `dme` with no
27
+ arguments to see the help message.
28
+
29
+ You can store your credentials in a YAML file in your home
30
+ directory. For more information, please see README at:
31
+ https://github.com/kigster/dnsmadeeasy
32
+
33
+ EOF
21
34
 
22
35
  spec.homepage = 'https://github.com/kigster/dnsmadeeasy'
23
36
  spec.license = 'MIT'
@@ -31,6 +44,8 @@ Gem::Specification.new do |spec|
31
44
  spec.require_paths = ['lib']
32
45
 
33
46
  spec.add_dependency 'hashie'
47
+ spec.add_dependency 'colored2'
48
+ spec.add_dependency 'awesome_print'
34
49
 
35
50
  spec.add_development_dependency 'yard'
36
51
  spec.add_development_dependency 'simplecov'
data/exe/dme CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'dnsmadeeasy'
4
- # require 'dnsmadeeasy/cli'
3
+ require 'dnsmadeeasy/runner'
4
+
5
+ DnsMadeEasy::Runner.new(ARGV).execute!
6
+
7
+
5
8
 
6
- # DnsMadeEasy::CLI::Runner.new(ARGV).execute!
7
- puts "Not yet implemented"
data/lib/dme.rb CHANGED
@@ -2,6 +2,10 @@ require 'dnsmadeeasy'
2
2
 
3
3
  module DME
4
4
  class << self
5
+ def [](key, secret)
6
+ ::DnsMadeEasy::Api::Client.new(key, secret)
7
+ end
8
+
5
9
  def method_missing(method, *args, &block)
6
10
  begin
7
11
  DnsMadeEasy.send(method, *args, &block)
@@ -3,11 +3,12 @@ module DnsMadeEasy
3
3
  API_BASE_URL_SANDBOX = 'https://sandboxapi.dnsmadeeasy.com/V2.0'
4
4
  end
5
5
 
6
- require_relative 'dnsmadeeasy/credentials'
7
- require_relative 'dnsmadeeasy/api/client'
6
+ require 'dnsmadeeasy/credentials'
7
+ require 'dnsmadeeasy/api/client'
8
8
 
9
9
  module DnsMadeEasy
10
10
  class Error < StandardError; end
11
+ class AuthenticationError < Error; end
11
12
  class APIKeyAndSecretMissingError < Error; end
12
13
 
13
14
  class << self
@@ -48,8 +49,13 @@ module DnsMadeEasy
48
49
  end
49
50
 
50
51
  def default!
52
+ assign_default_credentials
53
+ end
54
+
55
+
56
+ def assign_default_credentials
51
57
  if Credentials.exist?
52
- self.credentials = Credentials.default_file
58
+ self.credentials = Credentials.default_credentials_file
53
59
  end
54
60
  end
55
61
 
@@ -4,27 +4,46 @@ require 'json'
4
4
  require 'uri'
5
5
  require 'net/http'
6
6
  require 'hashie/mash'
7
+ require 'dnsmadeeasy/credentials'
7
8
 
8
9
  module DnsMadeEasy
9
10
  module Api
10
11
  class Client
11
12
 
13
+ class << self
14
+ def public_operations
15
+ (new('a', 'b').methods - Object.methods).map(&:to_s).reject { |r| r =~ /[=]$|^(api_|on_|request)/ }.sort
16
+ end
17
+ end
18
+
12
19
  attr_accessor :base_uri
13
- attr_reader :requests_remaining
14
- attr_reader :request_limit
20
+ attr_reader :requests_remaining,
21
+ :request_limit,
22
+ :api_key,
23
+ :api_secret
15
24
 
16
25
 
17
26
  def initialize(api_key, api_secret, sandbox = false, options = {})
18
27
  fail 'api_key is undefined' unless api_key
19
28
  fail 'api_secret is undefined' unless api_secret
20
29
 
21
- @api_key = api_key
22
- @api_secret = api_secret
23
- @options = options
30
+ @api_key = api_key
31
+ @api_secret = api_secret
32
+ @options = options
24
33
  @requests_remaining = -1
25
- @request_limit = -1
34
+ @request_limit = -1
35
+
36
+ sandbox ? on_sandbox : on_production
37
+ end
38
+
39
+
40
+ def on_sandbox(&block)
41
+ with_url(::DnsMadeEasy::API_BASE_URL_SANDBOX, &block)
42
+ end
43
+
26
44
 
27
- self.base_uri = sandbox ? API_BASE_URL_SANDBOX : API_BASE_URL_PRODUCTION
45
+ def on_production(&block)
46
+ with_url(::DnsMadeEasy::API_BASE_URL_PRODUCTION, &block)
28
47
  end
29
48
 
30
49
 
@@ -71,15 +90,25 @@ module DnsMadeEasy
71
90
  end
72
91
 
73
92
 
74
- def find(domain_name, name, type)
93
+ alias all records_for
94
+
95
+
96
+ def find_all(domain_name, name, type)
75
97
  records = records_for(domain_name)
76
- records['data'].detect { |r| r['name'] == name && r['type'] == type }
98
+ return nil unless records
99
+ records['data'].select { |r| r['name'] == name && r['type'] == type }
77
100
  end
78
101
 
79
102
 
80
- def find_record_id(domain_name, name, type)
103
+ def find_first(domain_name, name, type)
81
104
  records = records_for(domain_name)
105
+ return nil unless records
106
+ records['data'].detect { |r| r['name'] == name && r['type'] == type }
107
+ end
82
108
 
109
+
110
+ def find_record_ids(domain_name, name, type)
111
+ records = records_for(domain_name)
83
112
  records['data'].select { |r| r['name'] == name && r['type'] == type }.map { |r| r['id'] }
84
113
  end
85
114
 
@@ -109,6 +138,8 @@ module DnsMadeEasy
109
138
  end
110
139
 
111
140
 
141
+ # Specific record types
142
+
112
143
  def create_a_record(domain_name, name, value, options = {})
113
144
  # TODO: match IPv4 for value
114
145
  create_record domain_name, name, 'A', value, options
@@ -178,12 +209,12 @@ module DnsMadeEasy
178
209
  def update_records(domain, records, options = {})
179
210
  body = records.map do |record|
180
211
  {
181
- 'id' => record['id'],
182
- 'name' => record['name'],
183
- 'type' => record['type'],
184
- 'value' => record['value'],
212
+ 'id' => record['id'],
213
+ 'name' => record['name'],
214
+ 'type' => record['type'],
215
+ 'value' => record['value'],
185
216
  'gtdLocation' => record['gtdLocation'],
186
- 'ttl' => record['ttl']
217
+ 'ttl' => record['ttl']
187
218
  }.merge(options)
188
219
  end
189
220
  put "/dns/managed/#{get_id_by_domain(domain)}/records/updateMulti/", body
@@ -201,7 +232,7 @@ module DnsMadeEasy
201
232
 
202
233
  def delete(path, body = nil)
203
234
  request(path) do |uri|
204
- req = Net::HTTP::Delete.new(uri)
235
+ req = Net::HTTP::Delete.new(uri)
205
236
  req.body = body.to_json if body
206
237
  req
207
238
  end
@@ -210,7 +241,7 @@ module DnsMadeEasy
210
241
 
211
242
  def put(path, body = nil)
212
243
  request(path) do |uri|
213
- req = Net::HTTP::Put.new(uri)
244
+ req = Net::HTTP::Put.new(uri)
214
245
  req.body = body.to_json if body
215
246
  req
216
247
  end
@@ -219,7 +250,7 @@ module DnsMadeEasy
219
250
 
220
251
  def post(path, body)
221
252
  request(path) do |uri|
222
- req = Net::HTTP::Post.new(uri)
253
+ req = Net::HTTP::Post.new(uri)
223
254
  req.body = body.to_json
224
255
  req
225
256
  end
@@ -229,9 +260,9 @@ module DnsMadeEasy
229
260
  def request(path)
230
261
  uri = URI("#{base_uri}#{path}")
231
262
 
232
- http = Net::HTTP.new(uri.host, uri.port)
233
- http.use_ssl = true
234
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @options.key?(:ssl_verify_none)
263
+ http = Net::HTTP.new(uri.host, uri.port)
264
+ http.use_ssl = true
265
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @options.key?(:ssl_verify_none)
235
266
  http.open_timeout = @options[:open_timeout] if @options.key?(:open_timeout)
236
267
  http.read_timeout = @options[:read_timeout] if @options.key?(:read_timeout)
237
268
 
@@ -241,35 +272,53 @@ module DnsMadeEasy
241
272
  request[key] = value
242
273
  end
243
274
 
244
- response = http.request(request)
245
- response.value # raise Net::HTTPServerException unless response was 2xx
275
+ process_response!(http.request(request))
276
+ end
246
277
 
247
- process_rate_limits(response)
248
278
 
279
+ def process_response!(response)
280
+ response.value # raise Net::HTTPServerException unless response was 2xx
281
+ process_rate_limits(response)
249
282
  unparsed_json = response.body.to_s.empty? ? '{}' : response.body
250
-
251
283
  Hashie::Mash.new(JSON.parse(unparsed_json))
284
+ rescue Net::HTTPServerException => e
285
+ if e.message =~ /403.*forbidden/i
286
+ raise ::DnsMadeEasy::AuthenticationError.new(e)
287
+ else
288
+ raise e
289
+ end
252
290
  end
253
291
 
254
292
 
255
293
  def process_rate_limits(response)
256
294
  response.each_header do |header, value|
257
295
  @requests_remaining = value.to_i if header == 'x-dnsme-requestsremaining'
258
- @request_limit = value.to_i if header == 'x-dnsme-requestlimit'
296
+ @request_limit = value.to_i if header == 'x-dnsme-requestlimit'
259
297
  end
260
298
  end
261
299
 
262
300
 
263
301
  def request_headers
264
302
  request_date = Time.now.httpdate
265
- hmac = OpenSSL::HMAC.hexdigest('sha1', @api_secret, request_date)
303
+ hmac = OpenSSL::HMAC.hexdigest('sha1', @api_secret, request_date)
266
304
  {
267
- 'Accept' => 'application/json',
268
- 'x-dnsme-apiKey' => @api_key,
305
+ 'Accept' => 'application/json',
306
+ 'x-dnsme-apiKey' => @api_key,
269
307
  'x-dnsme-requestDate' => request_date,
270
- 'x-dnsme-hmac' => hmac
308
+ 'x-dnsme-hmac' => hmac
271
309
  }
272
310
  end
311
+
312
+
313
+ def with_url(url)
314
+ old_value = self.base_uri
315
+ self.base_uri = url
316
+ if block_given?
317
+ yield
318
+ self.base_uri = old_value
319
+ end
320
+ self
321
+ end
273
322
  end
274
323
  end
275
324
  end
@@ -25,7 +25,7 @@ module DnsMadeEasy
25
25
  #
26
26
  #
27
27
  class Credentials < Hash
28
- DEFAULT_CREDENTIALS_FILE = File.expand_path('~/.dnsmadeeasy/credentials.yml').freeze
28
+ #DEFAULT_CREDENTIALS_FILE = File.expand_path('~/.dnsmadeeasy/credentials.yml').freeze
29
29
 
30
30
  class CredentialsFileNotFound < StandardError
31
31
  end
@@ -33,13 +33,16 @@ module DnsMadeEasy
33
33
  #
34
34
  # Class Methods
35
35
  #
36
-
36
+ #
37
37
  class << self
38
- def exist?(file = DEFAULT_CREDENTIALS_FILE)
38
+ # Default credential file that's used if no argument is passed.
39
+ attr_accessor :default_credentials_file
40
+
41
+ def exist?(file = default_credentials_file)
39
42
  File.exist?(file)
40
43
  end
41
44
 
42
- def load(file = DEFAULT_CREDENTIALS_FILE)
45
+ def load(file = default_credentials_file)
43
46
  validate_argument(file)
44
47
 
45
48
  new.tap do |local|
@@ -48,10 +51,6 @@ module DnsMadeEasy
48
51
  end
49
52
  end
50
53
 
51
- def default_file
52
- DEFAULT_CREDENTIALS_FILE
53
- end
54
-
55
54
 
56
55
  private
57
56
 
@@ -72,6 +71,8 @@ module DnsMadeEasy
72
71
  end
73
72
  end
74
73
 
74
+ # Set the default
75
+ self.default_credentials_file ||= File.expand_path('~/.dnsmadeeasy/credentials.yml').freeze
75
76
 
76
77
  # Instance Methods
77
78
  # NOTE: we are subclassing Hash, which isn't awesome, but gets the job done.
@@ -116,7 +117,7 @@ module DnsMadeEasy
116
117
  when String, Symbol
117
118
  hash[key.to_sym] = value
118
119
  else
119
- hash[key] = value
120
+ hash[key.to_s.to_sym] = value
120
121
  end
121
122
  end
122
123
 
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'colored2'
4
+ require 'awesome_print'
5
+ require 'dnsmadeeasy'
6
+ require 'dnsmadeeasy/api/client'
7
+
8
+
9
+ module DnsMadeEasy
10
+ class Runner
11
+ SUPPORTED_FORMATS = %w(json yaml)
12
+
13
+ attr_accessor :format, :argv, :operation
14
+
15
+
16
+ def initialize(argv = nil)
17
+ self.argv = argv || ARGV.dup
18
+ configure_authentication
19
+ self.format = process_flags_format
20
+ end
21
+
22
+
23
+ def execute!
24
+ if argv.empty? || argv.size < 1
25
+ print_help_message
26
+ else
27
+ self.operation = argv.shift.to_sym
28
+ exit call_through_client(operation)
29
+ end
30
+ end
31
+
32
+
33
+ private
34
+
35
+ def call_through_client(method)
36
+ begin
37
+ result = DnsMadeEasy.client.send(method, *argv)
38
+ case result
39
+ when NilClass
40
+ puts 'No records returned.'
41
+ when Hashie::Mash
42
+ print_formatted(result.to_hash, format)
43
+ when Array
44
+ print_formatted(result.map(&:to_hash), format)
45
+ else
46
+ print_formatted(result, format)
47
+ end
48
+ 0
49
+ rescue ArgumentError => e
50
+ sig = method_signature(e, method)
51
+ (sig.shift == method.to_s) ?
52
+ print_signature(method, sig) :
53
+ print_error('Action', "#{method.to_s.bold.yellow}", 'has generated an error'.red, exception: e)
54
+ 1
55
+ rescue NoMethodError
56
+ print_error('Action', "#{method.to_s.bold.yellow}", 'is not valid.'.red)
57
+ puts 'HINT: try running ' + 'dme operations'.bold.green + ' to see the list of valid operations.'
58
+ 2
59
+ rescue Net::HTTPServerException => e
60
+ print_error(exception: e)
61
+ 3
62
+ end
63
+ end
64
+
65
+
66
+ def print_error(*args, exception: nil)
67
+ unless args.empty?
68
+ puts <<-EOF
69
+ #{'Error:'.bold.red} #{args.join(' ').red}
70
+ EOF
71
+ end
72
+
73
+ if exception
74
+ puts <<-EOF
75
+ #{'Exception: '.bold.red}#{exception.inspect.red}
76
+ EOF
77
+ end
78
+ end
79
+
80
+
81
+ def print_signature(method, sig)
82
+ puts <<-EOF
83
+ #{'Error: '.bold.yellow}
84
+ #{'You are missing some arguments for this operation:'.red}
85
+
86
+ #{'Correct Usage: '.bold.yellow}
87
+ #{method.to_s.bold.green} #{sig.join(' ').blue }
88
+
89
+ EOF
90
+ end
91
+
92
+
93
+ def process_flags_format
94
+ if argv.first&.start_with?('--')
95
+ format = argv.shift.gsub(/^--/, '')
96
+ if format =~ /^h(elp)?$/i
97
+ print_help_message
98
+ end
99
+ unless SUPPORTED_FORMATS.include?(format)
100
+ puts "Error: format #{format.bold.red} is not supported."
101
+ puts "Supported values are: #{SUPPORTED_FORMATS.join(', ')}"
102
+ exit 1
103
+ end
104
+ elsif argv.first =~ /^ope?r?a?t?i?o?n?$/i
105
+ print_supported_operations
106
+ exit 0
107
+ end
108
+ format
109
+ end
110
+
111
+
112
+ def configure_authentication
113
+ if ENV['DNSMADEEASY_API_KEY'] && ENV['DNSMADEEASY_API_SECRET']
114
+ DnsMadeEasy.configure do |config|
115
+ config.api_key = ENV['DNSMADEEASY_API_KEY']
116
+ config.api_secret = ENV['DNSMADEEASY_API_SECRET']
117
+ end
118
+ else
119
+ DnsMadeEasy.credentials = (ENV['DNSMADEEASY_CREDENTIALS'] || DnsMadeEasy::Credentials.default_credentials_file)
120
+ end
121
+ end
122
+
123
+
124
+ def print_usage_message
125
+ puts <<-EOF
126
+ #{'Usage:'.bold.yellow}
127
+ #{'# Execute an API call:'.dark}
128
+ #{"dme [ #{SUPPORTED_FORMATS.map { |f| "--#{f}" }.join(' | ')} ] operation [ arg1 arg2 ... ] ".bold.green}
129
+
130
+ #{'# Print suported operations:'.dark}
131
+ #{'dme op[erations]'.bold.green}
132
+
133
+ EOF
134
+ end
135
+
136
+
137
+ def print_help_message
138
+ print_usage_message
139
+
140
+ puts <<-EOF
141
+ #{'Credentials:'.bold.yellow}
142
+ Store your credentials in a YAML file
143
+ #{DnsMadeEasy::Credentials.default_credentials_file} as follows:
144
+
145
+ #{'credentials:
146
+ api_key: XXXX
147
+ api_secret: YYYY'.bold.magenta}
148
+
149
+ #{'Examples:'.bold.yellow}
150
+ #{'dme domain moo.com
151
+ dme --json domain moo.com
152
+ dme find_all moo.com A www
153
+ dme find_first moo.com CNAME vpn-west
154
+ dme --yaml find_first moo.com CNAME vpn-west'.green}
155
+
156
+ EOF
157
+ exit 1
158
+ end
159
+
160
+
161
+ def print_supported_operations
162
+ puts <<-EOF
163
+ #{'Actions:'.bold.yellow}
164
+ Checkout the README and RubyDoc for the arguments to each operation,
165
+ which is basically a method on a DnsMadeEasy::Api::Client instance.
166
+ #{'http://www.rubydoc.info/gems/dnsmadeeasy/DnsMadeEasy/Api/Client'.blue.bold.underlined}
167
+
168
+ #{'Valid Operations Are:'.bold.yellow}
169
+ #{DnsMadeEasy::Api::Client.public_operations.join("\n ").green.bold}
170
+
171
+ EOF
172
+ end
173
+
174
+
175
+ def print_formatted(result, format = nil)
176
+ if format
177
+ puts result.send("to_#{format}".to_sym)
178
+ else
179
+ ap(result, indent: 10)
180
+ end
181
+ end
182
+
183
+
184
+ # e.backtrack.first looks like this:
185
+ # ..../dnsmadeeasy/lib/dnsmadeeasy/api/client.rb:143:in `create_a_record'
186
+ def method_signature(e, method)
187
+ file, line, call_method = e.backtrace.first.split(':')
188
+ call_method = call_method.gsub(/[']/, '').split('`').last
189
+ if call_method && call_method.to_sym == method.to_sym
190
+ source_line = File.open(file).to_a[line.to_i - 1].chomp!
191
+ if source_line =~ /def #{method}/
192
+ signature = source_line.strip.gsub(/,/, '').split(%r{[ ()]})
193
+ signature.shift # remove def
194
+ return signature.reject { |a| a =~ /^([={}\)\(])*$/ }
195
+ end
196
+ end
197
+ []
198
+ rescue
199
+ []
200
+ end
201
+ end
202
+ end
203
+
204
+
205
+
@@ -1,3 +1,3 @@
1
1
  module DnsMadeEasy
2
- VERSION = '0.1.1'.freeze
2
+ VERSION = '0.2.3'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dnsmadeeasy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Gredeskoul
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: exe
14
14
  cert_chain: []
15
- date: 2017-12-09 00:00:00.000000000 Z
15
+ date: 2017-12-14 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: hashie
@@ -28,6 +28,34 @@ dependencies:
28
28
  - - ">="
29
29
  - !ruby/object:Gem::Version
30
30
  version: '0'
31
+ - !ruby/object:Gem::Dependency
32
+ name: colored2
33
+ requirement: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ - !ruby/object:Gem::Dependency
46
+ name: awesome_print
47
+ requirement: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ type: :runtime
53
+ prerelease: false
54
+ version_requirements: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
31
59
  - !ruby/object:Gem::Dependency
32
60
  name: yard
33
61
  requirement: !ruby/object:Gem::Requirement
@@ -170,12 +198,18 @@ files:
170
198
  - lib/dnsmadeeasy/api/client.rb
171
199
  - lib/dnsmadeeasy/credentials.rb
172
200
  - lib/dnsmadeeasy/dme.rb
201
+ - lib/dnsmadeeasy/runner.rb
173
202
  - lib/dnsmadeeasy/version.rb
174
203
  homepage: https://github.com/kigster/dnsmadeeasy
175
204
  licenses:
176
205
  - MIT
177
206
  metadata: {}
178
- post_install_message:
207
+ post_install_message: "\nThank you for using the DnsMadeEasy ruby gem, the Ruby client
208
+ \nAPI for DnsMadeEasy.com's SDK v2. Please note that this gem \ncomes with a command
209
+ line utility 'dme' which you can use \ninstead of the ruby API if you prefer. Run
210
+ `dme` with no\narguments to see the help message.\n\nYou can store your credentials
211
+ in a YAML file in your home\ndirectory. For more information, please see README
212
+ at:\nhttps://github.com/kigster/dnsmadeeasy\n\n"
179
213
  rdoc_options: []
180
214
  require_paths:
181
215
  - lib