bigpanda 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/bigpanda.rb +1 -0
- data/lib/bigpanda/bp-api.rb +134 -0
- data/lib/bigpanda/capistrano.rb +81 -0
- metadata +63 -0
data/lib/bigpanda.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'bigpanda/bp-api'
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
require 'json'
|
|
3
|
+
require 'net/https'
|
|
4
|
+
|
|
5
|
+
module BigPanda
|
|
6
|
+
|
|
7
|
+
VERSION = '0.1.0'
|
|
8
|
+
|
|
9
|
+
DEFAULT_CONFIG_FILES = [ "/etc/bigpanda.yaml", "/etc/bigpanda.yml" ]
|
|
10
|
+
DEFAULT_CONFIGURATION = { # overridable via the configuration file
|
|
11
|
+
:access_token => nil,
|
|
12
|
+
:target_url => 'https://api.bigpanda.io',
|
|
13
|
+
:deployment_start_path => '/data/events/deployments/start',
|
|
14
|
+
:deployment_end_path => '/data/events/deployments/end'
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
#
|
|
18
|
+
# Main BigPanda API Class
|
|
19
|
+
#
|
|
20
|
+
# The client needs to be initialized with the access_token of the organization.
|
|
21
|
+
# Possible options:
|
|
22
|
+
# 1. Pass the access_token as a :access_token parameter
|
|
23
|
+
# 2. Place a bigpanda.yaml file in /etc/ and add to the file - 'access_token': YOUR_TOKEN
|
|
24
|
+
# 3. Pass a location of a yaml file using the :file parameter
|
|
25
|
+
#
|
|
26
|
+
#
|
|
27
|
+
class Client
|
|
28
|
+
attr_reader :config, :ssl
|
|
29
|
+
|
|
30
|
+
def initialize(options = {})
|
|
31
|
+
|
|
32
|
+
unless options.fetch(:access_token, nil)
|
|
33
|
+
file = options.delete(:file)
|
|
34
|
+
file_config, config_files = read_config_from_file(file)
|
|
35
|
+
options.merge!(file_config) if file_config
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
@config = DEFAULT_CONFIGURATION.merge(options)
|
|
39
|
+
@ssl = options.delete(:ssl) || {}
|
|
40
|
+
|
|
41
|
+
unless @config.fetch(:access_token, nil)
|
|
42
|
+
raise "No BigPanda config token received, and no configuration file found. Searched: #{config_files.join ','}."
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def deployment_start(options = {})
|
|
47
|
+
return deployment_notification config[:deployment_start_path], options
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def deployment_end(options = {})
|
|
51
|
+
return deployment_notification config[:deployment_end_path], options
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
class Error < RuntimeError; end
|
|
57
|
+
class Unauthorized < RuntimeError; end
|
|
58
|
+
|
|
59
|
+
# Prepare the call to BigPanda API and send a HTTP Request
|
|
60
|
+
#
|
|
61
|
+
def deployment_notification(path, options)
|
|
62
|
+
place_default_values(options)
|
|
63
|
+
|
|
64
|
+
return request path, JSON.generate(options)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Perform the actual request to BigPanda API
|
|
68
|
+
#
|
|
69
|
+
def request(path, body, target_url = config[:target_url])
|
|
70
|
+
headers = { 'Accept' => 'application/json',
|
|
71
|
+
'Content-Type' => 'application/json',
|
|
72
|
+
'Authorization' => "Bearer #{config[:access_token]}" }
|
|
73
|
+
|
|
74
|
+
uri = URI.parse(target_url)
|
|
75
|
+
h = Net::HTTP.new uri.host, uri.port
|
|
76
|
+
h.set_debug_output $stderr if $DEBUG
|
|
77
|
+
h.use_ssl = (uri.scheme.downcase == 'https')
|
|
78
|
+
|
|
79
|
+
set_ssl_overrides(h)
|
|
80
|
+
|
|
81
|
+
h.start do |http|
|
|
82
|
+
response = http.request_post path, body, headers
|
|
83
|
+
raise Unauthorized if response.code.to_i == 401
|
|
84
|
+
raise Error, "server error: #{response.body}" if response.code.to_i >= 500
|
|
85
|
+
|
|
86
|
+
answer = JSON.load(response.body)['response']
|
|
87
|
+
raise Error, answer['errors'].join(", ") if response.code.to_i >= 400
|
|
88
|
+
|
|
89
|
+
return answer
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def place_default_values(options)
|
|
94
|
+
options[:timestamp] = options.fetch(:timestamp, Time.now.utc.to_i) # unix time
|
|
95
|
+
|
|
96
|
+
if options.has_key?(:hosts)
|
|
97
|
+
options[:hosts] = options[:hosts].kind_of?(Array) ? options[:hosts] : [options[:hosts]]
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Read configuration from the default list of configuration files and the received file.
|
|
102
|
+
#
|
|
103
|
+
# Returns the the found configuration and the list of files which were used.
|
|
104
|
+
#
|
|
105
|
+
def read_config_from_file(file)
|
|
106
|
+
|
|
107
|
+
config_files = ([file] + DEFAULT_CONFIG_FILES).compact
|
|
108
|
+
config = nil
|
|
109
|
+
|
|
110
|
+
config_files.each do |config_file|
|
|
111
|
+
if File.exists? config_file
|
|
112
|
+
config = YAML.load_file(config_file)
|
|
113
|
+
|
|
114
|
+
# Convert string keys to symbols
|
|
115
|
+
config.keys.each do |key|
|
|
116
|
+
config[(key.to_sym rescue key) || key] = config.delete(key)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
return config, config_files
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def set_ssl_overrides(http)
|
|
125
|
+
http.certificate = ssl[:client_cert] if ssl[:client_cert]
|
|
126
|
+
http.private_key = ssl[:client_key] if ssl[:client_key]
|
|
127
|
+
http.ca_file = ssl[:ca_file] if ssl[:ca_file]
|
|
128
|
+
http.ssl_version = ssl[:version] if ssl[:version]
|
|
129
|
+
http.verify_mode = ssl[:verify_mode] if ssl[:verify_mode]
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require 'bigpanda'
|
|
2
|
+
|
|
3
|
+
Capistrano::Configuration.instance(:must_exist).load do |config|
|
|
4
|
+
|
|
5
|
+
namespace :bigpanda do
|
|
6
|
+
|
|
7
|
+
desc '[Internal] Notifies BigPanda that a deployment has started'
|
|
8
|
+
task :notify_deploy_started do
|
|
9
|
+
transaction do
|
|
10
|
+
on_rollback do
|
|
11
|
+
notify_deploy_failed
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
send_deployment_start
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
desc '[Internal] Notifies BigPanda that a deployment has finished successfuly'
|
|
19
|
+
task :notify_deploy_finished do
|
|
20
|
+
send_deployment_end('success')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
desc '[Internal] Notifies BigPanda that a deployment has finished with an error'
|
|
24
|
+
task :notify_deploy_failed do
|
|
25
|
+
send_deployment_end('failure', errorMessage: 'failed to deploy')
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Map capistrano execution variables to BigPanda Fields for deployment start
|
|
31
|
+
#
|
|
32
|
+
# == Parameters:
|
|
33
|
+
# optional Hash which can contain all propriatery fields
|
|
34
|
+
#
|
|
35
|
+
def send_deployment_start(properties = {})
|
|
36
|
+
panda = create_bigpanda_client
|
|
37
|
+
|
|
38
|
+
panda.deployment_start({:component => application,
|
|
39
|
+
:version => "#{fetch(:branch, '')} #{release_name}",
|
|
40
|
+
:hosts => find_servers_for_task(current_task),
|
|
41
|
+
:env => rails_env,
|
|
42
|
+
:owner => fetch(:bp_owner, nil),
|
|
43
|
+
:properties => properties
|
|
44
|
+
})
|
|
45
|
+
rescue Exception => e
|
|
46
|
+
logger.important "err :: while sending BigPanda start, Skipping to next command. #{e.message}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Map capistrano execution variables to BigPanda Fields for deployment end
|
|
50
|
+
#
|
|
51
|
+
# == Parameters:
|
|
52
|
+
# optional Hash which can contain all propriatery fields
|
|
53
|
+
#
|
|
54
|
+
def send_deployment_end(status, properties = {})
|
|
55
|
+
panda = create_bigpanda_client
|
|
56
|
+
|
|
57
|
+
errorMessage = properties.delete(:errorMessage)
|
|
58
|
+
|
|
59
|
+
panda.deployment_end({ :component => application,
|
|
60
|
+
:version => "#{fetch(:branch, '')} #{release_name}",
|
|
61
|
+
:hosts => find_servers_for_task(current_task),
|
|
62
|
+
:status => status,
|
|
63
|
+
:env => rails_env,
|
|
64
|
+
:errorMessage => errorMessage,
|
|
65
|
+
:properties => properties})
|
|
66
|
+
rescue Exception => e
|
|
67
|
+
logger.important "err :: while sending BigPanda start, Skipping to next command. #{e.message}"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def create_bigpanda_client
|
|
72
|
+
BigPanda::Client.new(:access_token => fetch(:bigpanda_access_token, nil))
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# Hooks:
|
|
77
|
+
# Wrap deploy execution
|
|
78
|
+
|
|
79
|
+
before "deploy:update_code", "bigpanda:notify_deploy_started"
|
|
80
|
+
after "deploy", "bigpanda:notify_deploy_finished"
|
|
81
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: bigpanda
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- BigPanda
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2013-07-17 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: json
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ! '>='
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '0'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ! '>='
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '0'
|
|
30
|
+
description: A Ruby client (and additional integrations) for BigPanda's API
|
|
31
|
+
email: support@bigpanda.io
|
|
32
|
+
executables: []
|
|
33
|
+
extensions: []
|
|
34
|
+
extra_rdoc_files: []
|
|
35
|
+
files:
|
|
36
|
+
- lib/bigpanda.rb
|
|
37
|
+
- lib/bigpanda/capistrano.rb
|
|
38
|
+
- lib/bigpanda/bp-api.rb
|
|
39
|
+
homepage: https://github.com/bigpandaio/bigpanda-rb
|
|
40
|
+
licenses: []
|
|
41
|
+
post_install_message:
|
|
42
|
+
rdoc_options: []
|
|
43
|
+
require_paths:
|
|
44
|
+
- lib
|
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
46
|
+
none: false
|
|
47
|
+
requirements:
|
|
48
|
+
- - ! '>='
|
|
49
|
+
- !ruby/object:Gem::Version
|
|
50
|
+
version: '0'
|
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
52
|
+
none: false
|
|
53
|
+
requirements:
|
|
54
|
+
- - ! '>='
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: '0'
|
|
57
|
+
requirements: []
|
|
58
|
+
rubyforge_project:
|
|
59
|
+
rubygems_version: 1.8.24
|
|
60
|
+
signing_key:
|
|
61
|
+
specification_version: 3
|
|
62
|
+
summary: A Ruby client (and additional integrations) for BigPanda's API
|
|
63
|
+
test_files: []
|