ferris-bueller 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bd02010a5690c0772a134273d476c24e292d8b15
4
+ data.tar.gz: b0e2d65aaa1b7bd1546c9681c322b4429e4a0f65
5
+ SHA512:
6
+ metadata.gz: 41280791c72f6d5b32861eea7d9c588e533b76dce2485925f498b8a88e5a33dc89f3e959dedc46897350cf215924ce6ed7357598f220d66e8abd355dc8f61391
7
+ data.tar.gz: ccdbaefb94e9c4ac5418857913c8db8c862c020f6e22c0c588226bf862313b8285fd565f9e7e4a971739b9f47fa2a11b78835eedc62b8c6d004c8c42877e142e
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2015 Sean Clemmer and Blue Jeans Network
2
+
3
+ Permission to use, copy, modify, and/or distribute this software for any
4
+ purpose with or without fee is hereby granted, provided that the above
5
+ copyright notice and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
8
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
10
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
12
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13
+ PERFORMANCE OF THIS SOFTWARE.
data/Readme.md ADDED
@@ -0,0 +1,3 @@
1
+ # Ferris
2
+
3
+ TODO
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.0
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'ferris-bueller'
3
+ FerrisBueller::Main.start
@@ -0,0 +1,37 @@
1
+ module FerrisBueller
2
+ module Constants
3
+ RETRY_DELAY = 5
4
+
5
+ RESOLVED_TRANSITIONS = %w[ 51 ]
6
+
7
+ RESOLVED_STATE = /resolve/i
8
+
9
+ CLOSED_TRANSITIONS = %w[ 61 71 ]
10
+
11
+ CLOSED_STATE = /close/i
12
+
13
+ SEVERITIES = {
14
+ 1 => '10480',
15
+ 2 => '10481',
16
+ 3 => '10482',
17
+ 4 => '10483',
18
+ 5 => '10484'
19
+ }
20
+
21
+ SHOW_FIELDS = {
22
+ 'summary' => 'Summary',
23
+ 'description' => 'Description',
24
+ 'customfield_11250' => 'Severity',
25
+ 'customfield_11251' => 'Impact Started',
26
+ 'customfield_11252' => 'Impact Ended',
27
+ 'customfield_11253' => 'Reported By',
28
+ 'customfield_11254' => 'Services Affected',
29
+ 'customfield_11255' => 'Cause',
30
+ 'status' => 'Status',
31
+ 'created' => 'Created',
32
+ 'updated' => 'Updated'
33
+ }
34
+
35
+ SEVERITY_FIELD = SHOW_FIELDS.key('Severity')
36
+ end
37
+ end
@@ -0,0 +1,170 @@
1
+ require 'thin/logging'
2
+ require 'queryparams'
3
+
4
+ require_relative 'constants'
5
+ require_relative 'web'
6
+
7
+
8
+ module FerrisBueller
9
+ module Helpers
10
+ include Constants
11
+
12
+
13
+ def store ; @store end
14
+
15
+
16
+ def start_your_day_off
17
+ Web.set :environment, options.environment
18
+ Web.set :port, options.port
19
+ Web.set :bind, options.bind
20
+ Web.set :store, @store
21
+ Web.set :logger, log
22
+
23
+ if log.level >= ::Logger::DEBUG
24
+ Web.set :raise_errors, true
25
+ Web.set :dump_errors, true
26
+ Web.set :show_exceptions, true
27
+ Web.set :logging, ::Logger::DEBUG
28
+ end
29
+
30
+ Thin::Logging.logger = log
31
+
32
+ Web.run!
33
+ end
34
+
35
+
36
+ def go_refresh_jira_users
37
+ Thread.new do
38
+ loop do
39
+ refresh_jira_users
40
+ sleep options.user_refresh
41
+ end
42
+ end
43
+ end
44
+
45
+
46
+ def go_refresh_jira_members
47
+ Thread.new do
48
+ loop do
49
+ refresh_jira_members
50
+ sleep options.member_refresh
51
+ end
52
+ end
53
+ end
54
+
55
+
56
+ def go_refresh_jira_incidents
57
+ Thread.new do
58
+ loop do
59
+ refresh_jira_incidents
60
+ sleep options.incident_refresh
61
+ end
62
+ end
63
+ end
64
+
65
+
66
+ def refresh_jira_users
67
+ data = jira_request 'user/assignable/search', \
68
+ project: options.jira_project,
69
+ startAt: 0,
70
+ maxResults: 1_000_000
71
+
72
+ users = data.inject({}) do |h, user|
73
+ h[user['name']] = {
74
+ key: user['key'],
75
+ nick: user['name'],
76
+ name: user['displayName'],
77
+ email: user['emailAddress']
78
+ } ; h
79
+ end
80
+
81
+ store['jira_users'] = users
82
+
83
+ rescue StandardError => e
84
+ log.error \
85
+ error: 'could not refresh users',
86
+ event: 'exception',
87
+ exception: e.inspect,
88
+ class: e.class,
89
+ message: e.message,
90
+ backtrace: e.backtrace,
91
+ remediation: 'pausing breifly before retrying'
92
+ sleep RETRY_DELAY
93
+ retry
94
+ end
95
+
96
+
97
+ def refresh_jira_members
98
+ data = jira_request 'group', \
99
+ groupname: options.jira_group,
100
+ expand: 'users'
101
+
102
+ user_names = data['users']['items'].map { |u| u['displayName'] }
103
+ store['jira_members'] = user_names
104
+
105
+ rescue StandardError => e
106
+ log.error \
107
+ error: 'could not refresh members',
108
+ event: 'exception',
109
+ exception: e.inspect,
110
+ class: e.class,
111
+ message: e.message,
112
+ backtrace: e.backtrace,
113
+ remediation: 'pausing breifly before retrying'
114
+ sleep RETRY_DELAY
115
+ retry
116
+ end
117
+
118
+
119
+ def refresh_jira_incidents
120
+ data = jira_request 'search', \
121
+ jql: "project = #{options.jira_project} ORDER BY created ASC, priority DESC",
122
+ fields: SHOW_FIELDS.keys.join(','),
123
+ startAt: 0,
124
+ maxResults: 1_000_000
125
+
126
+ store['jira_incidents'] = data['issues'].map do |i|
127
+ i['num'] = i['key'].split('-', 2).last ; i
128
+ end
129
+
130
+ rescue StandardError => e
131
+ log.error \
132
+ error: 'could not refresh incidents',
133
+ event: 'exception',
134
+ exception: e.inspect,
135
+ class: e.class,
136
+ message: e.message,
137
+ backtrace: e.backtrace,
138
+ remediation: 'pausing breifly before retrying'
139
+ sleep RETRY_DELAY
140
+ retry
141
+ end
142
+
143
+
144
+ def jira_request path, params
145
+ api_url = File.join options.jira_url, 'rest/api/latest', path
146
+ log.trace \
147
+ event: 'jira request',
148
+ path: path,
149
+ params: params,
150
+ api_url: api_url
151
+ encoded_params = QueryParams.encode params
152
+ uri = URI(api_url + '?' + encoded_params)
153
+ http = Net::HTTP.new uri.host, uri.port
154
+ req = Net::HTTP::Get.new uri
155
+ req.use_ssl if uri.scheme == 'https'
156
+ req.basic_auth options.jira_user, options.jira_pass
157
+ req['Content-Type'] = 'application/json'
158
+ req['Accept'] = 'application/json'
159
+ resp = http.request req
160
+ log.debug \
161
+ event: 'jira request responded',
162
+ path: path,
163
+ params: params,
164
+ api_url: api_url,
165
+ response: resp
166
+ JSON.parse resp.body
167
+ end
168
+
169
+ end
170
+ end
@@ -0,0 +1,113 @@
1
+ require_relative 'mjolnir'
2
+ require_relative 'metadata'
3
+ require_relative 'helpers'
4
+
5
+
6
+ module FerrisBueller
7
+ class Main < Mjolnir
8
+ include Helpers
9
+
10
+
11
+ desc 'version', 'Show application version'
12
+ def version
13
+ puts VERSION
14
+ end
15
+
16
+
17
+ desc 'art', 'Show application art'
18
+ def art
19
+ puts "\n%s\n" % ART
20
+ end
21
+
22
+
23
+ desc 'start', 'Start Bender HipChat bot and Web server'
24
+ option :token, \
25
+ type: :string,
26
+ aliases: %w[ -t ],
27
+ desc: 'Set Slack verificatino token',
28
+ required: true,
29
+ default: ENV['FERRIS_BUELLER_TOKEN']
30
+ option :database, \
31
+ type: :string,
32
+ aliases: %w[ -d ],
33
+ desc: 'Set path to application database',
34
+ required: true,
35
+ default: ENV['FERRIS_BUELLER_DATABASE']
36
+ option :jira_user, \
37
+ type: :string,
38
+ aliases: %w[ -u ],
39
+ desc: 'Set JIRA username',
40
+ required: true,
41
+ default: ENV['FERRIS_BUELLER_JIRA_USER']
42
+ option :jira_pass, \
43
+ type: :string,
44
+ aliases: %w[ -p ],
45
+ desc: 'Set JIRA password',
46
+ required: true,
47
+ default: ENV['FERRIS_BUELLER_JIRA_PASS']
48
+ option :jira_url, \
49
+ type: :string,
50
+ aliases: %w[ -j ],
51
+ desc: 'Set JIRA base URL',
52
+ required: true,
53
+ default: ENV['FERRIS_BUELLER_JIRA_URL']
54
+ option :jira_project, \
55
+ type: :string,
56
+ aliases: %w[ -o ],
57
+ desc: 'Set JIRA project',
58
+ required: true,
59
+ default: ENV['FERRIS_BUELLER_JIRA_PROJECT']
60
+ option :jira_group, \
61
+ type: :string,
62
+ aliases: %w[ -g ],
63
+ desc: 'Set JIRA group for write mode',
64
+ required: true,
65
+ default: ENV['FERRIS_BUELLER_JIRA_GROUP']
66
+ option :jira_type, \
67
+ type: :string,
68
+ aliases: %w[ -e ],
69
+ desc: 'Set JIRA issue type',
70
+ required: true,
71
+ default: ENV['FERRIS_BUELLER_JIRA_TYPE']
72
+ option :user_refresh, \
73
+ type: :numeric,
74
+ aliases: %w[ -r ],
75
+ desc: 'Set JIRA user refresh rate',
76
+ default: (ENV['FERRIS_BUELLER_USER_REFRESH'] || 90)
77
+ option :incident_refresh, \
78
+ type: :numeric,
79
+ aliases: %w[ -i ],
80
+ desc: 'Set JIRA incident refresh rate',
81
+ default: (ENV['FERRIS_BUELLER_INCIDENT_REFRESH'] || 5)
82
+ option :member_refresh, \
83
+ type: :numeric,
84
+ aliases: %w[ -g ],
85
+ desc: 'Set JIRA group membership refresh rate',
86
+ default: (ENV['FERRIS_BUELLER_MEMBER_REFRESH'] || 60)
87
+ option :environment, \
88
+ type: :string,
89
+ aliases: %w[ -m ],
90
+ desc: 'Set environment for Web app',
91
+ default: (ENV['FERRIS_BUELLER_ENVIRONMENT'] || 'development')
92
+ option :port, \
93
+ type: :numeric,
94
+ aliases: %w[ -n ],
95
+ desc: 'Set port for Web app',
96
+ default: (ENV['FERRIS_BUELLER_PORT'] || 8080)
97
+ option :bind, \
98
+ type: :string,
99
+ aliases: %w[ -b ],
100
+ desc: 'Set bind for Web app',
101
+ default: (ENV['FERRIS_BUELLER_BIND'] || '0.0.0.0')
102
+ include_common_options
103
+ def start
104
+ log.info 'starting...'
105
+ @store = {}
106
+ go_refresh_jira_users
107
+ go_refresh_jira_members
108
+ go_refresh_jira_incidents
109
+ start_your_day_off
110
+ end
111
+
112
+ end
113
+ end
@@ -0,0 +1,43 @@
1
+ module FerrisBueller
2
+
3
+ # We use a VERSION file to tie into our build pipeline
4
+ VERSION = File.read(File.join(File.dirname(__FILE__), '..', '..', 'VERSION')).strip
5
+
6
+ # We don't really do all that much, be humble
7
+ SUMMARY = 'Successor to Bender, based on Ferris'
8
+
9
+ # Like the MIT license, but even simpler
10
+ LICENSE = 'ISC'
11
+
12
+ # Where you should look first
13
+ HOMEPAGE = 'https://github.com/sczizzo/ferris-bueller'
14
+
15
+ # Your benevolent dictator for life
16
+ AUTHOR = 'Sean Clemmer'
17
+
18
+ # Turn here to strangle your dictator
19
+ EMAIL = 'sclemmer@bluejeans.com'
20
+
21
+ # Bundled extensions
22
+ TRAVELING_RUBY_BUCKET = 'http://d6r77u77i8pq3.cloudfront.net'
23
+ TRAVELING_RUBY_VERSION = '20150715-2.2.2'
24
+ EM_VERSION = '1.0.4'
25
+ FFI_VERSION = '1.9.6'
26
+ JSON_VERSION = '1.8.2'
27
+ THIN_VERSION = '1.6.3'
28
+
29
+ # Every project deserves its own ASCII art
30
+ ART = <<-'EOART' % VERSION
31
+
32
+
33
+
34
+ .--. . .
35
+ | ) | |
36
+ |--: .-. . . | | .-. .--.
37
+ | )(.-' | | | |(.-' |
38
+ '--' `--'`--`-`-`-`--''
39
+
40
+
41
+
42
+ EOART
43
+ end
@@ -0,0 +1,57 @@
1
+ require 'thor'
2
+ require 'slog'
3
+
4
+
5
+ module FerrisBueller
6
+
7
+ # Thor's hammer! Like Thor with better logging
8
+ class Mjolnir < Thor
9
+
10
+ # Common options for Thor commands
11
+ COMMON_OPTIONS = {
12
+ log: {
13
+ type: :string,
14
+ aliases: %w[ -l ],
15
+ desc: 'Log to file instead of STDOUT',
16
+ default: ENV['FERRIS_BUELLER_LOG'] || nil
17
+ },
18
+ debug: {
19
+ type: :boolean,
20
+ aliases: %w[ -v ],
21
+ desc: 'Enable DEBUG-level logging',
22
+ default: ENV['FERRIS_BUELLER_DEBUG'] || false
23
+ },
24
+ trace: {
25
+ type: :boolean,
26
+ aliases: %w[ -z ],
27
+ desc: 'Enable TRACE-level logging (overrides DEBUG)',
28
+ default: ENV['FERRIS_BUELLER_TRACE'] || false
29
+ }
30
+ }
31
+
32
+ # Decorate Thor commands with the options above
33
+ def self.include_common_options
34
+ COMMON_OPTIONS.each do |name, spec|
35
+ option name, spec
36
+ end
37
+ end
38
+
39
+
40
+ no_commands do
41
+
42
+ # Construct a Logger given the command-line options
43
+ def log
44
+ return @logger if defined? @logger
45
+ device = options.log || $stdout
46
+ colorize, prettify = false, false
47
+ colorize, prettify = true, true if device.tty? rescue false
48
+ @logger = Slog.new \
49
+ out: device, colorize: colorize, prettify: prettify
50
+ @logger.level = :debug if options.debug?
51
+ @logger.level = :trace if options.trace?
52
+ @logger
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,47 @@
1
+ require 'json'
2
+
3
+ require 'sinatra/base'
4
+
5
+ require_relative 'metadata'
6
+
7
+ Thread.abort_on_exception = true
8
+
9
+
10
+ module FerrisBueller
11
+ class Web < Sinatra::Application
12
+ def log ; settings.logger end
13
+ def store ; settings.store end
14
+
15
+
16
+ get '/' do
17
+ log.info event: 'get /'
18
+ content_type :text
19
+ 'Sup.'
20
+ end
21
+
22
+
23
+ get '/v' do
24
+ log.info event: 'get /v'
25
+ content_type :text
26
+ VERSION
27
+ end
28
+
29
+
30
+ get '/s' do
31
+ log.info event: 'get /s'
32
+ content_type :json
33
+ store.to_json
34
+ end
35
+
36
+
37
+ post '/' do
38
+ request.body.rewind
39
+ body = request.body.read
40
+ log.info event: 'post /', params: params, body: body
41
+ # TODO
42
+ content_type :json
43
+ { params: params, body: body }.to_json
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,2 @@
1
+ require_relative 'ferris-bueller/metadata'
2
+ require_relative 'ferris-bueller/main'
metadata ADDED
@@ -0,0 +1,181 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ferris-bueller
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Sean Clemmer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-01-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: slog
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.19'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.19'
41
+ - !ruby/object:Gem::Dependency
42
+ name: queryparams
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.0.3
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.0.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: fuzzy-string-match
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.9.7
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.9.7
69
+ - !ruby/object:Gem::Dependency
70
+ name: sinatra
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.4'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.4'
83
+ - !ruby/object:Gem::Dependency
84
+ name: eventmachine
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '='
88
+ - !ruby/object:Gem::Version
89
+ version: 1.0.4
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '='
95
+ - !ruby/object:Gem::Version
96
+ version: 1.0.4
97
+ - !ruby/object:Gem::Dependency
98
+ name: thin
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '='
102
+ - !ruby/object:Gem::Version
103
+ version: 1.6.3
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '='
109
+ - !ruby/object:Gem::Version
110
+ version: 1.6.3
111
+ - !ruby/object:Gem::Dependency
112
+ name: json
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '='
116
+ - !ruby/object:Gem::Version
117
+ version: 1.8.2
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '='
123
+ - !ruby/object:Gem::Version
124
+ version: 1.8.2
125
+ - !ruby/object:Gem::Dependency
126
+ name: ffi
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '='
130
+ - !ruby/object:Gem::Version
131
+ version: 1.9.6
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '='
137
+ - !ruby/object:Gem::Version
138
+ version: 1.9.6
139
+ description: Successor to Bender, based on Ferris.
140
+ email: sclemmer@bluejeans.com
141
+ executables: []
142
+ extensions: []
143
+ extra_rdoc_files: []
144
+ files:
145
+ - LICENSE
146
+ - Readme.md
147
+ - VERSION
148
+ - bin/ferris-bueller
149
+ - lib/ferris-bueller.rb
150
+ - lib/ferris-bueller/constants.rb
151
+ - lib/ferris-bueller/helpers.rb
152
+ - lib/ferris-bueller/main.rb
153
+ - lib/ferris-bueller/metadata.rb
154
+ - lib/ferris-bueller/mjolnir.rb
155
+ - lib/ferris-bueller/web.rb
156
+ homepage: https://github.com/sczizzo/ferris-bueller
157
+ licenses:
158
+ - ISC
159
+ metadata: {}
160
+ post_install_message:
161
+ rdoc_options: []
162
+ require_paths:
163
+ - lib
164
+ required_ruby_version: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - ">="
167
+ - !ruby/object:Gem::Version
168
+ version: '0'
169
+ required_rubygems_version: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ requirements: []
175
+ rubyforge_project:
176
+ rubygems_version: 2.4.5.1
177
+ signing_key:
178
+ specification_version: 4
179
+ summary: Successor to Bender, based on Ferris
180
+ test_files: []
181
+ has_rdoc: