Class: TerraformDSL::Deployment
- Inherits:
-
Object
- Object
- TerraformDSL::Deployment
- Defined in:
- lib/scout/terraform_dsl/deployment.rb
Overview
Manage Terraform deployments
Defined Under Namespace
Classes: TerraformException
Instance Attribute Summary collapse
-
#directory ⇒ Object
Returns the value of attribute directory.
Class Method Summary collapse
- .load(file, directory = nil) ⇒ Object
-
.run(cmd) ⇒ String
Run a terraform command returning the STDOUT as a String.
-
.run_log(cmd, log_file = nil) ⇒ Object
Run a terraform command loging STDERR and STDOUT of the process to STDERR and to a log file.
Instance Method Summary collapse
-
#apply ⇒ Object
Applies a terraform deployment by running the plan_file.
- #bundle(file) ⇒ Object
-
#delete(element) ⇒ Object
Delete an element of a deployment.
-
#destroy ⇒ Object
Destroys a provision.
-
#element_state(element) ⇒ String
Return the state of a provisioned element.
-
#init ⇒ Object
Initialize deployment @directory with all the templates and modules.
-
#initialize(config_dir) ⇒ Deployment
constructor
Create a new deployment on a given directory.
-
#log_file ⇒ String
File where the logs will be stored.
-
#output(name, output) ⇒ Hash
Returns the value of an output for a given module in the current deployment.
-
#outputs ⇒ Hash
Returns the outputs available for a current deployment.
-
#plan ⇒ Object
Plan a terraform deployment and save it in #plan_file.
-
#plan_file ⇒ String
File where the terraform plan will be stored.
-
#provisioned_elements ⇒ Array
Lists all provisioned elements.
- #refresh ⇒ Object
-
#templates ⇒ Hash
Lists all provisioned elements.
-
#update ⇒ Object
Update changes on a terraform deployment by running init, plan, and apply.
-
#validate ⇒ Object
Validate a terraform deployment.
- #with_bundle(&block) ⇒ Object
-
#with_deployment ⇒ Object
Apply a deployment, run a block of code, and destroy the deployment afterwards.
Constructor Details
#initialize(config_dir) ⇒ Deployment
Create a new deployment on a given directory. Templates and modules will reside on the directory and can be used by terraform
87 88 89 90 91 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 87 def initialize(config_dir) @directory = (Path === config_dir) ? config_dir.find : config_dir @init = false end |
Instance Attribute Details
#directory ⇒ Object
Returns the value of attribute directory.
80 81 82 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 80 def directory @directory end |
Class Method Details
.load(file, directory = nil) ⇒ Object
272 273 274 275 276 277 278 279 280 281 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 272 def self.load(file, directory = nil) directory ||= WORK_DIR[TerraformDSL.obj2digest(file)] TerraformDSL.log "Load #{file} bundle into #{directory}", "TerraformDSL::Deployment" Misc.in_dir directory do `tar xvfz #{file}` end deployment = TerraformDSL::Deployment.new directory deployment.refresh deployment end |
.run(cmd) ⇒ String
Run a terraform command returning the STDOUT as a String. Forwards STDERR of the process
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 18 def self.run(cmd) Open3.popen3("terraform #{cmd}") do |stdin, stdout, stderr, wait_thr| TerraformDSL.log "Running: terraform #{cmd}", wait_thr.pid stdin.close stderr_thr = Thread.new do while (line = stderr.gets) TerraformDSL.log line, wait_thr.pid end end out = stdout.read exit_status = wait_thr.value raise TerraformException, out.split(/Error:\s*/m).last if exit_status != 0 stderr_thr.join out end end |
.run_log(cmd, log_file = nil) ⇒ Object
Run a terraform command loging STDERR and STDOUT of the process to STDERR and to a log file.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 42 def self.run_log(cmd, log_file = nil) log_io = Open.open(log_file, mode: 'a') if log_file log_io.sync = true if log_io Open3.popen3("terraform #{cmd}") do |stdin, stdout, stderr, wait_thr| TerraformDSL.log "Running: terraform #{cmd}", wait_thr.pid stdin.close wait_thr.pid stdin.close stderr_thr = Thread.new do while (line = stderr.gets) TerraformDSL.log line, [wait_thr.pid, :STDERR] * " - " log_io.puts "[#{Time.now} - STDERR]: " + line if log_io end end stdout_thr = Thread.new do while (line = stdout.gets) TerraformDSL.log line, [wait_thr.pid, :STDOUT] * " - " log_io.puts "[#{Time.now} - STDOUT]: " + line if log_io end end exit_status = wait_thr.value stderr_thr.join stdout_thr.join log_io.close if log_io if exit_status != 0 log_io.close if log_io log_txt = Open.read(log_file, :encoding => "UTF-8") error_msg = log_txt.split(/Error:/).last error_msg = error_msg.split("\n").collect{|e| e.sub(/.*? STD...\]:\s*/,'') } * "\n" raise TerraformException, error_msg end end nil end |
Instance Method Details
#apply ⇒ Object
Applies a terraform deployment by running the plan_file.
141 142 143 144 145 146 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 141 def apply plan unless @planned Misc.in_dir @directory do Deployment.run_log("apply -auto-approve #{plan_file}", log_file) end end |
#bundle(file) ⇒ Object
253 254 255 256 257 258 259 260 261 262 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 253 def bundle(file) raise TerraformException, "Target bundle file is nil" if file.nil? TerraformDSL.log "Bundle #{@directory} in #{file}", "TerraformDSL::Deployment" Misc.in_dir @directory do cmd = "tar cvfz '#{file}' *" cmd += ' *.lock.hcl' if Dir.glob('*.lock.hcl').any? cmd += ' > /dev/null' system(cmd) end end |
#delete(element) ⇒ Object
Delete an element of a deployment. Removes the definition file and the output file
246 247 248 249 250 251 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 246 def delete(element) [element + '.tf', element + '.output.tf'].each do |file| path = @directory[file] Open.rm path end end |
#destroy ⇒ Object
Destroys a provision
193 194 195 196 197 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 193 def destroy Misc.in_dir @directory do Deployment.run_log('destroy -auto-approve', log_file) end end |
#element_state(element) ⇒ String
Return the state of a provisioned element
186 187 188 189 190 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 186 def element_state(element) Misc.in_dir @directory do Deployment.run("state show '#{element}'") end end |
#init ⇒ Object
Initialize deployment @directory with all the templates and modules. Sets @init to true and @planned to false. Removes plan_file if present
105 106 107 108 109 110 111 112 113 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 105 def init Misc.in_dir @directory.find do Deployment.run_log 'init', log_file end Open.rm plan_file if Open.exist?(plan_file) @init = true @planned = false nil end |
#log_file ⇒ String
Returns File where the logs will be stored.
99 100 101 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 99 def log_file @directory.log end |
#output(name, output) ⇒ Hash
Returns the value of an output for a given module in the current deployment
223 224 225 226 227 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 223 def output(name, output) name = name.name if defined?(TerraformDSL::Module) && name.is_a?(TerraformDSL::Module) outputs[[name, output].join('_')] end |
#outputs ⇒ Hash
Returns the outputs available for a current deployment
202 203 204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 202 def outputs outputs = {} Misc.in_dir @directory do output_info = JSON.parse(Deployment.run('output -json')) output_info.each do |output, info| outputs[output] = info['value'] end end outputs end |
#plan ⇒ Object
Plan a terraform deployment and save it in #plan_file. Runs init if required. Saves the time in @planned
132 133 134 135 136 137 138 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 132 def plan init unless @init Misc.in_dir @directory.find do Deployment.run_log("plan -out #{plan_file}", log_file) end @planned = Time.now end |
#plan_file ⇒ String
Returns File where the terraform plan will be stored.
94 95 96 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 94 def plan_file @directory['main.plan'] end |
#provisioned_elements ⇒ Array
Lists all provisioned elements
158 159 160 161 162 163 164 165 166 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 158 def provisioned_elements Misc.in_dir @directory do begin Deployment.run('state list').split("\n") rescue StandardError [] end end end |
#refresh ⇒ Object
148 149 150 151 152 153 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 148 def refresh plan unless @planned Misc.in_dir @directory do Deployment.run_log('refresh', log_file) end end |
#templates ⇒ Hash
Lists all provisioned elements
171 172 173 174 175 176 177 178 179 180 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 171 def templates elements = {} @directory.glob("*.tf").each do |file| if m = File.basename(file).match(/^([^.]+)\.([^.]+)\.tf/) elements[m[1]] ||= [] elements[m[1]] << m[2] end end elements end |
#update ⇒ Object
Update changes on a terraform deployment by running init, plan, and apply
116 117 118 119 120 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 116 def update init plan apply end |
#validate ⇒ Object
Validate a terraform deployment. Runs init if required
123 124 125 126 127 128 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 123 def validate init unless @init Misc.in_dir @directory do Deployment.run('validate') end end |
#with_bundle(&block) ⇒ Object
264 265 266 267 268 269 270 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 264 def with_bundle(&block) name = 'deployment-bundle-tmp_' + rand(100000).to_s + '.tar.gz' TmpFile.with_file nil, extension: 'deployment_bundle' do |tmpfile| bundle(file) yield file end end |
#with_deployment ⇒ Object
Apply a deployment, run a block of code, and destroy the deployment afterwards
233 234 235 236 237 238 239 240 |
# File 'lib/scout/terraform_dsl/deployment.rb', line 233 def with_deployment begin apply yield ensure destroy end end |