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) ⇒ 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.
43 44 45 46 47 |
# File 'lib/blower/context.rb', line 43 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.
39 40 41 |
# File 'lib/blower/context.rb', line 39 def file @file end |
#hosts ⇒ Object
The target hosts.
32 33 34 |
# File 'lib/blower/context.rb', line 32 def hosts @hosts end |
#path ⇒ Object
Search path for tasks.
29 30 31 |
# File 'lib/blower/context.rb', line 29 def path @path end |
#user ⇒ Object
Username override. If not-nil, this user is used for all remote accesses.
35 36 37 |
# File 'lib/blower/context.rb', line 35 def user @user end |
Instance Method Details
#as(user, quiet: false) ⇒ Object
Yield with a temporary username override
99 100 101 102 103 104 105 |
# File 'lib/blower/context.rb', line 99 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.
161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/blower/context.rb', line 161 def cp (from, to, as: user, on: hosts, quiet: false, once: nil) 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 end end end end end |
#get(name, default = nil) ⇒ Object
Return a context variable.
52 53 54 |
# File 'lib/blower/context.rb', line 52 def get (name, default = nil) @data.fetch(name, default) end |
#on(*hosts, quiet: false) ⇒ Object
Yield with a temporary host list
89 90 91 92 93 94 95 |
# File 'lib/blower/context.rb', line 89 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.
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# File 'lib/blower/context.rb', line 246 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
231 232 233 234 235 236 237 |
# File 'lib/blower/context.rb', line 231 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.
179 180 181 182 183 184 185 |
# File 'lib/blower/context.rb', line 179 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.
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/blower/context.rb', line 212 def render (from, to, as: user, on: hosts, quiet: false, once: nil) self.once once, quiet: quiet do Dir.chdir File.dirname(file) do (Dir["#{from}**/*.erb"] + Dir["#{from}**/.*.erb"]).each do |path| 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 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.
116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/blower/context.rb', line 116 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.
66 67 68 |
# File 'lib/blower/context.rb', line 66 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
136 137 138 139 140 141 142 143 144 |
# File 'lib/blower/context.rb', line 136 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
58 59 60 61 62 |
# File 'lib/blower/context.rb', line 58 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.
75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/blower/context.rb', line 75 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.
194 195 196 197 198 199 200 201 202 |
# File 'lib/blower/context.rb', line 194 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 |