zillabyte-cli 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +15 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +20 -0
  4. data/README.md +29 -0
  5. data/bin/zillabyte +18 -0
  6. data/lib/zillabyte/api/base.rb +11 -0
  7. data/lib/zillabyte/api/data.rb +126 -0
  8. data/lib/zillabyte/api/flows.rb +239 -0
  9. data/lib/zillabyte/api/locks.rb +4 -0
  10. data/lib/zillabyte/api/logs.rb +32 -0
  11. data/lib/zillabyte/api/metrics.rb +48 -0
  12. data/lib/zillabyte/api/queries.rb +58 -0
  13. data/lib/zillabyte/api/semantic_tags.rb +24 -0
  14. data/lib/zillabyte/api/settings.rb +8 -0
  15. data/lib/zillabyte/api/sources.rb +28 -0
  16. data/lib/zillabyte/api/zillalogs.rb +66 -0
  17. data/lib/zillabyte/api.rb +170 -0
  18. data/lib/zillabyte/auth.rb +155 -0
  19. data/lib/zillabyte/cli/auth.rb +33 -0
  20. data/lib/zillabyte/cli/base.rb +161 -0
  21. data/lib/zillabyte/cli/config.rb +63 -0
  22. data/lib/zillabyte/cli/counters.rb +61 -0
  23. data/lib/zillabyte/cli/flows.rb +702 -0
  24. data/lib/zillabyte/cli/help.rb +137 -0
  25. data/lib/zillabyte/cli/helpers/data_schema_builder.rb +3 -0
  26. data/lib/zillabyte/cli/host.rb +21 -0
  27. data/lib/zillabyte/cli/logs.rb +118 -0
  28. data/lib/zillabyte/cli/query.rb +172 -0
  29. data/lib/zillabyte/cli/relations.rb +326 -0
  30. data/lib/zillabyte/cli/sources.rb +37 -0
  31. data/lib/zillabyte/cli/templates/js/simple_function.js +33 -0
  32. data/lib/zillabyte/cli/templates/js/zillabyte.conf.yaml +2 -0
  33. data/lib/zillabyte/cli/templates/python/requirements.txt +7 -0
  34. data/lib/zillabyte/cli/templates/python/simple_function.py +27 -0
  35. data/lib/zillabyte/cli/templates/python/zillabyte.conf.yaml +4 -0
  36. data/lib/zillabyte/cli/templates/ruby/Gemfile +3 -0
  37. data/lib/zillabyte/cli/templates/ruby/simple_function.rb +36 -0
  38. data/lib/zillabyte/cli/templates/ruby/zillabyte.conf.yaml +2 -0
  39. data/lib/zillabyte/cli/version.rb +11 -0
  40. data/lib/zillabyte/cli/zillalogs.rb +86 -0
  41. data/lib/zillabyte/cli.rb +37 -0
  42. data/lib/zillabyte/command.rb +254 -0
  43. data/lib/zillabyte/common/progress.rb +17 -0
  44. data/lib/zillabyte/common/tar.rb +102 -0
  45. data/lib/zillabyte/common.rb +13 -0
  46. data/lib/zillabyte/helpers.rb +49 -0
  47. data/lib/zillabyte/queries.rb +39 -0
  48. data/lib/zillabyte-cli/version.rb +5 -0
  49. data/lib/zillabyte-cli.rb +5 -0
  50. data/zillabyte-cli.gemspec +42 -0
  51. data/zillabyte_emails.csv +1 -0
  52. data/zillaconf.json +3 -0
  53. metadata +278 -0
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YTVkNDVmMWE1NWJiMzhmMTk5M2IxOGJkZDExYjIxMTY3MGRiNDBjMg==
5
+ data.tar.gz: !binary |-
6
+ ZGEyMjU3NjM5MTE0NWE1N2I4ZDdkZjZlNTk2NmQzNzYzYmI2ZGZkYw==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NDk2ZTcyMjk1ODg5NTE3NTU0ZGFmNDlkYTY4MWIzOGEyYjEyYjJlNDk0YTI2
10
+ OTAwYmRkMWU1MzliOWYyMmIyZWFjMTFiZWI0NWE0NmUzZTA3Y2Y4ZTkyNjMz
11
+ ODBkYWQ1ZDA1MjkzZGE1NTg5MDA0NzMwZmFhYzNhNmRlYzBiNTY=
12
+ data.tar.gz: !binary |-
13
+ MjI3YzIzNGMzMjkzY2JjNjZmMjc2YzU4MDU3Y2RlNTQzYjE0OTYzN2VhNTc4
14
+ ZWRmMGZhMjc2M2FiYjkwYTc1OGY2YzUwNjM3YmRiOTU1NzA2OWFiNzBiNWU4
15
+ YTRjYTNiMzQyYWM5ZmVhZjdlZDY1MjI5ZDJkNjUzZjc3OWU1NTE=
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in zillabyte-cli.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Zillabyte
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Zillabyte
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'zillabyte'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install zillabyte
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/bin/zillabyte ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'zillabyte' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ require_relative '../lib/zillabyte-cli'
17
+ Zillabyte::CLI.start(*ARGV)
18
+
@@ -0,0 +1,11 @@
1
+ class Zillabyte::API::Base
2
+
3
+ def initialize(api)
4
+ @api = api
5
+ end
6
+
7
+ def request(*args)
8
+ @api.request(*args)
9
+ end
10
+
11
+ end
@@ -0,0 +1,126 @@
1
+ require 'net/http'
2
+
3
+ class Zillabyte::API::Data < Zillabyte::API::Base
4
+
5
+
6
+ # # GET /datasets
7
+ # def list(options = {})
8
+ #
9
+ # options = {
10
+ # # TODO
11
+ # }.merge(options)
12
+ #
13
+ # res = @api.request(
14
+ # :expects => 200,
15
+ # :method => :get,
16
+ # :path => "/datasets"
17
+ # )
18
+ #
19
+ # res.body
20
+ #
21
+ # end
22
+
23
+
24
+
25
+
26
+ # GET /datasets/1
27
+ def get(id, options = {})
28
+
29
+ options = {
30
+ :name => id
31
+ # rows
32
+ # schema
33
+ # relations
34
+ }.merge(options)
35
+
36
+ res = @api.request(
37
+ :expects => 200,
38
+ :method => :get,
39
+ :path => "/relations/#{id}",
40
+ :body => options.to_json
41
+ )
42
+
43
+ res.body
44
+
45
+ end
46
+
47
+
48
+ # POST /datasets
49
+ def create(name, options = {})
50
+
51
+ options = {
52
+ :name => name,
53
+ # rows
54
+ # schema
55
+ # relations
56
+ }.merge(options)
57
+
58
+ res = @api.request(
59
+ :expects => 200,
60
+ :method => :post,
61
+ :path => "/relations",
62
+ :body => options.to_json
63
+ )
64
+
65
+ res.body
66
+
67
+ end
68
+
69
+
70
+
71
+
72
+
73
+
74
+ # POST /datasets/1/append
75
+ def append(id, options = {})
76
+ opts = {:name => id}
77
+ file = options[:file] if options[:file]
78
+ if(file)
79
+ opts[:size] = File.size(file)
80
+ options.delete(:file)
81
+ end
82
+ options = opts.merge(options)
83
+
84
+ res = @api.request(
85
+ :expects => 200,
86
+ :method => :post,
87
+ :path => "/relations/#{id}/append",
88
+ :body => options.to_json
89
+ )
90
+
91
+ hash = res.body
92
+ if(hash['uri'])
93
+ uri = URI(hash['uri'])
94
+ response = nil
95
+ try_again = 1
96
+ while(try_again)
97
+ Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
98
+ request = Net::HTTP::Put.new(uri.request_uri)
99
+ request.body_stream = Zillabyte::Common::Tar.tar(file, [])
100
+ request['Content-Length'] = request.body_stream.size
101
+ request['Content-Type'] = ''
102
+ response = http.request(request)
103
+ if response.code.to_i >= 300
104
+ try_again = 1
105
+ break
106
+ end
107
+ try_again = nil
108
+ end
109
+ end
110
+ hash[:appended] = opts[:size]
111
+ hash.delete('uri')
112
+ res = @api.request(
113
+ :expects => 200,
114
+ :method => :post,
115
+ :path => "/relations/#{id}/store",
116
+ :body => options.to_json
117
+ )
118
+ end
119
+ hash
120
+
121
+ end
122
+
123
+
124
+
125
+
126
+ end
@@ -0,0 +1,239 @@
1
+ require 'net/http'
2
+ require 'mkfifo'
3
+ require 'zillabyte/cli/config'
4
+
5
+ class Zillabyte::API::Flows < Zillabyte::API::Base
6
+
7
+
8
+ # GET /flows
9
+ def list(options = {})
10
+
11
+ options = {
12
+ # TODO
13
+ }.merge(options)
14
+
15
+ res = @api.request(
16
+ :expects => 200,
17
+ :method => :get,
18
+ :path => "/flows"
19
+ )
20
+
21
+ res.body
22
+
23
+ end
24
+
25
+
26
+
27
+
28
+ # GET /flows/id
29
+ def get(id, options = {})
30
+
31
+ options = {
32
+ # TODO
33
+ }.merge(options)
34
+
35
+ res = @api.request(
36
+ :expects => 200,
37
+ :method => :get,
38
+ :path => "/flows/#{id}",
39
+ :body => options.to_json
40
+ )
41
+
42
+ res.body
43
+
44
+ end
45
+
46
+
47
+
48
+
49
+ # GET /flows/id/kill
50
+ def kill(id, options = {})
51
+
52
+ options = {
53
+ # TODO
54
+ }.merge(options)
55
+
56
+ res = @api.request(
57
+ :expects => 200,
58
+ :method => :post,
59
+ :path => "/flows/#{id}/kill",
60
+ :body => options.to_json
61
+ )
62
+
63
+ res.body
64
+
65
+ end
66
+
67
+
68
+
69
+
70
+
71
+
72
+
73
+
74
+ # GET /flows/id
75
+ def pull_to_directory(id, dir, progress = nil, options = {})
76
+
77
+ # Get the resource. note query params
78
+ progress.display "downloading ##{id}" if progress
79
+ res = @api.request(
80
+ :expects => 200,
81
+ :method => :get,
82
+ :path => "/flows/#{id}/download"
83
+ #:path => "/flows/#{id}?indirect_url=1"
84
+ #:path => "/flows/#{id}?tar=1"
85
+ )
86
+
87
+ hash = res.body
88
+ unless hash['status'] == 'error'
89
+ if(hash['tar'])
90
+ progress.display "unpacking to #{dir}" if progress
91
+ tar = StringIO.new(Base64.decode64(hash['tar']))
92
+ hash.delete('tar')
93
+ Zillabyte::Common::Tar.untar(tar, dir)
94
+ #If you get an uri instead of the tar, then download the file directly from s3
95
+ elsif(hash['uri'])
96
+ progress.display "downloading ##{id} to #{dir}" if progress
97
+ uri = URI(hash['uri'])
98
+ try_again = 1
99
+ while(try_again)
100
+ Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
101
+ request = Net::HTTP::Get.new(uri.request_uri)
102
+ response = http.request(request)
103
+ if response.code.to_i >= 300
104
+ try_again = 1
105
+ break
106
+ end
107
+ tar = StringIO.new(response.body)
108
+ Zillabyte::Common::Tar.untar(tar, dir)
109
+ try_again = nil
110
+ end
111
+ end
112
+ hash.delete('uri')
113
+ end
114
+ end
115
+
116
+ hash
117
+
118
+ end
119
+
120
+
121
+
122
+ # POST /flows
123
+ def push_directory(dir, progress = nil, options = {})
124
+
125
+ # Get the meta info
126
+ options[:local_flag] = 1
127
+ hash = Zillabyte::API::Flows.get_rich_meta_info_from_script(dir, progress, options)
128
+ if hash.nil?
129
+ error "unable to extract flow meta information"
130
+ end
131
+
132
+ # Tar up everything...
133
+ hash['ignore_files'] ||= []
134
+ hash['ignore_files'] << "info_to_ruby.in"
135
+ hash['ignore_files'] << "vEnv"
136
+
137
+ top_dir = hash['top_dir'] || "."
138
+ ignore_files = hash['ignore_files'] || []
139
+ progress.display("packaging directory... ", false) if progress
140
+ tar = Zillabyte::Common::Tar.tar(top_dir, ignore_files)
141
+ progress.display("done") if progress
142
+
143
+ hash.delete('pwd')
144
+
145
+ options = {
146
+ :name => hash['name'],
147
+ :meta => hash,
148
+ # :tar => Base64.encode64(tar.read)
149
+ }.merge(options)
150
+
151
+ progress.display("uploading #{tar.size} bytes... ", false) if progress
152
+ res = @api.request(
153
+ :expects => 200,
154
+ :method => :post,
155
+ :path => "/flows",
156
+ :body => options.to_json
157
+ )
158
+
159
+ if(res.body['uri'])
160
+ uri = URI(res.body['uri'])
161
+ try_again = 1
162
+ while(try_again)
163
+ Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
164
+ request = Net::HTTP::Put.new(uri.request_uri)
165
+ request.body_stream = tar
166
+ request['Content-Length'] = request.body_stream.size
167
+ request['Content-Type'] = ''
168
+ response = http.request(request)
169
+ if response.code.to_i >= 300
170
+ try_again = 1
171
+ break
172
+ end
173
+ try_again = nil
174
+ end
175
+ end
176
+ res.body.delete('uri')
177
+ end
178
+ progress.display("done")
179
+ res.body
180
+
181
+ end
182
+
183
+ ####################################################IMPORTANT####################################################
184
+ # #
185
+ # get_rich_meta_info_from_script only works with zillabyte flows:push now! The pipe "info_to_ruby.in" is #
186
+ # hardcoded as the meta info passing pipe, so if 2 processes are trying to access it simultaneously there might #
187
+ # be problems since it gets created/destroyed within this script (attempting to create a fifo that already #
188
+ # exists or deleting a fifo that still has information in it may occur). #
189
+ # #
190
+ ####################################################IMPORTANT####################################################
191
+ def self.get_rich_meta_info_from_script(dir, progress = nil, options = {})
192
+ hash = Zillabyte::CLI::Config.get_config_info(dir, progress, options)
193
+ if hash.nil?
194
+ return {"status" => "error", "error" => "invalid_directory", "error_message" => "The specified directory (#{dir}) does not appear to contain a valid Zillabyte configuration file."}
195
+ end
196
+
197
+ full_script = File.join(dir, hash['script'])
198
+ command = nil
199
+
200
+ info_file = SecureRandom.uuid
201
+ arg = "--info --file #{info_file}"
202
+ stderr = ""
203
+ stderr = " 2> /dev/null" unless options[:test]
204
+
205
+ case hash["language"]
206
+ when "ruby"
207
+ command = "cd \"#{dir}\"; unset BUNDLE_GEMFILE; ZILLABYTE_HARNESS=1 bundle exec ruby \"#{full_script}\" #{arg} #{stderr}"
208
+ command = "cd \"#{dir}\"; unset BUNDLE_GEMFILE; ZILLABYTE_HARNESS=1 bundle exec ruby \"#{full_script}\" #{arg} #{stderr}"
209
+ when "python"
210
+ if(File.directory?("#{dir}/vEnv"))
211
+ command = "cd \"#{dir}\"; PYTHONPATH=~/zb1/multilang/python/Zillabyte #{dir}/vEnv/bin/python \"#{full_script}\" #{arg} #{stderr}"
212
+ else
213
+ command = "cd \"#{dir}\"; PYTHONPATH=~/zb1/multilang/python/Zillabyte python \"#{full_script}\" #{arg} 2> /dev/null"
214
+ end
215
+ when "js"
216
+ # command = "#{Zillabyte::API::CASPERJS_BIN} #{Zillabyte::API::API_CLIENT_JS} \"#{full_script}\" --info"
217
+ command = "cd \"#{dir}\"; NODE_PATH=~/zb1/multilang/js #{Zillabyte::API::NODEJS_BIN} \"#{full_script}\" #{arg} #{stderr}"
218
+ else
219
+ progress.error "unsupported language: #{hash["language"]}" if progress
220
+ return nil
221
+ end
222
+
223
+ results = Zillabyte::Command::Flows.get_info(command, info_file, options)
224
+
225
+ begin
226
+ meta = JSON.parse(results.split("\n").first.strip) # Throws error if invalid json
227
+ rescue Exception => e
228
+ progress.error "the underlying flow did not return a valid result. command: #{command} error: #{e.message}" if progress
229
+ exit
230
+ end
231
+
232
+
233
+ # Merge with the new info
234
+ return hash.merge(meta)
235
+
236
+ end
237
+
238
+
239
+ end
@@ -0,0 +1,4 @@
1
+ module Zillabyte
2
+ module Lock
3
+ end
4
+ end
@@ -0,0 +1,32 @@
1
+ require 'net/http'
2
+ require 'open-uri'
3
+
4
+ class Zillabyte::API::Logs < Zillabyte::API::Base
5
+
6
+
7
+ # GET /flows/ID/logs
8
+ def get(flow_id, operation_id, options = {})
9
+
10
+ options = {
11
+ }.merge(options)
12
+
13
+ since = ""
14
+ if options[:since]
15
+ since = "?since=#{URI::encode(options[:since])}"
16
+ end
17
+
18
+ res = @api.request(
19
+ :expects => 200,
20
+ :method => :get,
21
+ :path => "/flows/#{flow_id}/logs/#{operation_id}#{since}"
22
+ )
23
+
24
+ res.body
25
+
26
+ end
27
+
28
+
29
+
30
+
31
+
32
+ end
@@ -0,0 +1,48 @@
1
+ class Zillabyte::API::Metrics < Zillabyte::API::Base
2
+
3
+
4
+ # GET /metrics
5
+ def list(options = {})
6
+
7
+ options = {
8
+ # TODO
9
+ }.merge(options)
10
+
11
+ res = @api.request(
12
+ :expects => 200,
13
+ :method => :get,
14
+ :path => "/metrics"
15
+ )
16
+
17
+ res.body
18
+
19
+ end
20
+
21
+
22
+
23
+ # GET /metrics
24
+ def show(id, options = {}, block = nil)
25
+
26
+
27
+ if block
28
+ res = @api.request(
29
+ :expects => 200,
30
+ :method => :get,
31
+ :path => "/metrics/#{id}?#{options.to_query}",
32
+ :response_block => block
33
+ )
34
+ else
35
+ res = @api.request(
36
+ :expects => 200,
37
+ :method => :get,
38
+ :path => "/metrics/#{id}?#{options.to_query}",
39
+ )
40
+
41
+ end
42
+
43
+ res.body
44
+
45
+ end
46
+
47
+
48
+ end
@@ -0,0 +1,58 @@
1
+ class Zillabyte::API::Queries < Zillabyte::API::Base
2
+
3
+
4
+ # GET /sxp
5
+ def sxp(expression, options = {})
6
+
7
+ options = {
8
+ 'sxp' => expression
9
+ }.merge(options)
10
+
11
+ res = request(
12
+ :expects => 200,
13
+ :method => :post,
14
+ :path => "/query_sxp",
15
+ :body => options.to_json
16
+ )
17
+
18
+ res.body
19
+
20
+ end
21
+
22
+
23
+
24
+ # GET /sql
25
+ def sql(expression, options = {})
26
+
27
+ options = {
28
+ 'sql' => expression
29
+ }.merge(options)
30
+
31
+ res = request(
32
+ :expects => 200,
33
+ :method => :post,
34
+ :path => "/query_sql",
35
+ :body => options.to_json
36
+ )
37
+
38
+ res.body
39
+
40
+ end
41
+
42
+
43
+
44
+ def agnostic(expression, options = {})
45
+ case expression
46
+ when Array
47
+ return sxp(expression, options)
48
+ when String
49
+ return sql(expression, options)
50
+ else
51
+ throw "unknown expression type: #{expression}"
52
+ end
53
+ end
54
+
55
+
56
+
57
+
58
+ end
@@ -0,0 +1,24 @@
1
+
2
+ class Zillabyte::API::SemanticTags < Zillabyte::API::Base
3
+
4
+
5
+ # GET /semantic_tags
6
+ def list(options = {})
7
+
8
+ options = {
9
+ # TODO
10
+ }.merge(options)
11
+
12
+ res = @api.request(
13
+ :expects => 200,
14
+ :method => :get,
15
+ :path => "/semantic_tags"
16
+ )
17
+
18
+ res.body
19
+
20
+ end
21
+
22
+
23
+
24
+ end
@@ -0,0 +1,8 @@
1
+ module Zillabyte
2
+ class API
3
+ # PY_VIRTUAL_ENV_DIR = "/tmp/vEnv"
4
+ CASPERJS_BIN = "/usr/local/bin/casperjs"
5
+ API_CLIENT_JS = File.join(ENV['HOME'], "zb1/api.client.js/api.coffee")
6
+ NODEJS_BIN = "/usr/local/bin/node"
7
+ end
8
+ end
@@ -0,0 +1,28 @@
1
+ class Zillabyte::API::Sources < Zillabyte::API::Base
2
+
3
+
4
+ # GET /sources
5
+ def list(options = {})
6
+
7
+ options = {
8
+ # TODO
9
+ }.merge(options)
10
+
11
+ res = @api.request(
12
+ :expects => 200,
13
+ :method => :get,
14
+ :path => "/sources"
15
+ )
16
+
17
+ res.body
18
+
19
+ end
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+ end