reactio 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 36606269241ac620fd46cec36ca3cf045e3b8908
4
+ data.tar.gz: 85c450f2de769ae85546cb9031cedd4671cb90a8
5
+ SHA512:
6
+ metadata.gz: fe2eadf9a63c611c44cf8bd41665f20b706684f1c69e2d84ffacd777556d189f247c4b9c90f292f40c7580ac76676a94626756c6f32382df2b9236a8898c6855
7
+ data.tar.gz: 8e3e02366a1851008c23b279145b2b47c3fadabe19a4d3aa615007fc11756f295609da0645d8232e555005277f9ffa74d70caa5b7650b09fdf354cde2a103ef8
@@ -0,0 +1,16 @@
1
+ /.bundle/
2
+ /vendor/
3
+ /.yardoc
4
+ /Gemfile.lock
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ .rspec
11
+ /tmp/
12
+ *.bundle
13
+ *.so
14
+ *.o
15
+ *.a
16
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in reactio.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Hajime Sueyoshi
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,118 @@
1
+ # Reactio
2
+
3
+ Reactio API Client for ruby
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'reactio'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install reactio
20
+
21
+ ## Usage
22
+
23
+ ### include Reactio
24
+
25
+ ```ruby
26
+ require 'reactio'
27
+ include Reactio
28
+
29
+ reactio.create_incident('An Incident')
30
+ ```
31
+
32
+ And run:
33
+
34
+ $ REACTIO_API_KEY='YOUR_API_KEY' REACTIO_ORGANIZATION='YOUR_ORGANIZATION' bundle exec ruby create_incident.rb
35
+
36
+ ### Or instantiate Reactio::Service
37
+
38
+ ```ruby
39
+ require 'reactio'
40
+
41
+ reactio = Reactio::Service.new(
42
+ api_key: 'YOUR_API_KEY',
43
+ organization: 'YOUR_ORGANIZATION'
44
+ )
45
+ reactio.create_incident('An Incident')
46
+ ```
47
+
48
+ ### Reactio incidents
49
+
50
+ - インシデント作成(およびトピック登録)
51
+
52
+ ```ruby
53
+ require 'reactio'
54
+ include Reactio
55
+
56
+ reactio.create_incident(
57
+ 'サイト閲覧不可',
58
+ status: 'open',
59
+ detection: 'internal',
60
+ cause: 'over-capacity',
61
+ cause_supplement: 'Webサーバがアクセス過多でダウン',
62
+ point: 'application',
63
+ scale: 'point',
64
+ pend_text: 'Webサーバの再起動を行う',
65
+ topics: %w(原因調査 復旧作業),
66
+ notification_text: '至急対応をお願いします',
67
+ notification_call: false
68
+ )
69
+ ```
70
+
71
+ - 一斉通知
72
+
73
+ ```ruby
74
+ require 'reactio'
75
+ include Reactio
76
+
77
+ reactio.notify_incident(
78
+ 123,
79
+ notification_text: '至急対応をお願いします',
80
+ notification_call: true
81
+ )
82
+ ```
83
+
84
+ - インシデント一覧取得
85
+
86
+ ```ruby
87
+ require 'reactio'
88
+ include Reactio
89
+
90
+ list = reactio.list_incidents(
91
+ from: Time.now - (60 * 60 * 24 * 7),
92
+ to: Time.now,
93
+ status: 'pend',
94
+ page: 1,
95
+ per_page: 50
96
+ )
97
+
98
+ p list.first
99
+ #=> {:id=>1, :name=>"サイト閲覧不可", :manager=>nil, :status=>"pend", :detection=>"msp", :cause=>"over-capacity", :cause_supplement=>"Webサーバがアクセス過多でダウン", :point=>"middleware", :scale=>"whole", :pend_text=>"Webサーバの再起動を行う", :close_text=>"Webサーバのスケールアウトを行う", :closed_by=>nil, :closed_at=>nil, :pended_by=>nil, :pended_at=>nil, :created_by=>0, :created_at=>1430208000, :updated_by=>0, :updated_at=>1430208000}
100
+ ```
101
+
102
+ - インシデント取得
103
+
104
+ ```ruby
105
+ require 'reactio'
106
+ include Reactio
107
+
108
+ p reactio.describe_incident(123)
109
+ #=> {:id=>123, :name=>"サイト閲覧不可", :manager=>nil, :status=>"open", :detection=>"msp", :cause=>"over-capacity", :cause_supplement=>"Webサーバがアクセス過多でダウン", :point=>"middleware", :scale=>"whole", :pend_text=>"Webサーバの再起動を行う", :close_text=>"Webサーバのスケールアウトを行う", :closed_by=>nil, :closed_at=>nil, :pended_by=>nil, :pended_at=>nil, :created_by=>0, :created_at=>1430208000, :updated_by=>0, :updated_at=>1430208000, :topics=>[{:id=>1, :name=>"原因調査", :status=>"open", :color=>"#5661aa", :closed_by=>nil, :closed_at=>nil, :created_by=>0, :created_at=>1430208000, :updated_by=>0, :updated_at=>1430208000}, {:id=>2, :name=>"復旧作業", :status=>"open", :color=>"#077f40", :closed_by=>nil, :closed_at=>nil, :created_by=>0, :created_at=>1430208000, :updated_by=>0, :updated_at=>1430208000}], :files=>[{:name=>"障害報告書", :path=>"https://demo.reactio.jp/data/reactio-mvp/files/incident/1/_bYMRLTxj75lcXCWN0iaAZud2CuGqFFL/Screen_Shot.png"}], :users=>[{:id=>1}, {:id=>2}]}
110
+ ```
111
+
112
+ ## Contributing
113
+
114
+ 1. Fork it ( https://github.com/[my-github-username]/reactio/fork )
115
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
116
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
117
+ 4. Push to the branch (`git push origin my-new-feature`)
118
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,29 @@
1
+ require 'reactio/version'
2
+ require 'reactio/errors'
3
+ require 'reactio/utils'
4
+ require 'reactio/service'
5
+
6
+ module Reactio
7
+
8
+ def self.included(base)
9
+ base.class_eval do
10
+ include InstanceMethods
11
+ end
12
+ end
13
+
14
+ module InstanceMethods
15
+
16
+ def reactio
17
+ @reactio ||= create_service
18
+ end
19
+
20
+ private
21
+
22
+ def create_service
23
+ Service.new(
24
+ api_key: ENV['REACTIO_API_KEY'],
25
+ organization: ENV['REACTIO_ORGANIZATION']
26
+ )
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,53 @@
1
+ require 'faraday'
2
+ require 'reactio/api_endpoint'
3
+ require 'reactio/faraday_engine'
4
+
5
+ module Reactio
6
+ class APIClient
7
+
8
+ class << self
9
+
10
+ def build(api_key, organization)
11
+ raise ArgumentError, 'api_key is required' unless api_key
12
+ raise ArgumentError, 'organization is required' unless organization
13
+ http_client = build_http_client(
14
+ api_key,
15
+ APIEndpoint.new(organization)
16
+ )
17
+ new(http_client)
18
+ end
19
+
20
+ def build_http_client(api_key, api_endpoint)
21
+ Faraday.new(url: api_endpoint.base_url) do |faraday|
22
+ faraday.use :reactio, api_key
23
+ faraday.request :url_encoded
24
+ faraday.adapter Faraday.default_adapter
25
+ end
26
+ end
27
+ end
28
+
29
+ def initialize(http_client)
30
+ @http = http_client
31
+ end
32
+
33
+ def request(method, path, env = {})
34
+ response = @http.send(method, path, env[:body])
35
+ handle_api_response(response)
36
+ end
37
+
38
+ private
39
+
40
+ def handle_api_response(res)
41
+ case res.status
42
+ when 200..299
43
+ res.body
44
+ when 401
45
+ raise Reactio::AuthenticationError, res.body.inspect
46
+ when 400..499
47
+ raise Reactio::BadRequest, res.body.inspect
48
+ when 500..599
49
+ raise Reactio::ServerError, res.body.inspect
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,23 @@
1
+ require 'uri'
2
+
3
+ module Reactio
4
+ class APIEndpoint
5
+ DOMAIN = 'reactio.jp'.freeze
6
+
7
+ attr_reader :organization
8
+
9
+ def initialize(organization)
10
+ @organization = organization
11
+ @base_url = URI::HTTPS.build(host: "#{organization}.#{DOMAIN}")
12
+ end
13
+
14
+ def base_url
15
+ @base_url.to_s
16
+ end
17
+
18
+ def ==(other)
19
+ other.instance_of?(self.class) &&
20
+ self.organization == other.organization
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ module Reactio
2
+ class BadRequest < StandardError; end
3
+ class AuthenticationError < StandardError; end
4
+ class ServerError < StandardError; end
5
+ end
@@ -0,0 +1,43 @@
1
+ require 'faraday'
2
+ require 'json'
3
+
4
+ module Reactio
5
+ class FaradayEngine < Faraday::Middleware
6
+ USER_AGENT = "Reactio ruby v#{VERSION}".freeze
7
+ MIME_TYPE = 'application/json'.freeze
8
+
9
+ def initialize(app, api_key)
10
+ super(app)
11
+ @api_key = api_key
12
+ end
13
+
14
+ def call(request_env)
15
+ set_request_header(request_env)
16
+ encode_body(request_env)
17
+ @app.call(request_env).on_complete do |response_env|
18
+ decode_body(response_env)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def set_request_header(env)
25
+ env[:request_headers].merge!(
26
+ 'Accept' => MIME_TYPE,
27
+ 'Content-Type' => MIME_TYPE,
28
+ 'X-Api-Key' => @api_key,
29
+ 'User-Agent' => USER_AGENT
30
+ )
31
+ end
32
+
33
+ def encode_body(env)
34
+ env[:body] = JSON.dump(env[:body])
35
+ end
36
+
37
+ def decode_body(env)
38
+ env[:body] = JSON.parse(env[:body], symbolize_names: true)
39
+ end
40
+ end
41
+ end
42
+
43
+ Faraday::Middleware.register_middleware reactio: Reactio::FaradayEngine
@@ -0,0 +1,46 @@
1
+ require 'reactio/api_client'
2
+
3
+ module Reactio
4
+ class Service
5
+ include Utils
6
+
7
+ def initialize(options)
8
+ @api = APIClient.build(
9
+ options[:api_key],
10
+ options[:organization]
11
+ )
12
+ end
13
+
14
+ def create_incident(name, options = {})
15
+ payload = { name: name }.tap do |me|
16
+ me[:detection] = to_option_string(options.delete(:detection)) if options.key?(:detection)
17
+ me[:cause] = to_option_string(options.delete(:cause)) if options.key?(:cause)
18
+ me[:point] = to_option_string(options.delete(:point)) if options.key?(:point)
19
+ me[:scale] = to_option_string(options.delete(:scale)) if options.key?(:scale)
20
+ end
21
+ .merge!(options)
22
+ @api.request(:post, "/api/v1/incidents", body: payload)
23
+ end
24
+
25
+ def describe_incident(incident_id)
26
+ @api.request(:get, "/api/v1/incidents/#{incident_id}")
27
+ end
28
+
29
+ def list_incidents(options = {})
30
+ payload = {}.tap do |me|
31
+ me[:from] = options.delete(:from).to_i if options[:from]
32
+ me[:to] = options.delete(:to).to_i if options[:to]
33
+ me[:status] = options.delete(:status).to_s if options[:status]
34
+ end
35
+ .merge!(options)
36
+ @api.request(:get, "/api/v1/incidents", body: payload)
37
+ end
38
+
39
+ def notify_incident(incident_id, options = {})
40
+ @api.request(
41
+ :post, "/api/v1/notifications",
42
+ body: { incident_id: incident_id }.merge(options)
43
+ )
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,10 @@
1
+ module Reactio
2
+ module Utils
3
+ NIL_STRING = 'null'.freeze
4
+
5
+ def to_option_string(symbol)
6
+ return NIL_STRING if symbol.nil?
7
+ symbol.to_s.gsub('_', '-')
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module Reactio
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'reactio/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "reactio"
8
+ spec.version = Reactio::VERSION
9
+ spec.authors = ["Hajime Sueyoshi"]
10
+ spec.email = ["hajime.sueyoshi@gaiax.com"]
11
+ spec.summary = %q{Reactio API Client}
12
+ spec.description = %q{The official Reactio API Client for ruby.}
13
+ spec.homepage = "https://reactio.jp/"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "faraday"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.7"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "rspec"
26
+ spec.add_development_dependency "webmock"
27
+ end
@@ -0,0 +1,59 @@
1
+ ---
2
+ :id: 1
3
+ :name: "サイト閲覧不可"
4
+ :manager:
5
+ :status: open
6
+ :detection: msp
7
+ :cause: over-capacity
8
+ :cause_supplement: Webサーバがアクセス過多でダウン
9
+ :point: middleware
10
+ :scale: whole
11
+ :pend_text: Webサーバの再起動を行う
12
+ :close_text: Webサーバのスケールアウトを行う
13
+ :closed_by:
14
+ :closed_at:
15
+ :pended_by:
16
+ :pended_at:
17
+ :created_by: 0
18
+ :created_at: 1430208000
19
+ :updated_by: 0
20
+ :updated_at: 1430208000
21
+ :topics:
22
+ - :id: 1
23
+ :name: "原因調査"
24
+ :status: open
25
+ :color: "#5661aa"
26
+ :closed_by:
27
+ :closed_at:
28
+ :created_by: 0
29
+ :created_at: 1430208000
30
+ :updated_by: 0
31
+ :updated_at: 1430208000
32
+ - :id: 2
33
+ :name: "復旧作業"
34
+ :status: open
35
+ :color: "#077f40"
36
+ :closed_by:
37
+ :closed_at:
38
+ :created_by: 0
39
+ :created_at: 1430208000
40
+ :updated_by: 0
41
+ :updated_at: 1430208000
42
+ :notifications:
43
+ :id: 1
44
+ :notification_text: "お疲れ様です。Webサーバで障害が発生しました。至急対応をお願い致します。"
45
+ :notification_call: true
46
+ :notificated_for:
47
+ :phone:
48
+ - '1'
49
+ - '3'
50
+ :email1:
51
+ - '1'
52
+ - '2'
53
+ - '3'
54
+ :email2:
55
+ - '1'
56
+ - '2'
57
+ :imkayac:
58
+ - '1'
59
+ :created_at: 1430208000