jackal-stacks 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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +2 -0
- data/CONTRIBUTING.md +25 -0
- data/LICENSE +13 -0
- data/README.md +15 -0
- data/jackal-stacks.gemspec +17 -0
- data/lib/jackal-stacks.rb +13 -0
- data/lib/jackal-stacks/builder.rb +242 -0
- data/lib/jackal-stacks/formatter.rb +4 -0
- data/lib/jackal-stacks/formatter/code_fetcher.rb +30 -0
- data/lib/jackal-stacks/formatter/github.rb +39 -0
- data/lib/jackal-stacks/formatter/slack.rb +43 -0
- data/lib/jackal-stacks/formatter/webhook.rb +27 -0
- data/lib/jackal-stacks/stack_common.rb +42 -0
- data/lib/jackal-stacks/version.rb +6 -0
- data/lib/jackal-stacks/wrecker.rb +46 -0
- metadata +101 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4b71b344dfac97c00282df6e96bde5f3d413a74e
|
4
|
+
data.tar.gz: 9b787df9e775186d5333de90f3eacfd9076a1135
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 55393fe0bb6bfd1b26e6841eac37a4674b384560a90688bfa8094c7fc3ec01a13841cbd0ed8e265136ba90c811bd4c4c4a1cbba1ebcc4a141e88c875ede9609d
|
7
|
+
data.tar.gz: dadc256d8c3b29ec838e608141f4a088577ff593790c3aad5d9b22e3526136d893dc990b78f5c2e9ab897f842cd44b9ab4edfd9e41c5dbbb495f0d1101fd1df8
|
data/CHANGELOG.md
ADDED
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# Contributing
|
2
|
+
|
3
|
+
## Branches
|
4
|
+
|
5
|
+
### `master` branch
|
6
|
+
|
7
|
+
The master branch is the current stable released version.
|
8
|
+
|
9
|
+
### `develop` branch
|
10
|
+
|
11
|
+
The develop branch is the current edge of development.
|
12
|
+
|
13
|
+
## Pull requests
|
14
|
+
|
15
|
+
* https://github.com/carnivore-rb/jackal-stacks/pulls
|
16
|
+
|
17
|
+
Please base all pull requests of the `develop` branch. Merges to
|
18
|
+
`master` only occur through the `develop` branch. Pull requests
|
19
|
+
based on `master` will likely be cherry picked.
|
20
|
+
|
21
|
+
## Issues
|
22
|
+
|
23
|
+
Need to report an issue? Use the github issues:
|
24
|
+
|
25
|
+
* https://github.com/carnivore-rb/jackal-stacks/issues
|
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright 2015 Chris Roberts
|
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,15 @@
|
|
1
|
+
# Jackal Stacks
|
2
|
+
|
3
|
+
Build stacks \o/
|
4
|
+
|
5
|
+
## Requirements
|
6
|
+
|
7
|
+
This service assumes the payload information provided via the code
|
8
|
+
fetcher service.
|
9
|
+
|
10
|
+
## Configuration
|
11
|
+
|
12
|
+
# Info
|
13
|
+
|
14
|
+
* Repository: https://github.com/carnivore-rb/jackal-stacks
|
15
|
+
* IRC: Freenode @ #carnivore
|
@@ -0,0 +1,17 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__)) + '/lib/'
|
2
|
+
require 'jackal-stacks/version'
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = 'jackal-stacks'
|
5
|
+
s.version = Jackal::Stacks::VERSION.version
|
6
|
+
s.summary = 'Message processing helper'
|
7
|
+
s.author = 'Chris Roberts'
|
8
|
+
s.email = 'code@chrisroberts.org'
|
9
|
+
s.homepage = 'https://github.com/carnivore-rb/jackal-stacks'
|
10
|
+
s.description = 'Build stuff!'
|
11
|
+
s.require_path = 'lib'
|
12
|
+
s.license = 'Apache 2.0'
|
13
|
+
s.add_dependency 'jackal'
|
14
|
+
s.add_dependency 'librarian-chef'
|
15
|
+
s.add_dependency 'sfn'
|
16
|
+
s.files = Dir['lib/**/*'] + %w(jackal-stacks.gemspec README.md CHANGELOG.md CONTRIBUTING.md LICENSE)
|
17
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'sfn'
|
2
|
+
require 'jackal'
|
3
|
+
|
4
|
+
module Jackal
|
5
|
+
module Stacks
|
6
|
+
autoload :Builder, 'jackal-stacks/builder'
|
7
|
+
autoload :StackCommon, 'jackal-stacks/stack_common'
|
8
|
+
autoload :Wrecker, 'jackal-stacks/wrecker'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'jackal-stacks/formatter'
|
13
|
+
require 'jackal-stacks/version'
|
@@ -0,0 +1,242 @@
|
|
1
|
+
require 'jackal-stacks'
|
2
|
+
|
3
|
+
module Jackal
|
4
|
+
module Stacks
|
5
|
+
# Stack builder
|
6
|
+
class Builder < Callback
|
7
|
+
|
8
|
+
include StackCommon
|
9
|
+
|
10
|
+
# Setup callback
|
11
|
+
def setup(*_)
|
12
|
+
require 'sfn'
|
13
|
+
require 'bogo-ui'
|
14
|
+
require 'stringio'
|
15
|
+
require 'openssl'
|
16
|
+
# Ensure we can build the API at startup
|
17
|
+
stacks_api
|
18
|
+
end
|
19
|
+
|
20
|
+
# Determine validity of message
|
21
|
+
#
|
22
|
+
# @param message [Carnivore::Message]
|
23
|
+
# @return [Truthy, Falsey]
|
24
|
+
def valid?(message)
|
25
|
+
super do |payload|
|
26
|
+
payload.get(:data, :stacks, :builder) &&
|
27
|
+
payload.get(:data, :stacks, :template) &&
|
28
|
+
payload.get(:data, :stacks, :asset) &&
|
29
|
+
allowed?(payload)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# @return [String] working directory
|
34
|
+
def working_directory
|
35
|
+
memoize(:working_directory, :direct) do
|
36
|
+
FileUtils.mkdir_p(dir = config.fetch(:working_directory, '/tmp/jackal-stack-builder'))
|
37
|
+
dir
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [String] fresh working directory
|
42
|
+
def workspace(payload)
|
43
|
+
File.join(working_directory, payload[:id])
|
44
|
+
end
|
45
|
+
|
46
|
+
# Build or update stacks
|
47
|
+
#
|
48
|
+
# @param message [Carnivore::Message]
|
49
|
+
def execute(message)
|
50
|
+
failure_wrap(message) do |payload|
|
51
|
+
directory = asset_store.unpack(asset_store.get(payload.get(:data, :stacks, :asset)), workspace(payload))
|
52
|
+
begin
|
53
|
+
unless(payload.get(:data, :stacks, :name))
|
54
|
+
payload.set(:data, :stacks, :name, stack_name(payload))
|
55
|
+
end
|
56
|
+
store_stable_asset(payload, directory)
|
57
|
+
begin
|
58
|
+
stack = stacks_api.stacks.get(payload.get(:data, :stacks, :name))
|
59
|
+
rescue
|
60
|
+
stack = nil
|
61
|
+
end
|
62
|
+
if(stack)
|
63
|
+
info "Stack currently exists. Applying update [#{stack}]"
|
64
|
+
run_stack(payload, directory, :update)
|
65
|
+
payload.set(:data, :stacks, :updated, true)
|
66
|
+
else
|
67
|
+
info "Stack does not currently exist. Building new stack [#{payload.get(:data, :stacks, :name)}]"
|
68
|
+
init_provider(payload)
|
69
|
+
run_stack(payload, directory, :create)
|
70
|
+
payload.set(:data, :stacks, :created, true)
|
71
|
+
end
|
72
|
+
ensure
|
73
|
+
FileUtils.rm_rf(directory)
|
74
|
+
end
|
75
|
+
job_completed(:stacks, payload, message)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Build configuration arguments for Sfn::Command execution
|
80
|
+
#
|
81
|
+
# @param payload [Smash]
|
82
|
+
# @param directory [String] directory to unpacked asset
|
83
|
+
# @return [Smash] stack command options hash
|
84
|
+
def build_stack_args(payload, directory)
|
85
|
+
Smash.new(
|
86
|
+
:base_directory => File.join(directory, 'cloudformation'),
|
87
|
+
:parameters => load_stack_parameters(payload, directory),
|
88
|
+
:ui => Bogo::Ui.new(
|
89
|
+
:app_name => 'JackalStacks',
|
90
|
+
:defaults => true,
|
91
|
+
:output_to => StringIO.new('')
|
92
|
+
),
|
93
|
+
:interactive_parameters => false,
|
94
|
+
:nesting_bucket => config.get(:orchestration, :bucket_name),
|
95
|
+
:apply_nesting => true,
|
96
|
+
:processing => true,
|
97
|
+
:options => {
|
98
|
+
:disable_rollback => true,
|
99
|
+
:capabilities => ['CAPABILITY_IAM']
|
100
|
+
},
|
101
|
+
:credentials => config.get(:orchestration, :api, :credentials),
|
102
|
+
:file => payload.get(:data, :stacks, :template),
|
103
|
+
:file_path_prompt => false,
|
104
|
+
:poll => false
|
105
|
+
)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Extract any custom parameters from asset store if available,
|
109
|
+
# and merge any parameters provided via payload, and finally
|
110
|
+
# merge any parameters provided via configuration
|
111
|
+
#
|
112
|
+
# @param payload [Smash]
|
113
|
+
# @param directory [String]
|
114
|
+
# @note parameter precedence:
|
115
|
+
# * Hook URL parameters
|
116
|
+
# * Payload parameters
|
117
|
+
# * Stacks file parameters
|
118
|
+
# * Service configuration parameters
|
119
|
+
def load_stack_parameters(payload, directory)
|
120
|
+
params = Smash.new
|
121
|
+
stacks_file = load_stacks_file(payload, directory)
|
122
|
+
s_namespace = determine_namespace(payload)
|
123
|
+
template = payload.get(:data, :stacks, :template)
|
124
|
+
params.deep_merge!(payload.fetch(:data, :webhook, :query, :stacks, :parameters, Smash.new))
|
125
|
+
params.deep_merge!(payload.fetch(:data, :stacks, :parameters, Smash.new))
|
126
|
+
params.deep_merge!(
|
127
|
+
stacks_file.fetch(s_namespace, template, :parameters,
|
128
|
+
stacks_file.fetch(:default, template, :parameters, Smash.new)
|
129
|
+
)
|
130
|
+
)
|
131
|
+
params.deep_merge!(
|
132
|
+
config.fetch(:parameter_overrides, s_namespace, template,
|
133
|
+
config.fetch(:parameter_overrides, :default, template, Smash.new)
|
134
|
+
)
|
135
|
+
)
|
136
|
+
params
|
137
|
+
end
|
138
|
+
|
139
|
+
# Parse the `.stacks` file if available
|
140
|
+
#
|
141
|
+
# @param payload [Smash]
|
142
|
+
# @param directory [String] path to unpacked asset directory
|
143
|
+
# @return [Smash]
|
144
|
+
def load_stacks_file(payload, directory)
|
145
|
+
stacks_path = File.join(directory, '.stacks')
|
146
|
+
if(File.exists?(stacks_path))
|
147
|
+
Bogo::Config.new(file_path).data
|
148
|
+
else
|
149
|
+
Smash.new
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# Perform stack action
|
154
|
+
#
|
155
|
+
# @param payload [Smash]
|
156
|
+
# @param directory [String] directory to unpacked asset
|
157
|
+
# @param action [Symbol, String] :create or :update
|
158
|
+
# @return [TrueClass]
|
159
|
+
def run_stack(payload, directory, action)
|
160
|
+
unless([:create, :update].include?(action.to_sym))
|
161
|
+
abort ArgumentError.new("Invalid action argument `#{action}`. Expecting `create` or `update`!")
|
162
|
+
end
|
163
|
+
args = build_stack_args(payload, directory)
|
164
|
+
stack_name = payload.get(:data, :stacks, :name)
|
165
|
+
Sfn::Command.const_get(action.to_s.capitalize).new(args, [stack_name]).execute!
|
166
|
+
true
|
167
|
+
end
|
168
|
+
|
169
|
+
# Check if this payload is allowed to be processed based on
|
170
|
+
# defined restrictions within the configuration
|
171
|
+
#
|
172
|
+
# @param payload [Smash]
|
173
|
+
# @return [TrueClass, FalseClass]
|
174
|
+
def allowed?(payload)
|
175
|
+
!!determine_namespace(payload)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Initialize provider if instructed via config
|
179
|
+
#
|
180
|
+
# @param payload [Smash]
|
181
|
+
# @note this currently init's chef related items
|
182
|
+
def init_provider(payload)
|
183
|
+
if(config.get(:init, :chef, :validator) || config.get(:init, :chef, :encrypted_secret))
|
184
|
+
bucket = stacks_api.api_for(:storage).buckets.get(config.get(:orchestration, :bucket_name))
|
185
|
+
validator_name = name_for(payload, 'validator.pem')
|
186
|
+
if(config.get(:init, :chef, :validator) && bucket.files.get(validator_name).nil?)
|
187
|
+
file = bucket.files.build(:name => validator_name)
|
188
|
+
file.body = OpenSSL::PKey::RSA.new(2048).export
|
189
|
+
file.save
|
190
|
+
end
|
191
|
+
secret_name = name_for(payload, 'encrypted_data_bag_secret')
|
192
|
+
if(config.get(:init, :chef, :encrypted_secret) && bucket.files.get(secret_name).nil?)
|
193
|
+
file = bucket.files.build(:name => secret_name)
|
194
|
+
file.body = SecureRandom.base64(2048)
|
195
|
+
file.save
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Store stable asset in object store
|
201
|
+
#
|
202
|
+
# @param payload [Smash]
|
203
|
+
def store_stable_asset(payload, directory)
|
204
|
+
if(config.get(:init, :stable))
|
205
|
+
['rm -rf .librarian Gemfile Gemfile.lock', 'librarian-chef install', 'rm -rf tmp'].each do |cmd|
|
206
|
+
info "Starting stable store pre-pack command: #{cmd}"
|
207
|
+
process_manager.process(payload[:id], cmd) do |process|
|
208
|
+
process.cwd = directory
|
209
|
+
process.io.inherit!
|
210
|
+
process.start
|
211
|
+
process.wait
|
212
|
+
unless(process.exit_code == 0)
|
213
|
+
raise 'Cookbook install failed!'
|
214
|
+
end
|
215
|
+
end
|
216
|
+
info "Completed stable store pre-pack command: #{cmd}"
|
217
|
+
end
|
218
|
+
debug "Starting stable asset upload for #{payload[:id]}"
|
219
|
+
bucket = stacks_api.api_for(:storage).buckets.get(config.get(:orchestration, :bucket_name))
|
220
|
+
stable_name = name_for(payload, 'stable.zip')
|
221
|
+
file = bucket.files.get(stable_name) || bucket.files.build(:name => stable_name)
|
222
|
+
file.body = asset_store.pack(directory)
|
223
|
+
file.save
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
# Provide prefixed key name for asset
|
228
|
+
#
|
229
|
+
# @param payload [Smash]
|
230
|
+
# @param asset_name [String
|
231
|
+
# @return [String]
|
232
|
+
# @note this is currently a no-op and thus are shared across
|
233
|
+
# stacks. currently is stubbed for completion of template and
|
234
|
+
# interaction logic
|
235
|
+
def name_for(payload, asset_name)
|
236
|
+
File.join(determine_namespace(payload), asset_name)
|
237
|
+
asset_name
|
238
|
+
end
|
239
|
+
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'jackal-stacks'
|
2
|
+
|
3
|
+
module Jackal
|
4
|
+
module Stacks
|
5
|
+
module Formatter
|
6
|
+
# Format code fetcher data for stacks
|
7
|
+
class CodeFetcher < Jackal::Formatter
|
8
|
+
|
9
|
+
SOURCE = 'code_fetcher'
|
10
|
+
DESTINATION = 'stacks'
|
11
|
+
|
12
|
+
# Format payload
|
13
|
+
#
|
14
|
+
# @param payload [Smash]
|
15
|
+
def format(payload)
|
16
|
+
if(payload.get(:data, :code_fetcher))
|
17
|
+
payload.set(:data, :stacks, :asset,
|
18
|
+
payload.get(:data, :code_fetcher, :asset)
|
19
|
+
)
|
20
|
+
payload.set(:data, :stacks, :reference,
|
21
|
+
payload.get(:data, :code_fetcher, :info, :reference)
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'jackal-stacks'
|
2
|
+
|
3
|
+
module Jackal
|
4
|
+
module Stacks
|
5
|
+
module Formatter
|
6
|
+
# Format github data for stacks
|
7
|
+
class Github < Jackal::Formatter
|
8
|
+
|
9
|
+
# Source service
|
10
|
+
SOURCE = :github
|
11
|
+
# Destination service
|
12
|
+
DESTINATION = :stacks
|
13
|
+
|
14
|
+
# Valid github events
|
15
|
+
VALID_EVENTS = %w(create delete push)
|
16
|
+
|
17
|
+
# Format payload
|
18
|
+
#
|
19
|
+
# @param payload [Smash]
|
20
|
+
def format(payload)
|
21
|
+
if(VALID_EVENTS.include?(payload.get(:data, :github, :event)))
|
22
|
+
if(payload.get(:data, :github, :query, :template))
|
23
|
+
payload.set(:data, :stacks, :template,
|
24
|
+
payload.get(:data, :github, :query, :template)
|
25
|
+
)
|
26
|
+
end
|
27
|
+
if(payload.get(:data, :github, :event) == 'delete')
|
28
|
+
payload.set(:data, :stacks, :wrecker, true)
|
29
|
+
else
|
30
|
+
payload.set(:data, :stacks, :builder, true)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'jackal-stacks'
|
2
|
+
|
3
|
+
module Jackal
|
4
|
+
module Stacks
|
5
|
+
module Formatter
|
6
|
+
# Format result for slack notification
|
7
|
+
class Slack < Jackal::Formatter
|
8
|
+
|
9
|
+
# Source service
|
10
|
+
SOURCE = 'stacks'
|
11
|
+
# Destination service
|
12
|
+
DESTINATION = 'slack'
|
13
|
+
|
14
|
+
NOTIFY_ON = %w(created updated destroyed)
|
15
|
+
|
16
|
+
# Format payload
|
17
|
+
#
|
18
|
+
# @param payload [Smash]
|
19
|
+
def format(payload)
|
20
|
+
if(payload.get(:data, :stacks))
|
21
|
+
unless((notify = payload.fetch(:data, :stacks, {}).keys & NOTIFY_ON).empty?)
|
22
|
+
msgs = payload.fetch(:data, :slack, :messages, [])
|
23
|
+
msgs << Smash.new(
|
24
|
+
:description => "Stacks result: #{notify.first}",
|
25
|
+
:message => [
|
26
|
+
"Stack has been #{notify.first} [name: #{payload.get(:data, :stacks, :name)}]",
|
27
|
+
"* Template: #{payload.get(:data, :stacks, :template)}",
|
28
|
+
"* Repository: #{payload.get(:data, :code_fetcher, :info, :owner)}/#{payload.get(:data, :code_fetcher, :info, :name)}",
|
29
|
+
"* Reference: #{payload.get(:data, :code_fetcher, :info, :reference)}",
|
30
|
+
"* SHA: #{payload.get(:data, :code_fetcher, :info, :commit_sha)}"
|
31
|
+
].join("\n"),
|
32
|
+
:color => :good
|
33
|
+
)
|
34
|
+
payload.set(:data, :slack, :messages, msgs)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'jackal-stacks'
|
2
|
+
|
3
|
+
module Jackal
|
4
|
+
module Stacks
|
5
|
+
module Formatter
|
6
|
+
# Format webhook data for stacks
|
7
|
+
class Webhook < Jackal::Formatter
|
8
|
+
|
9
|
+
SOURCE = 'webhook'
|
10
|
+
DESTINATION = 'stacks'
|
11
|
+
|
12
|
+
# Format payload
|
13
|
+
#
|
14
|
+
# @param payload [Smash]
|
15
|
+
def format(payload)
|
16
|
+
if(payload.get(:data, :webhook, :query, :template))
|
17
|
+
payload.set(:data, :stacks, :template,
|
18
|
+
payload.get(:data, :webhook, :query, :template)
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'jackal-stacks'
|
2
|
+
|
3
|
+
module Jackal
|
4
|
+
module Stacks
|
5
|
+
module StackCommon
|
6
|
+
|
7
|
+
# @return [Miasma::Models::Orchestration]
|
8
|
+
def stacks_api
|
9
|
+
memoize(:stacks_api, :direct) do
|
10
|
+
Miasma.api(
|
11
|
+
config.fetch(
|
12
|
+
:orchestration, :api, Smash.new
|
13
|
+
).merge(
|
14
|
+
:type => :orchestration
|
15
|
+
)
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Determine namespace key to use for accessing parameters
|
21
|
+
#
|
22
|
+
# @param payload [Smash]
|
23
|
+
# @return [String]
|
24
|
+
# @note if not match found, `default` will return
|
25
|
+
def determine_namespace(payload)
|
26
|
+
config.fetch(:mappings, Smash.new).map do |ns, glob|
|
27
|
+
ns if File.fnmatch?(glob, payload.get(:data, :stacks, :reference).to_s)
|
28
|
+
end.compact.first
|
29
|
+
end
|
30
|
+
|
31
|
+
# Generate stack name based on payload
|
32
|
+
#
|
33
|
+
# @param payload [Smash]
|
34
|
+
# @return [String] stack name
|
35
|
+
def stack_name(payload)
|
36
|
+
s_namespace = determine_namespace(payload)
|
37
|
+
"#{s_namespace}-#{payload.get(:data, :stacks, :template).sub(/\.[a-z]+$/, '').gsub(/[^A-Za-z0-9\-]/, '-')}"
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'jackal-stacks'
|
2
|
+
|
3
|
+
module Jackal
|
4
|
+
module Stacks
|
5
|
+
# Stack destroyer
|
6
|
+
class Wrecker < Callback
|
7
|
+
|
8
|
+
include StackCommon
|
9
|
+
|
10
|
+
# Setup callback
|
11
|
+
def setup(*_)
|
12
|
+
stacks_api
|
13
|
+
end
|
14
|
+
|
15
|
+
# Determine validity of message
|
16
|
+
#
|
17
|
+
# @param message [Carnivore::Message]
|
18
|
+
# @return [Truthy, Falsey]
|
19
|
+
def valid?(message)
|
20
|
+
super do |payload|
|
21
|
+
payload.get(:data, :stacks, :wrecker)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Build or update stacks
|
26
|
+
#
|
27
|
+
# @param message [Carnivore::Message]
|
28
|
+
def execute(message)
|
29
|
+
failure_wrap(message) do |payload|
|
30
|
+
s_name = stack_name(payload)
|
31
|
+
stack = stacks_api.stacks.get(s_name)
|
32
|
+
if(stack)
|
33
|
+
info "Stack currently exists. Destroying. [#{stack.name}]"
|
34
|
+
stack.destroy
|
35
|
+
payload.set(:data, :stacks, :destroyed, true)
|
36
|
+
job_completed(:stacks, payload, message)
|
37
|
+
else
|
38
|
+
error "Failed to locate requested stack for destruction [#{s_name}]"
|
39
|
+
failed(payload, message, 'Requested stack does not exist')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jackal-stacks
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Roberts
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-03-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: jackal
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: librarian-chef
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sfn
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Build stuff!
|
56
|
+
email: code@chrisroberts.org
|
57
|
+
executables: []
|
58
|
+
extensions: []
|
59
|
+
extra_rdoc_files: []
|
60
|
+
files:
|
61
|
+
- CHANGELOG.md
|
62
|
+
- CONTRIBUTING.md
|
63
|
+
- LICENSE
|
64
|
+
- README.md
|
65
|
+
- jackal-stacks.gemspec
|
66
|
+
- lib/jackal-stacks.rb
|
67
|
+
- lib/jackal-stacks/builder.rb
|
68
|
+
- lib/jackal-stacks/formatter.rb
|
69
|
+
- lib/jackal-stacks/formatter/code_fetcher.rb
|
70
|
+
- lib/jackal-stacks/formatter/github.rb
|
71
|
+
- lib/jackal-stacks/formatter/slack.rb
|
72
|
+
- lib/jackal-stacks/formatter/webhook.rb
|
73
|
+
- lib/jackal-stacks/stack_common.rb
|
74
|
+
- lib/jackal-stacks/version.rb
|
75
|
+
- lib/jackal-stacks/wrecker.rb
|
76
|
+
homepage: https://github.com/carnivore-rb/jackal-stacks
|
77
|
+
licenses:
|
78
|
+
- Apache 2.0
|
79
|
+
metadata: {}
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options: []
|
82
|
+
require_paths:
|
83
|
+
- lib
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
requirements: []
|
95
|
+
rubyforge_project:
|
96
|
+
rubygems_version: 2.2.2
|
97
|
+
signing_key:
|
98
|
+
specification_version: 4
|
99
|
+
summary: Message processing helper
|
100
|
+
test_files: []
|
101
|
+
has_rdoc:
|