Class: Blower::Context
- Extended by:
- Forwardable
- Defined in:
- lib/blower/context.rb
Overview
Blower tasks are executed within a context.
The context can be used to share information between tasks by storing it in instance variables.
Defined Under Namespace
Classes: HostHash
Instance Attribute Summary collapse
-
#file ⇒ Object
The file name of the currently running task.
-
#hosts ⇒ Object
The target hosts.
-
#path ⇒ Object
Search path for tasks.
-
#user ⇒ Object
Username override.
Instance Method Summary collapse
-
#as(user, quiet: false) ⇒ Object
Yield with a temporary username override.
-
#cp(from, to, as: user, on: hosts, quiet: false, once: nil, delete: false) ⇒ Object
Copy a file or readable to the host filesystems.
-
#get(name, default = nil) ⇒ Object
Return a context variable.
-
#initialize(path) ⇒ Context
constructor
Create a new Context.
-
#on(*hosts, quiet: false) ⇒ Object
Yield with a temporary host list.
-
#once(key, store: "/var/cache/blower.json", quiet: false) ⇒ Object
Execute a block only once per host.
-
#ping(on: hosts, quiet: false) ⇒ Object
Ping each host by trying to connect to port 22.
-
#read(filename, as: user, on: hosts, quiet: false) ⇒ Hash
Reads a remote file from each host.
-
#render(from, to, as: user, on: hosts, quiet: false, once: nil) ⇒ Object
Renders and installs files from ERB templates.
-
#run(task, optional: false, quiet: false, once: nil) ⇒ Object
Find and execute a task.
-
#set(hash) ⇒ Object
Merge the hash into the context variables.
-
#sh(command, as: user, on: hosts, quiet: false, once: nil) ⇒ Object
Execute a shell command on each host.
-
#unset(*names) ⇒ Object
Remove context variables.
-
#with(hash, quiet: false) ⇒ Object
Yield with the hash temporary merged into the context variables.
-
#write(string, to, as: user, on: hosts, quiet: false, once: nil) ⇒ Object
Writes a string to a file on the host filesystems.
Constructor Details
#initialize(path) ⇒ Context
Create a new Context.
44 45 46 47 48 |
# File 'lib/blower/context.rb', line 44 def initialize (path) @path = path @data = {} @hosts = [] end |
Instance Attribute Details
#file ⇒ Object
The file name of the currently running task. Context#cp interprets relative file names relative to this file name’s directory component.
40 41 42 |
# File 'lib/blower/context.rb', line 40 def file @file end |
#hosts ⇒ Object
The target hosts.
33 34 35 |
# File 'lib/blower/context.rb', line 33 def hosts @hosts end |
#path ⇒ Object
Search path for tasks.
30 31 32 |
# File 'lib/blower/context.rb', line 30 def path @path end |
#user ⇒ Object
Username override. If not-nil, this user is used for all remote accesses.
36 37 38 |
# File 'lib/blower/context.rb', line 36 def user @user end |
Instance Method Details
#as(user, quiet: false) ⇒ Object
Yield with a temporary username override
100 101 102 103 104 105 106 |
# File 'lib/blower/context.rb', line 100 def as (user, quiet: false) let :@user => user do log.info "as #{user}", quiet: quiet do yield end end end |
#cp(readable, to, as: user, on: hosts, quiet: false) ⇒ Object #cp(filename, to, as: user, on: hosts, quiet: false) ⇒ Object
Copy a file or readable to the host filesystems.
162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/blower/context.rb', line 162 def cp (from, to, as: user, on: hosts, quiet: false, once: nil, delete: false) self.once once, quiet: quiet do log.info "cp: #{from} -> #{to}", quiet: quiet do Dir.chdir File.dirname(file) do hash_map(hosts) do |host| host.cp from, to, as: as, quiet: quiet, delete: delete end end end end end |
#get(name, default = nil) ⇒ Object
Return a context variable.
53 54 55 |
# File 'lib/blower/context.rb', line 53 def get (name, default = nil) @data.fetch(name, default) end |
#on(*hosts, quiet: false) ⇒ Object
Yield with a temporary host list
90 91 92 93 94 95 96 |
# File 'lib/blower/context.rb', line 90 def on (*hosts, quiet: false) let :@hosts => hosts.flatten do log.info "on #{@hosts.map(&:name).join(", ")}", quiet: quiet do yield end end end |
#once(key, store: "/var/cache/blower.json", quiet: false) ⇒ Object
Execute a block only once per host. It is usually preferable to make tasks idempotent, but when that isn’t possible, once will only execute the block on hosts where a block with the same key hasn’t previously been successfully executed.
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'lib/blower/context.rb', line 259 def once (key, store: "/var/cache/blower.json", quiet: false) return yield unless key log.info "once: #{key}", quiet: quiet do hash_map(hosts) do |host| done = begin JSON.parse(host.read(store, quiet: true)) rescue => e {} end unless done[key] on [host] do yield end done[key] = true host.write(done.to_json, store, quiet: true) end end end end |
#ping(on: hosts, quiet: false) ⇒ Object
Ping each host by trying to connect to port 22
244 245 246 247 248 249 250 |
# File 'lib/blower/context.rb', line 244 def ping (on: hosts, quiet: false) log.info "ping", quiet: quiet do hash_map(hosts) do |host| host.ping end end end |
#read(filename, as: user, on: hosts, quiet: false) ⇒ Hash
Reads a remote file from each host.
180 181 182 183 184 185 186 |
# File 'lib/blower/context.rb', line 180 def read (filename, as: user, on: hosts, quiet: false) log.info "read: #{filename}", quiet: quiet do hash_map(hosts) do |host| host.read filename, as: as end end end |
#render(from, to, as: user, on: hosts, quiet: false, once: nil) ⇒ Object
Renders and installs files from ERB templates. Files are under from in ERB format. from/foo/bar.conf.erb is rendered and written to to/foo/bar.conf. Non-ERB files are ignored.
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
# File 'lib/blower/context.rb', line 213 def render (from, to, as: user, on: hosts, quiet: false, once: nil) self.once once, quiet: quiet do Dir.chdir File.dirname(file) do Find.find(from).each do |path| if File.directory?(path) to_path = to + path[from.length..-1] sh "mkdir -p #{to_path.shellescape}" elsif path =~ /\.erb$/ template = ERB.new(File.read(path)) to_path = to + path[from.length..-5] log.info "render: #{path} -> #{to_path}", quiet: quiet do hash_map(hosts) do |host| host.cp StringIO.new(template.result(binding)), to_path, as: as, quiet: quiet end end else to_path = to + path[from.length..-1] log.info "copy: #{path} -> #{to_path}", quiet: quiet do hash_map(hosts) do |host| host.cp File.open(path), to_path, as: as, quiet: quiet end end end end end end end |
#run(task, optional: false, quiet: false, once: nil) ⇒ Object
Find and execute a task. For each entry in the search path, it checks for path/task.rb, path/task/blow.rb, and finally for bare path/task. The search stops at the first match. If found, the task is executed within the context, with @file bound to the task’s file name.
117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/blower/context.rb', line 117 def run (task, optional: false, quiet: false, once: nil) once once, quiet: quiet do log.info "run #{task}", quiet: quiet do file = find_task(task) code = File.read(file) let :@file => file do instance_eval(code, file) end end end rescue TaskNotFound => e return if optional raise e end |
#set(hash) ⇒ Object
Merge the hash into the context variables.
67 68 69 |
# File 'lib/blower/context.rb', line 67 def set (hash) @data.merge! hash end |
#sh(command, as: user, on: hosts, quiet: false, once: nil) ⇒ Object
Execute a shell command on each host
137 138 139 140 141 142 143 144 145 |
# File 'lib/blower/context.rb', line 137 def sh (command, as: user, on: hosts, quiet: false, once: nil) self.once once, quiet: quiet do log.info "sh #{command}", quiet: quiet do hash_map(hosts) do |host| host.sh command, as: as, quiet: quiet end end end end |
#unset(*names) ⇒ Object
Remove context variables
59 60 61 62 63 |
# File 'lib/blower/context.rb', line 59 def unset (*names) names.each do |name| @data.delete name end end |
#with(hash, quiet: false) ⇒ Object
Yield with the hash temporary merged into the context variables. Only variables specifically named in hash will be reset when the yield returns.
76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/blower/context.rb', line 76 def with (hash, quiet: false) old_values = data.values_at(hash.keys) log.debug "with #{hash}", quiet: quiet do set hash yield end ensure hash.keys.each.with_index do |key, i| @data[key] = old_values[i] end end |
#write(string, to, as: user, on: hosts, quiet: false, once: nil) ⇒ Object
Writes a string to a file on the host filesystems.
195 196 197 198 199 200 201 202 203 |
# File 'lib/blower/context.rb', line 195 def write (string, to, as: user, on: hosts, quiet: false, once: nil) self.once once, quiet: quiet do log.info "write: #{string.bytesize} bytes -> #{to}", quiet: quiet do hash_map(hosts) do |host| host.write string, to, as: as, quiet: quiet end end end end |