panoramix 0.6.1 → 0.7.2
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/panoramix/panoramix_core.rb +9 -3
- data/lib/panoramix/plugin/cfn.rb +230 -0
- data/lib/panoramix/plugin/env.rb +73 -0
- data/lib/panoramix/tasks/actions.rb +3 -1
- data/lib/panoramix.rb +2 -0
- data/locales/en.yml +9 -1
- metadata +36 -2
@@ -41,20 +41,26 @@ module Panoramix
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
def define_action_task(name, desctiption, instance, action)
|
44
|
+
def define_action_task(name, desctiption, instance, action, prerequisites)
|
45
45
|
if instance.respond_to? action.name
|
46
46
|
Rake.application.last_description = desctiption
|
47
47
|
Rake::Task.define_task "#{name}:#{action.name.to_s}" do |t|
|
48
48
|
run_custom_task(instance, action.name)
|
49
49
|
end
|
50
50
|
|
51
|
+
# This must be fixed. Bad code quality!!
|
52
|
+
if action.name == "vars"
|
53
|
+
t = Rake::Task["#{name}:#{action.name.to_s}"]
|
54
|
+
t.enhance prerequisites
|
55
|
+
end
|
56
|
+
|
51
57
|
action.addTask("#{name}:#{action.name.to_s}", instance.class)
|
52
58
|
end
|
53
59
|
end
|
54
60
|
|
55
61
|
def define_task(name, prerequisites, description, block=nil)
|
56
62
|
Rake.application.last_description = description
|
57
|
-
Rake::
|
63
|
+
Rake::MultiTask.define_task({name => prerequisites}, &block)
|
58
64
|
end
|
59
65
|
|
60
66
|
def define_tasks(name, descriptions, instance, prerequisites, block=nil)
|
@@ -67,7 +73,7 @@ module Panoramix
|
|
67
73
|
define_task(name, prerequisites, descriptions[:main], action)
|
68
74
|
|
69
75
|
Panoramix::Tasks::Actions.each do |act|
|
70
|
-
define_action_task(name, descriptions[act.name.to_sym], instance, act)
|
76
|
+
define_action_task(name, descriptions[act.name.to_sym], instance, act, prerequisites)
|
71
77
|
end
|
72
78
|
end
|
73
79
|
|
@@ -0,0 +1,230 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'panoramix/plugin/base'
|
3
|
+
require 'highline/import'
|
4
|
+
require 'toml'
|
5
|
+
|
6
|
+
module Panoramix
|
7
|
+
module Plugin
|
8
|
+
|
9
|
+
class CloudFormationExceptionError < StandardError; end
|
10
|
+
|
11
|
+
class CloudFormation < Base
|
12
|
+
|
13
|
+
attr_reader :dst
|
14
|
+
attr_reader :src
|
15
|
+
attr_reader :stage
|
16
|
+
attr_reader :params
|
17
|
+
attr_reader :owner
|
18
|
+
attr_reader :version
|
19
|
+
|
20
|
+
def initialize(dst, src, parameters, stage, owner, version)
|
21
|
+
@dst = dst
|
22
|
+
@src = src
|
23
|
+
@stage = stage
|
24
|
+
@owner = owner
|
25
|
+
@version = version
|
26
|
+
|
27
|
+
@params = TOML.load_file(parameters)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Final Cloud Formation stack name
|
31
|
+
def stack_name
|
32
|
+
"#{@stage}-#{@dst}-#{@version}-#{owner}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def ask_pro
|
36
|
+
choose do |menu|
|
37
|
+
menu.prompt = "Would you like to delete the stack #{stack_name}? "
|
38
|
+
|
39
|
+
menu.choice(:No) do
|
40
|
+
say("Don't do it again!")
|
41
|
+
return false
|
42
|
+
end
|
43
|
+
menu.choices(:Yes) do
|
44
|
+
resp = ask("Warning, this action can not be reversed. Do you want to continue? (Yes/No)".red, String) do |q|
|
45
|
+
q.default = "No"
|
46
|
+
end
|
47
|
+
return resp == "Yes"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def question
|
53
|
+
case @stage
|
54
|
+
when "pro"
|
55
|
+
return ask_pro
|
56
|
+
when "pre"
|
57
|
+
return ask_pro
|
58
|
+
when "test"
|
59
|
+
return true
|
60
|
+
when "dev"
|
61
|
+
return true
|
62
|
+
else
|
63
|
+
return false
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Return the stack creation time
|
68
|
+
def timestamp
|
69
|
+
return Time.at(0) unless @created
|
70
|
+
|
71
|
+
return Time.parse(@created["CreationTime"])
|
72
|
+
end
|
73
|
+
|
74
|
+
# Has this stacks already been created
|
75
|
+
def created?
|
76
|
+
return @created if @created
|
77
|
+
# Get a list af all created Stacks
|
78
|
+
query = shell("aws cloudformation describe-stacks --query 'Stacks[*].{StackName:StackName, CreationTime:CreationTime}'", true)[:out]
|
79
|
+
parsed_stacks = JSON.parse query
|
80
|
+
|
81
|
+
# Check wether the stacks has already been created
|
82
|
+
info = parsed_stacks.select { |s| s["StackName"] == stack_name }
|
83
|
+
@created = info.empty? ? nil: info
|
84
|
+
end
|
85
|
+
|
86
|
+
# Action delete for this task
|
87
|
+
def delete
|
88
|
+
return unless question
|
89
|
+
|
90
|
+
cmd = "aws cloudformation delete-stack \
|
91
|
+
--stack-name #{stack_name}"
|
92
|
+
|
93
|
+
shell(cmd)
|
94
|
+
end
|
95
|
+
|
96
|
+
# When this instance needs to be executed
|
97
|
+
def needed? timestamps
|
98
|
+
this_time = timestamp
|
99
|
+
timestamps.any? { |t| t > this_time }
|
100
|
+
end
|
101
|
+
|
102
|
+
# Match every parameter with an environment variable
|
103
|
+
def fill_env path
|
104
|
+
file = File.read path
|
105
|
+
json = JSON.parse file
|
106
|
+
|
107
|
+
env = Hash.new
|
108
|
+
json["Parameters"].each do |k,v|
|
109
|
+
env[k] = @params["default"][k]? @params["default"][k] : nil
|
110
|
+
env[k] = @params[@stage][k]? @params[@stage][k] : env[k]
|
111
|
+
env[k] = ENV[k]? ENV[k] : env[k]
|
112
|
+
raise "Parameter or environment variable #{k} not defined" unless env[k]
|
113
|
+
end
|
114
|
+
env
|
115
|
+
end
|
116
|
+
|
117
|
+
# Wait until the stack is being created
|
118
|
+
def wait_for_creation stack_id
|
119
|
+
loop do
|
120
|
+
status = shell("aws cloudformation describe-stacks --stack #{stack_id} --query Stacks[0].StackStatus --output text", true)[:out].strip
|
121
|
+
break if status != "CREATE_IN_PROGRESS"
|
122
|
+
sleep 30
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Deafult task
|
127
|
+
def run_default
|
128
|
+
if created?
|
129
|
+
raise "already created"
|
130
|
+
end
|
131
|
+
env = fill_env @src
|
132
|
+
|
133
|
+
params = ""
|
134
|
+
env.each {|k,v| params = params + "ParameterKey=#{k},ParameterValue=#{v} "}
|
135
|
+
|
136
|
+
template = "file://#{@src}"
|
137
|
+
|
138
|
+
cmd = "aws cloudformation create-stack \
|
139
|
+
--query StackId \
|
140
|
+
--stack-name #{stack_name} \
|
141
|
+
--template-body #{template} \
|
142
|
+
--disable-rollback \
|
143
|
+
--parameters #{params}"
|
144
|
+
|
145
|
+
result = shell(cmd, true)[:out]
|
146
|
+
stack_id = result.strip
|
147
|
+
|
148
|
+
wait_for_creation stack_id
|
149
|
+
end
|
150
|
+
|
151
|
+
def ps
|
152
|
+
if created?
|
153
|
+
shell("aws cloudformation describe-stacks --stack-name #{stack_name}")
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def cfn(args, &block)
|
162
|
+
name = args.keys[0]
|
163
|
+
|
164
|
+
deps = args[name]
|
165
|
+
|
166
|
+
cfn_options = deps.select { |d| d.is_a? Hash }
|
167
|
+
|
168
|
+
# Get cloudformation template file path
|
169
|
+
template = cfn_options.empty? ? nil : cfn_options.first[:template]
|
170
|
+
|
171
|
+
# Raise error if :template value is nil
|
172
|
+
unless template
|
173
|
+
message = I18n.t('errors.cfn.no_template_provided')
|
174
|
+
raise(Panoramix::Plugin::DockerUpExceptionError, message)
|
175
|
+
end
|
176
|
+
|
177
|
+
# Required by aws cli
|
178
|
+
template = File.expand_path template
|
179
|
+
|
180
|
+
# Raise error if the file does not exist
|
181
|
+
unless File.exists? template
|
182
|
+
message = I18n.t('errors.cfn.template_not_found', {:path => template})
|
183
|
+
raise(Panoramix::Plugin::DockerUpExceptionError, message)
|
184
|
+
end
|
185
|
+
|
186
|
+
# Get cloudformation parameters file path
|
187
|
+
parameters = cfn_options.empty? ? nil : cfn_options.first[:parameters]
|
188
|
+
|
189
|
+
# Raise error if :parameters value is nil
|
190
|
+
unless parameters
|
191
|
+
message = I18n.t('errors.cfn.no_parameters_provided')
|
192
|
+
raise(Panoramix::Plugin::DockerUpExceptionError, message)
|
193
|
+
end
|
194
|
+
|
195
|
+
# Raise error if the file does not exist
|
196
|
+
unless File.exists? parameters
|
197
|
+
message = I18n.t('errors.cfn.parameters_not_found', {:path => parameters})
|
198
|
+
raise(Panoramix::Plugin::DockerUpExceptionError, message)
|
199
|
+
end
|
200
|
+
|
201
|
+
# Get the PANORAMIX_OWNER environment variable
|
202
|
+
owner = ENV["PANORAMIX_OWNER"]
|
203
|
+
raise "Variable PANORAMIX_OWNER not defined" unless owner
|
204
|
+
|
205
|
+
# Convert name.surname to namesurname
|
206
|
+
owner = owner.gsub(".", "")
|
207
|
+
|
208
|
+
descriptions = I18n.t('cfn')
|
209
|
+
descriptions = Hash.new if descriptions.class != Hash
|
210
|
+
|
211
|
+
# Merge deps with the cloudformation file task
|
212
|
+
prerequisites = deps.select { |d| ! d.is_a? Hash }
|
213
|
+
prerequisites = prerequisites.push(template)
|
214
|
+
|
215
|
+
["blue", "green"].each do |version|
|
216
|
+
# Create a task inside each development stage namespace
|
217
|
+
["pro", "pre", "dev", "test"].each do |stage|
|
218
|
+
stage_name = "#{stage}:#{name}:#{version}"
|
219
|
+
instance = Panoramix::Plugin::CloudFormation.new(name, template, parameters, stage, owner, version)
|
220
|
+
Panoramix.define_tasks(stage_name, descriptions, instance, prerequisites, block)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
=begin
|
226
|
+
["blue", "green"].each do |version|
|
227
|
+
["pro", "pre", "dev", "test"].each do |stage|
|
228
|
+
end
|
229
|
+
end
|
230
|
+
=end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'panoramix/plugin/base'
|
3
|
+
|
4
|
+
module Panoramix
|
5
|
+
module Plugin
|
6
|
+
|
7
|
+
class EnvironmentError < StandardError; end
|
8
|
+
|
9
|
+
class Environment < Base
|
10
|
+
|
11
|
+
attr_reader :dst
|
12
|
+
attr_reader :src
|
13
|
+
|
14
|
+
def initialize(dst, src)
|
15
|
+
@dst = dst
|
16
|
+
@src = src
|
17
|
+
end
|
18
|
+
|
19
|
+
# Always return an old time
|
20
|
+
def timestamp
|
21
|
+
return Time.at(0)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Always true
|
25
|
+
def needed? timestamps
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
# Deafult task
|
30
|
+
def run_default
|
31
|
+
@src.each do |var|
|
32
|
+
raise "Environment variable #{var} not defined" unless ENV[var]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def vars
|
37
|
+
puts @dst.bold
|
38
|
+
@src.each do |var|
|
39
|
+
puts "#{var}=#{ENV[var]}"
|
40
|
+
end
|
41
|
+
puts ""
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def env(args, &block)
|
49
|
+
name = ""
|
50
|
+
|
51
|
+
deps = []
|
52
|
+
# case env "URL"
|
53
|
+
if (args.class == String)
|
54
|
+
name = args
|
55
|
+
vars = [name]
|
56
|
+
else # case env "some_var" => [{:vars => [......]}]
|
57
|
+
name = args.keys[0]
|
58
|
+
|
59
|
+
deps = args[name]
|
60
|
+
env_options = deps.select { |d| d.is_a? Hash }
|
61
|
+
# Get variables array
|
62
|
+
vars = env_options.empty? ? nil : env_options.first[:vars]
|
63
|
+
end
|
64
|
+
|
65
|
+
descriptions = I18n.t('env')
|
66
|
+
descriptions = Hash.new if descriptions.class != Hash
|
67
|
+
|
68
|
+
# Merge deps
|
69
|
+
prerequisites = deps.select { |d| ! d.is_a? Hash }
|
70
|
+
|
71
|
+
instance = Panoramix::Plugin::Environment.new(name, vars)
|
72
|
+
Panoramix.define_tasks(name, descriptions, instance, prerequisites, block)
|
73
|
+
end
|
@@ -21,8 +21,10 @@ module Panoramix
|
|
21
21
|
end
|
22
22
|
|
23
23
|
Actions = Array.new
|
24
|
-
Actions.push(Action.new("
|
24
|
+
Actions.push(Action.new("delete", false, [Plugin::CloudFormation]))
|
25
|
+
Actions.push(Action.new("ps", false, [Plugin::DockerUp, Plugin::CloudFormation, Plugin::Environment]))
|
25
26
|
Actions.push(Action.new("rm", false, [Plugin::DockerUp]))
|
27
|
+
Actions.push(Action.new("vars", false, [Plugin::Environment]))
|
26
28
|
Actions.push(Action.new("logs", false, [Plugin::DockerUp]))
|
27
29
|
Actions.push(Action.new("clobber", false, [Plugin::DockerUp, Plugin::DockerBuild, Plugin::DockerImage]))
|
28
30
|
Actions.push(Action.new("clean", true, [Plugin::Wget, Plugin::Git, Plugin::S3]))
|
data/lib/panoramix.rb
CHANGED
@@ -2,6 +2,8 @@ require "panoramix/external"
|
|
2
2
|
require "panoramix/plugin/docker_image"
|
3
3
|
require "panoramix/plugin/docker_build"
|
4
4
|
require "panoramix/plugin/docker_up"
|
5
|
+
require "panoramix/plugin/cfn"
|
6
|
+
require "panoramix/plugin/env"
|
5
7
|
require "panoramix/dsl"
|
6
8
|
require "panoramix/panoramix_core"
|
7
9
|
require "panoramix/tasks/actions"
|
data/locales/en.yml
CHANGED
@@ -52,4 +52,12 @@ en:
|
|
52
52
|
s3:
|
53
53
|
not_found: Cannot download %{uri}.
|
54
54
|
git:
|
55
|
-
not_found: Tag %{tag} or branch %{branch} not found.
|
55
|
+
not_found: Tag %{tag} or branch %{branch} not found.
|
56
|
+
cfn:
|
57
|
+
main: Create a new CloudFormation stack
|
58
|
+
ps: Show stack status
|
59
|
+
delete: Delete the CloudFormation stack
|
60
|
+
template_not_found: The given template file %{path} has not found.
|
61
|
+
no_template_provided: Required parameter :template has not been provided.
|
62
|
+
parameters_not_found: The given parameters file %{path} has not found.
|
63
|
+
no_parameters_provided: Required parameter :parameters has not been provided.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: panoramix
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-10-
|
12
|
+
date: 2015-10-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: pry
|
@@ -91,6 +91,38 @@ dependencies:
|
|
91
91
|
- - '='
|
92
92
|
- !ruby/object:Gem::Version
|
93
93
|
version: 0.7.7
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: highline/import
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: toml
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
94
126
|
description: Panoramix is a Rakefile like lib, capable of handling docker deployments
|
95
127
|
email: jig@safelayer.com
|
96
128
|
executables: []
|
@@ -99,11 +131,13 @@ extra_rdoc_files: []
|
|
99
131
|
files:
|
100
132
|
- lib/panoramix.rb
|
101
133
|
- lib/panoramix/locale.rb
|
134
|
+
- lib/panoramix/plugin/cfn.rb
|
102
135
|
- lib/panoramix/plugin/docker_image.rb
|
103
136
|
- lib/panoramix/plugin/docker_up.rb
|
104
137
|
- lib/panoramix/plugin/s3.rb
|
105
138
|
- lib/panoramix/plugin/git.rb
|
106
139
|
- lib/panoramix/plugin/base.rb
|
140
|
+
- lib/panoramix/plugin/env.rb
|
107
141
|
- lib/panoramix/plugin/docker_build.rb
|
108
142
|
- lib/panoramix/plugin/docker_image_base.rb
|
109
143
|
- lib/panoramix/plugin/wget.rb
|