panoramix 0.6.1 → 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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::Task.define_task({name => prerequisites}, &block)
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("ps", false, [Plugin::DockerUp]))
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.6.1
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-02 00:00:00.000000000 Z
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