Class: Lxc
- Inherits:
-
Object
- Object
- Lxc
- Defined in:
- lib/vagabond/cookbooks/lxc/libraries/lxc.rb
Defined Under Namespace
Classes: CommandFailed
Class Attribute Summary collapse
-
.use_sudo ⇒ Object
Returns the value of attribute use_sudo.
Instance Attribute Summary collapse
-
#name ⇒ Object
readonly
Returns the value of attribute name.
Class Method Summary collapse
-
.connection_alive?(ip) ⇒ Boolean
- ip
-
IP address Returns if IP address is alive.
-
.exists?(name) ⇒ Boolean
- name
-
name of container Returns if container exists.
-
.frozen ⇒ Object
List frozen containers.
-
.full_list ⇒ Object
Return full container information list.
-
.info(name) ⇒ Object
- name
-
Name of container Returns information about given container.
-
.list ⇒ Object
List of containers.
-
.running ⇒ Object
List running containers.
-
.stopped ⇒ Object
List stopped containers.
- .sudo ⇒ Object
Instance Method Summary collapse
-
#container_command(cmd, retries = 1) ⇒ Object
- cmd
- Shell command string retries
-
Number of retry attempts (1 second sleep interval) Runs command in container via ssh.
-
#container_config ⇒ Object
(also: #config)
Full path to container configuration file.
-
#container_ip(retries = 0, raise_on_fail = false) ⇒ Object
- retries
-
Number of discovery attempt (3 second sleep intervals) Returns container IP.
-
#container_path ⇒ Object
(also: #path)
Full path to container.
- #container_rootfs ⇒ Object (also: #rootfs)
-
#exists? ⇒ Boolean
Returns if container exists.
- #expand_path(path) ⇒ Object
-
#freeze ⇒ Object
Freeze the container.
-
#frozen? ⇒ Boolean
Returns if container is frozen.
- #hw_detected_address ⇒ Object
-
#initialize(name, args = {}) ⇒ Lxc
constructor
- name
- name of container args
-
Argument hash - :base_path -> path to container directory - :dnsmasq_lease_file -> path to lease file.
- #knife_container(cmd, ip) ⇒ Object
-
#leased_address ⇒ Object
Container address via dnsmasq lease.
-
#lxc_stored_address ⇒ Object
Container address via lxc config file.
- #pid ⇒ Object
- #proc_detected_address(base = '/run/netns') ⇒ Object
-
#run_command(cmd, args = {}) ⇒ Object
Simple helper to shell out.
-
#running? ⇒ Boolean
Returns if container is running.
-
#shutdown ⇒ Object
Shutdown the container.
-
#start ⇒ Object
Start the container.
- #state ⇒ Object
-
#stop ⇒ Object
Stop the container.
-
#stopped? ⇒ Boolean
Returns if container is stopped.
- #sudo ⇒ Object
-
#unfreeze ⇒ Object
Unfreeze the container.
Constructor Details
#initialize(name, args = {}) ⇒ Lxc
- name
-
name of container
- args
-
Argument hash
- :base_path -> path to container directory
- :dnsmasq_lease_file -> path to lease file
81 82 83 84 85 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 81 def initialize(name, args={}) @name = name @base_path = args[:base_path] || '/var/lib/lxc' @lease_file = args[:dnsmasq_lease_file] || '/var/lib/misc/dnsmasq.leases' end |
Class Attribute Details
.use_sudo ⇒ Object
Returns the value of attribute use_sudo.
9 10 11 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 9 def use_sudo @use_sudo end |
Instance Attribute Details
#name ⇒ Object (readonly)
Returns the value of attribute name.
5 6 7 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 5 def name @name end |
Class Method Details
.connection_alive?(ip) ⇒ Boolean
- ip
-
IP address
Returns if IP address is alive
71 72 73 74 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 71 def connection_alive?(ip) %x{ping -c 1 -W 1 #{ip}} $?.exitstatus == 0 end |
.exists?(name) ⇒ Boolean
- name
-
name of container
Returns if container exists
37 38 39 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 37 def exists?(name) list.include?(name) end |
.frozen ⇒ Object
List frozen containers
31 32 33 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 31 def frozen full_list[:frozen] end |
.full_list ⇒ Object
Return full container information list
59 60 61 62 63 64 65 66 67 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 59 def full_list res = {} list.each do |item| item_info = info(item) res[item_info[:state]] ||= [] res[item_info[:state]] << item end res end |
.info(name) ⇒ Object
- name
-
Name of container
Returns information about given container
48 49 50 51 52 53 54 55 56 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 48 def info(name) res = {:state => nil, :pid => nil} info = %x{#{sudo}lxc-info -n #{name}}.split("\n") parts = info.first.split(' ') res[:state] = parts.last.downcase.to_sym parts = info.last.split(' ') res[:pid] = parts.last.to_i res end |
.list ⇒ Object
List of containers
42 43 44 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 42 def list %x{#{sudo}lxc-ls}.split("\n").uniq end |
.running ⇒ Object
List running containers
21 22 23 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 21 def running full_list[:running] end |
.stopped ⇒ Object
List stopped containers
26 27 28 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 26 def stopped full_list[:stopped] end |
.sudo ⇒ Object
11 12 13 14 15 16 17 18 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 11 def sudo case use_sudo when TrueClass 'sudo ' when String "#{use_sudo} " end end |
Instance Method Details
#container_command(cmd, retries = 1) ⇒ Object
- cmd
-
Shell command string
- retries
-
Number of retry attempts (1 second sleep interval)
Runs command in container via ssh
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 295 def container_command(cmd, retries=1) begin knife_container(cmd, container_ip(5)) rescue => e if(retries.to_i > 0) Chef::Log.info "Encountered error running container command (#{cmd}): #{e}" Chef::Log.info "Retrying command..." retries = retries.to_i - 1 sleep(1) retry else raise e end end end |
#container_config ⇒ Object Also known as: config
Full path to container configuration file
197 198 199 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 197 def container_config File.join(container_path, 'config') end |
#container_ip(retries = 0, raise_on_fail = false) ⇒ Object
- retries
-
Number of discovery attempt (3 second sleep intervals)
Returns container IP
109 110 111 112 113 114 115 116 117 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 109 def container_ip(retries=0, raise_on_fail=false) (retries.to_i + 1).times do ip = proc_detected_address || hw_detected_address || leased_address || lxc_stored_address return ip if ip && self.class.connection_alive?(ip) Chef::Log.warn "LXC IP discovery: Failed to detect live IP" sleep(3) if retries > 0 end raise "Failed to detect live IP address for container: #{name}" if raise_on_fail end |
#container_path ⇒ Object Also known as: path
Full path to container
191 192 193 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 191 def container_path File.join(@base_path, name) end |
#container_rootfs ⇒ Object Also known as: rootfs
202 203 204 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 202 def container_rootfs File.join(container_path, 'rootfs') end |
#exists? ⇒ Boolean
Returns if container exists
88 89 90 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 88 def exists? self.class.exists?(name) end |
#expand_path(path) ⇒ Object
207 208 209 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 207 def (path) File.join(container_rootfs, path) end |
#freeze ⇒ Object
Freeze the container
232 233 234 235 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 232 def freeze run_command("#{sudo}lxc-freeze -n #{name}") run_command("#{sudo}lxc-wait -n #{name} -s FROZEN", :allow_failure_retry => 2) end |
#frozen? ⇒ Boolean
Returns if container is frozen
103 104 105 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 103 def frozen? self.class.info(name)[:state] == :frozen end |
#hw_detected_address ⇒ Object
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 153 def hw_detected_address hw = File.readlines(container_config).detect{|line| line.include?('hwaddr') }.to_s.split('=').last.to_s.downcase if(File.exists?(container_config) && !hw.empty?) running? # need to do a list! ip = File.readlines('/proc/net/arp').detect{|line| line.downcase.include?(hw) }.to_s.split(' ').first.to_s.strip if(ip.to_s.empty?) nil else Chef::Log.info "LXC Discovery: Found container address via HW addr: #{ip}" ip end end end |
#knife_container(cmd, ip) ⇒ Object
253 254 255 256 257 258 259 260 261 262 263 264 265 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 253 def knife_container(cmd, ip) require 'chef/knife/ssh' Chef::Knife::Ssh.load_deps k = Chef::Knife::Ssh.new([ ip, '-m', '-i', '/opt/hw-lxc-config/id_rsa', '--no-host-key-verify', cmd ]) e = nil begin e = k.run rescue SystemExit => e end raise CommandFailed.new(cmd) if e.nil? || e != 0 end |
#leased_address ⇒ Object
Container address via dnsmasq lease
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 135 def leased_address ip = nil if(File.exists?(@lease_file)) leases = File.readlines(@lease_file).map{|line| line.split(' ')} leases.each do |lease| if(lease.include?(name)) ip = lease[2] end end end if(ip.to_s.empty?) nil else Chef::Log.info "LXC Discovery: Found container address via DHCP lease: #{ip}" ip end end |
#lxc_stored_address ⇒ Object
Container address via lxc config file
120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 120 def lxc_stored_address if(File.exists?(container_config)) ip = File.readlines(container_config).detect{|line| line.include?('ipv4') }.to_s.split('=').last.to_s.strip if(ip.to_s.empty?) nil else Chef::Log.info "LXC Discovery: Found container address via storage: #{ip}" ip end end end |
#pid ⇒ Object
215 216 217 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 215 def pid self.class.info(name)[:pid] end |
#proc_detected_address(base = '/run/netns') ⇒ Object
171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 171 def proc_detected_address(base='/run/netns') if(pid != -1) Dir.mktmpdir do |t_dir| name = File.basename(t_dir) path = File.join(base, name) system("#{sudo}mkdir -p #{base}") system("#{sudo}ln -s /proc/#{pid}/ns/net #{path}") res = %x{#{sudo}ip netns exec #{name} ip -4 addr show scope global | grep inet} system("#{sudo}rm -f #{path}") ip = res.strip.split(' ')[1].to_s.sub(%r{/.*$}, '').strip ip.empty? ? nil : ip end end end |
#run_command(cmd, args = {}) ⇒ Object
Simple helper to shell out
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 268 def run_command(cmd, args={}) retries = args[:allow_failure_retry].to_i begin shlout = Mixlib::ShellOut.new(cmd, :logger => Chef::Log.logger, :live_stream => STDOUT, :timeout => args[:timeout] || 1200 ) shlout.run_command shlout.error! rescue Mixlib::ShellOut::ShellCommandFailed, CommandFailed, Mixlib::ShellOut::CommandTimeout if(args[:allow_failure]) true elsif(retries > 0) Chef::Log.warn "LXC run command failed: #{cmd}" Chef::Log.warn "Retrying command. #{args[:allow_failure_retry].to_i - retries} of #{args[:allow_failure_retry].to_i} retries remain" retries -= 1 retry else raise end end end |
#running? ⇒ Boolean
Returns if container is running
93 94 95 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 93 def running? self.class.info(name)[:state] == :running end |
#shutdown ⇒ Object
Shutdown the container
244 245 246 247 248 249 250 251 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 244 def shutdown run_command("#{sudo}lxc-shutdown -n #{name}") run_command("#{sudo}lxc-wait -n #{name} -s STOPPED", :allow_failure => true, :timeout => 10) if(running?) container_command('shutdown -h now') run_command("#{sudo}lxc-wait -n #{name} -s STOPPED") end end |
#start ⇒ Object
Start the container
220 221 222 223 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 220 def start run_command("#{sudo}lxc-start -n #{name} -d") run_command("#{sudo}lxc-wait -n #{name} -s RUNNING", :allow_failure_retry => 2) end |
#state ⇒ Object
211 212 213 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 211 def state self.class.info(name)[:state] end |
#stop ⇒ Object
Stop the container
226 227 228 229 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 226 def stop run_command("#{sudo}lxc-stop -n #{name}") run_command("#{sudo}lxc-wait -n #{name} -s STOPPED", :allow_failure_retry => 2) end |
#stopped? ⇒ Boolean
Returns if container is stopped
98 99 100 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 98 def stopped? self.class.info(name)[:state] == :stopped end |
#sudo ⇒ Object
186 187 188 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 186 def sudo self.class.sudo end |
#unfreeze ⇒ Object
Unfreeze the container
238 239 240 241 |
# File 'lib/vagabond/cookbooks/lxc/libraries/lxc.rb', line 238 def unfreeze run_command("#{sudo}lxc-unfreeze -n #{name}") run_command("#{sudo}lxc-wait -n #{name} -s RUNNING", :allow_failure_retry => 2) end |