squab-client 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE.md ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2013 Square Inc.
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ Squab Client
2
+ =====
3
+
4
+ This is the Squab Client directory. Please see the root level directory for information on squab, using squab, and developing squab.
data/bin/squab-digest ADDED
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # A squab stream to e-mail script
4
+ #
5
+
6
+ require 'rubygems'
7
+ require 'optparse'
8
+ require 'ostruct'
9
+ require 'pp'
10
+ require 'net/smtp'
11
+
12
+ require 'squab-client'
13
+
14
+ options = OpenStruct.new
15
+ options.days = 1
16
+ options.sources = []
17
+ options.to = []
18
+ options.from = "squab-digest@example.com"
19
+ options.today = Time.now.strftime("%a, %b %d")
20
+
21
+ optparse = OptionParser.new do |opts|
22
+ opts.banner = "Usarge #{__FILE__} [options]"
23
+ opts.on('-d', '--days DAYS', "Number of days to digest") do |arg|
24
+ options.days = arg.to_i
25
+ end
26
+ opts.on('-e', '--email EMAIL', "Where to send the digest") do |arg|
27
+ options.to.push(arg)
28
+ end
29
+ opts.on('-s', '--source SOURCE', 'Specify a source to digest. Can be used multiple times') do |arg|
30
+ options.sources.push(arg)
31
+ end
32
+ opts.on('-a', '--api URL', "API URL for squab") do |arg|
33
+ options.api = arg
34
+ end
35
+ opts.on('-D', '--dry-run', "Don't send mail, output the message to stdout") do
36
+ options.dry = true
37
+ end
38
+ end
39
+
40
+ optparse.parse!
41
+
42
+ sc = if options.api
43
+ Squab::Client.new(:api => options.api)
44
+ else
45
+ Squab::Client.new()
46
+ end
47
+
48
+ if options.sources.empty?
49
+ $stderr.puts optparse
50
+ $stderr.puts "\n[ERROR] You must supply a source to digest (-s)"
51
+ exit 1
52
+ end
53
+
54
+ if options.to.empty?
55
+ $stderr.puts optparse
56
+ $stderr.puts "\n[ERROR] You must supply an email to send to (-e)"
57
+ exit 1
58
+ end
59
+
60
+ since = Time.now.to_i - (86400 * options.days.to_i)
61
+ message = <<-EOM.gsub(/^\s+/, '')
62
+ From: #{options.from}
63
+ To: #{options.to.join(',')}
64
+ Subject: Squab Digest Report for #{options.today}
65
+ EOM
66
+
67
+ message << "\n\n"
68
+
69
+ options.sources.each do |src|
70
+ search_params = { :source => src,
71
+ :from => since }
72
+
73
+ res = JSON.parse(sc.search(search_params))
74
+ message << "#{src} events from the last #{options.days} days\n\n"
75
+ res.each do |event|
76
+ message << sprintf("%-16s -- %s\n", event['uid'], event['value'])
77
+ end
78
+ message << "\n\n"
79
+ end
80
+
81
+ if options.dry
82
+ puts message
83
+ else
84
+ Net::SMTP.start('localhost', 25) do |smtp|
85
+ smtp.send_message message, options.from, options.to
86
+ end
87
+ end
data/bin/squawk ADDED
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'squab-client'
4
+ require 'optparse'
5
+
6
+ options = {}
7
+ options[:max_retry] = 3
8
+
9
+ optparse = OptionParser.new do |opts|
10
+ opts.banner = "Usage: #{__FILE__} [options] [message]"
11
+ opts.on('-a', '--api URL', 'Set the API url to use') do |arg|
12
+ options[:api] = arg
13
+ end
14
+ opts.on('-u', '--url URL', 'Set an explicit URL for your event') do |arg|
15
+ options[:url] = arg
16
+ end
17
+ opts.on('-U', '--user USER', 'Set an explicit user for your message') do |arg|
18
+ options[:user] = arg
19
+ end
20
+ opts.on('-S', '--source SOURCE', 'Set an explicit source for your message') do |arg|
21
+ options[:source] = arg
22
+ end
23
+ opts.on('-r', '--max-retry 3', "The maximum number of time to retry sending\n a message on failure (default: 3)") do |arg|
24
+ options[:max_retry] = arg
25
+ end
26
+ opts.on('--noverify', "Don't verify SSL. You probably shouldn't do this") do |arg|
27
+ options[:no_verify] = true
28
+ end
29
+ opts.on_tail("-h", "--help", "Show this message") do
30
+ puts opts
31
+ exit
32
+ end
33
+ end
34
+ optparse.parse!
35
+
36
+ sq = if (options[:api].nil?)
37
+ Squab::Client.new
38
+ else
39
+ Squab::Client.new(:api => options[:api])
40
+ end
41
+
42
+ if options[:user]
43
+ sq.uid = options[:user]
44
+ end
45
+
46
+ if options[:source]
47
+ sq.source = options[:source]
48
+ end
49
+
50
+ if (options[:no_verify])
51
+ sq.ssl_verify = false
52
+ end
53
+
54
+ if ARGV.length < 1
55
+ puts optparse
56
+ raise "You must provide a message to send to Squab"
57
+ exit
58
+ end
59
+ message = ARGV.join(' ')
60
+ puts message
61
+
62
+ urls = if options[:url].nil?
63
+ URI.extract(message)
64
+ else
65
+ [options[:url]]
66
+ end
67
+
68
+ try_count = 0
69
+ begin
70
+ if urls.length == 1
71
+ sq.send(message, urls.first)
72
+ elsif urls.length > 1
73
+ puts "Multiple URLs found, using #{urls.last}"
74
+ sq.send(message, urls.last)
75
+ else
76
+ sq.send(message)
77
+ end
78
+ rescue SendEventFailed
79
+ try_count += 1
80
+ if try_count > options[:max_retry]
81
+ $stderr.puts "Failed to send message to squab, the server is not responding correctly"
82
+ else
83
+ sleep 1
84
+ retry
85
+ end
86
+ end
@@ -0,0 +1,167 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require 'rubygems'
4
+ require 'json'
5
+ require 'yaml'
6
+ require 'etc'
7
+
8
+ class SendEventFailed < StandardError
9
+ end
10
+
11
+ module Squab
12
+ class Client
13
+ attr_accessor :source, :uid, :api_url, :ssl_verify
14
+ attr_accessor :api_version_prefix, :events_prefix
15
+ # Opts accepts
16
+ # api => The API URL to hit
17
+ # user => The user to report
18
+ # source => the source to report
19
+ def initialize(opts={})
20
+ @source = get_my_source(opts[:source])
21
+ @uid = get_my_user(opts[:user])
22
+ parse_config
23
+ @api_url = get_api(opts[:api] || @config[:api])
24
+ @ssl_verify = @config['ssl_verify'] || true
25
+ @api_version_prefix = @config['api_prefix'] || '/api/v1'
26
+ @events_prefix = [@api_version_prefix, 'events'].join('/')
27
+ end
28
+
29
+ def send(event, url=nil)
30
+ payload = {
31
+ "uid" => @uid,
32
+ "source" => @source,
33
+ "value" => event,
34
+ "url" => url,
35
+ }.to_json
36
+ header = {'Content-Type' => 'application/json'}
37
+ req = Net::HTTP::Post.new(@events_prefix, initheader = header)
38
+ req.body = payload
39
+ try_count = 1
40
+ begin
41
+ http = Net::HTTP.new(@api_url.host, @api_url.port)
42
+ http = setup_ssl(http) if @api_url.scheme == "https"
43
+ response = http.request(req)
44
+ rescue EOFError, Errno::ECONNREFUSED => e
45
+ raise SendEventFailed, "Could not reach the Squab server"
46
+ end
47
+ response
48
+ end
49
+
50
+ def list_sources
51
+ req = make_request('sources')
52
+ get_req(req)
53
+ end
54
+
55
+ def list_users
56
+ req = make_request('users')
57
+ get_req(req)
58
+ end
59
+
60
+ def list_urls
61
+ req = make_request('urls')
62
+ get_req(req)
63
+ end
64
+
65
+ def get(max=5, since=nil)
66
+ req = if since
67
+ make_event_request("since/#{since.to_i}")
68
+ else
69
+ make_event_request("limit/#{max}")
70
+ end
71
+ get_req(req)
72
+ end
73
+
74
+ def get_from_event(event_num)
75
+ req = make_event_request("starting/#{event_num}")
76
+ get_req(req)
77
+ end
78
+
79
+ def get_from_user(username)
80
+ req = make_event_request("user/#{username}")
81
+ get_req(req)
82
+ end
83
+
84
+ def get_from_source(source)
85
+ req = make_event_request("source/#{source}")
86
+ get_req(req)
87
+ end
88
+
89
+ def simple_search(search_val)
90
+ req = make_event_request("search/value/#{search_val}/limit/5")
91
+ get_req(req)
92
+ end
93
+
94
+ def search(search_params)
95
+ req = Net::HTTP::Post.new([ @events_prefix, 'search' ].join('/'))
96
+ req.body = JSON.dump(search_params)
97
+ get_req(req)
98
+ end
99
+
100
+ def get_api(url)
101
+ url ? URI.parse(url) : URI.parse(
102
+ "http://squab/"
103
+ )
104
+ end
105
+
106
+ def parse_config(file=nil)
107
+ # Default
108
+ config_file = file || '/etc/squab.yaml'
109
+ # Instance override
110
+ if File.exist?(config_file)
111
+ @config = YAML.load(File.open(config_file).read)
112
+ else
113
+ @config = {}
114
+ end
115
+ end
116
+
117
+ def get_my_source(source=nil)
118
+ source || File.basename($PROGRAM_NAME)
119
+ end
120
+
121
+ def get_my_user(username=nil)
122
+ username || Etc.getpwuid(Process.uid).name
123
+ end
124
+
125
+ private
126
+ def setup_ssl(http)
127
+ http.use_ssl = true
128
+ http.ca_file = OpenSSL::X509::DEFAULT_CERT_FILE
129
+ if @ssl_verify
130
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
131
+ else
132
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
133
+ $stderr.puts("Bypassing SSL verification, this should only happen "+
134
+ "during testing and development")
135
+ end
136
+ http.verify_depth = 5
137
+ http
138
+ end
139
+
140
+ def get_req(req, full_req=false)
141
+ http = Net::HTTP.new(@api_url.host, @api_url.port)
142
+ http = setup_ssl(http) if @api_url.scheme == "https"
143
+ resp = http.start { |h| h.request(req) }
144
+ if full_req
145
+ resp
146
+ else
147
+ resp.body
148
+ end
149
+ end
150
+
151
+ def make_event_request(to)
152
+ Net::HTTP::Get.new([ @events_prefix, to ].join('/'))
153
+ end
154
+
155
+ def make_request(to)
156
+ Net::HTTP::Get.new([ @api_version_prefix, to ].join('/'))
157
+ end
158
+ end
159
+ end
160
+
161
+ # Old name space, deprecated and should be removed eventually
162
+ class SquabClient < Squab::Client
163
+ def initialize(api_url=nil, source=nil, uid=nil)
164
+ super(:api => api_url, :source => source, :user => uid)
165
+ end
166
+ end
167
+
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: squab-client
3
+ version: !ruby/object:Gem::Version
4
+ hash: 7
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 4
9
+ - 0
10
+ version: 1.4.0
11
+ platform: ruby
12
+ authors:
13
+ - Grier Johnson
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2013-12-02 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: A client wrapper for the Squab API, also includes the CLI tool 'squawk' for quick message sending
23
+ email:
24
+ - github@squareup.com
25
+ executables:
26
+ - squawk
27
+ extensions: []
28
+
29
+ extra_rdoc_files:
30
+ - LICENSE.md
31
+ files:
32
+ - lib/squab-client.rb
33
+ - bin/squawk
34
+ - bin/squab-digest
35
+ - README.md
36
+ - LICENSE.md
37
+ has_rdoc: true
38
+ homepage: http://github.com/square/squab
39
+ licenses:
40
+ - Apache 2.0
41
+ post_install_message:
42
+ rdoc_options:
43
+ - --charset=UTF-8
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ hash: 3
52
+ segments:
53
+ - 0
54
+ version: "0"
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 23
61
+ segments:
62
+ - 1
63
+ - 3
64
+ - 6
65
+ version: 1.3.6
66
+ requirements: []
67
+
68
+ rubyforge_project:
69
+ rubygems_version: 1.6.2
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: Squab client
73
+ test_files: []
74
+