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.
@@ -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