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.
@@ -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: []