Class: Distem::Node::Container
- Inherits:
-
Object
- Object
- Distem::Node::Container
- Defined in:
- lib/distem/node/container.rb
Overview
Class that allow to manage all container (cgroup/lxc) associated physical and virtual resources
Constant Summary
- MAX_SIMULTANEOUS_ACTIONS =
The maximum simultaneous actions (start,stop)
32
- MAX_SIMULTANEOUS_CONFIG =
32
- SSH_KEY_PREFIX =
The prefix to set to the SSH key whick are copied on the virtual nodes
''
- SSH_KEY_FILENAME =
The default file to save virtual node specific ssh key pair (see Distem::Resource::VNode::sshkey)
'identity'
- @@cleanlock =
Clean only one time
Mutex.new
- @@cleaned =
Was the system cleaned
false
- @@filelock =
Only write on common files once at the same time
Mutex.new
- @@contsem =
Max number of simultaneous action
Lib::Semaphore.new(MAX_SIMULTANEOUS_ACTIONS)
- @@confsem =
Max number of simultaneous config action
Lib::Semaphore.new(MAX_SIMULTANEOUS_CONFIG)
Instance Attribute Summary (collapse)
-
- (Object) cpuforge
readonly
The object used to set up physical CPU limitations.
-
- (Object) fsforge
readonly
The object used to set up physical filesystem.
-
- (Object) networkforges
readonly
The object used to set up network limitations.
-
- (Object) vnode
readonly
The virtual node this container is set for.
Class Method Summary (collapse)
-
+ (Object) clean
Clean every previously created containers (previous distem run, lxc, …).
Instance Method Summary (collapse)
-
- (Object) configure(distempnode)
Congigure a virtual node (set LXC config files, …) on a physical machine.
-
- (Object) destroy
Remove and shutdown the virtual node, remove it's filesystem, …
- - (Object) freeze
-
- (Container) initialize(vnode)
constructor
Create a new Container and associate it to a virtual node ==== Attributes *
vnode
The VNode object. -
- (Object) reconfigure
Update and reconfigure a virtual node (if the was some changes in the virtual resources description).
-
- (Object) remove
Stop and Remove every physical resources that should be associated to the virtual node associated with this container (cgroups,lxc,…).
- - (Object) set_global_arptable(data, file)
- - (Object) set_global_etchosts(data)
-
- (Object) setup
Setup the virtual node container (copy ssh keys, …).
-
- (Object) start
Start all the resources associated to a virtual node (Run the virtual node).
-
- (Object) stop
Stop all the resources associated to a virtual node (Shutdown the virtual node).
- - (Object) unfreeze
Constructor Details
- (Container) initialize(vnode)
Create a new Container and associate it to a virtual node
Attributes
-
vnode
The VNode object
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/distem/node/container.rb', line 42 def initialize(vnode) raise unless vnode.is_a?(Resource::VNode) raise Lib::UninitializedResourceError, "vfilesystem/image" unless vnode.filesystem @vnode = vnode @fsforge = FileSystemForge.new(@vnode) raise Lib::ResourceNotFoundError, @vnode.filesystem.path if \ !File.exist?(@vnode.filesystem.path) and !File.exist?(@vnode.filesystem.sharedpath) @cpuforge = CPUForge.new(@vnode,@vnode.host.algorithms[:cpu]) @networkforges = {} @vnode.vifaces.each do |viface| @networkforges[viface] = NetworkForge.new(viface) end @curname = "" @configfile = "" @id = 0 setup() @stopped = false end |
Instance Attribute Details
- (Object) cpuforge (readonly)
The object used to set up physical CPU limitations
32 33 34 |
# File 'lib/distem/node/container.rb', line 32 def cpuforge @cpuforge end |
- (Object) fsforge (readonly)
The object used to set up physical filesystem
34 35 36 |
# File 'lib/distem/node/container.rb', line 34 def fsforge @fsforge end |
- (Object) networkforges (readonly)
The object used to set up network limitations
36 37 38 |
# File 'lib/distem/node/container.rb', line 36 def networkforges @networkforges end |
- (Object) vnode (readonly)
The virtual node this container is set for
30 31 32 |
# File 'lib/distem/node/container.rb', line 30 def vnode @vnode end |
Class Method Details
+ (Object) clean
Clean every previously created containers (previous distem run, lxc, …)
128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/distem/node/container.rb', line 128 def self.clean unless @@cleaned if (@@cleanlock.locked?) @@cleanlock.synchronize{} else @@cleanlock.synchronize { LXCWrapper::Command.clean() } end @@cleaned = true end end |
Instance Method Details
- (Object) configure(distempnode)
Congigure a virtual node (set LXC config files, …) on a physical machine
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
# File 'lib/distem/node/container.rb', line 234 def configure(distempnode) @@confsem.synchronize do rootfspath = nil if @vnode.filesystem.shared rootfspath = @vnode.filesystem.sharedpath else rootfspath = @vnode.filesystem.path end @curname = "#{@vnode.name}-#{@id}" # Generate lxc configfile configfile = File.join(FileSystemForge::PATH_DEFAULT_CONFIGFILE, "config-#{@curname}") LXCWrapper::ConfigFile.generate(@vnode,configfile,distempnode) etcpath = File.join(rootfspath,'etc') # Make hostname local unless @vnode.filesystem.shared File.open(File.join(etcpath,'hosts'),'a') do |f| f.puts("127.0.0.1\t#{@vnode.name}") f.puts("::1\t#{@vnode.name}") end end block = Proc.new { # Make address local @vnode.vifaces.each do |viface| if viface.vnetwork File.open(File.join(etcpath,'hosts'),'a') do |f| f.puts("#{viface.address.address.to_s}\t#{@vnode.name}") end end end # Load config in rc.local filename = File.join(etcpath,'rc.local') cmd = '. /etc/rc.local-`hostname`' ret = Lib::Shell.run("grep '#{cmd}' #{filename}; true",true) if ret.empty? File.open(filename,File::WRONLY|File::TRUNC|File::CREAT, 0755) { |f| f.puts("#!/bin/sh -ex\n") f.puts(cmd) f.puts("exit 0") } end # Make the file executable even if it was already existing. rc.local is 644 by default. FileUtils.chmod(0755, filename) } if @vnode.filesystem.shared @@filelock.synchronize { block.call } else block.call end # Node specific rc.local filename = File.join(etcpath,"rc.local-#{@vnode.name}") File.open(filename,File::WRONLY|File::TRUNC|File::CREAT, 0755) { |f| f.puts("#!/bin/sh -ex\n") f.puts("echo 1 > /proc/sys/net/ipv4/ip_forward") if @vnode.gateway? @vnode.vifaces.each do |viface| if viface.vnetwork addr = viface.address f.puts("ifconfig #{viface.name} #{addr.address.to_s} netmask #{addr.netmask.to_s} broadcast #{addr.broadcast.to_s}") f.puts("ip route flush dev #{viface.name}") f.puts("ip route add #{viface.vnetwork.address.to_string} dev #{viface.name}") #compute all routes viface.vnetwork.vroutes.each_value do |vroute| f.puts("ip route add #{vroute.dstnet.address.to_string} via #{vroute.gw.address.to_s} dev #{viface.name}") unless vroute.gw.address.to_s == viface.address.to_s end end f.puts("#iptables -t nat -A POSTROUTING -o #{viface.name} -j MASQUERADE") if vnode.gateway? end f.puts("exit 0") } LXCWrapper::Command.create(@vnode.name,configfile) @id += 1 end end |
- (Object) destroy
Remove and shutdown the virtual node, remove it's filesystem, …
198 199 200 201 |
# File 'lib/distem/node/container.rb', line 198 def destroy stop() if !@stopped remove() end |
- (Object) freeze
203 204 205 |
# File 'lib/distem/node/container.rb', line 203 def freeze LXCWrapper::Command.freeze(@vnode.name) end |
- (Object) reconfigure
Update and reconfigure a virtual node (if the was some changes in the virtual resources description)
212 213 214 215 |
# File 'lib/distem/node/container.rb', line 212 def reconfigure @cpuforge.apply @networkforges.each_value { |netforge| netforge.apply } end |
- (Object) remove
Stop and Remove every physical resources that should be associated to the virtual node associated with this container (cgroups,lxc,…)
187 188 189 190 191 192 193 194 195 |
# File 'lib/distem/node/container.rb', line 187 def remove LXCWrapper::Command.destroy(@vnode.name,true) if !@vnode.filesystem.shared && @vnode.filesystem.cow # The subvolume deletion is performed automatically by LXC in the Jessie version. if File.exist?(@vnode.filesystem.path) Lib::Shell.run("btrfs subvolume delete #{@vnode.filesystem.path}") end end end |
- (Object) set_global_arptable(data, file)
225 226 227 228 229 230 231 |
# File 'lib/distem/node/container.rb', line 225 def set_global_arptable(data, file) rootfspath = @vnode.filesystem.shared ? @vnode.filesystem.sharedpath : @vnode.filesystem.path path = File.join(rootfspath, file) File.open(path,'w') {|f| f.write(data + "\n") } end |
- (Object) set_global_etchosts(data)
217 218 219 220 221 222 223 |
# File 'lib/distem/node/container.rb', line 217 def set_global_etchosts(data) rootfspath = @vnode.filesystem.shared ? @vnode.filesystem.sharedpath : @vnode.filesystem.path etcpath = File.join(rootfspath,'etc') File.open(File.join(etcpath,'hosts'),'w') {|f| f.write(data + "\n") } end |
- (Object) setup
Setup the virtual node container (copy ssh keys, …)
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/distem/node/container.rb', line 65 def setup() rootfspath = nil if @vnode.filesystem.shared rootfspath = @vnode.filesystem.sharedpath else rootfspath = @vnode.filesystem.path end sshpath = File.join(rootfspath,'root','.ssh') # Creating SSH directory unless File.exist?(sshpath) Lib::Shell.run("mkdir -p #{sshpath}") end # Copying every private keys if not already existing Daemon::Admin.ssh_keys_priv.each do |keyfile| keypath=File.join(sshpath,"#{SSH_KEY_PREFIX}#{File.basename(keyfile)}") Lib::Shell.run("cp #{keyfile} #{keypath}") unless File.exist?(keypath) end File.open(File.join(sshpath,SSH_KEY_FILENAME),'w') do |f| f.puts @vnode.sshkey['private'] end if @vnode.sshkey and @vnode.sshkey['private'] # Copying every public keys if not already existing Daemon::Admin.ssh_keys_pub.each do |keyfile| keypath=File.join(sshpath,"#{SSH_KEY_PREFIX}#{File.basename(keyfile)}") Lib::Shell.run("cp #{keyfile} #{keypath}") unless File.exist?(keypath) end File.open(File.join(sshpath,"#{SSH_KEY_FILENAME}.pub"),'w') do |f| f.puts @vnode.sshkey['public'] end if @vnode.sshkey and @vnode.sshkey['public'] # Copying authorized_keys file of the host hostauthfile = File.join(Daemon::Admin::PATH_SSH,'authorized_keys') authfile = File.join(sshpath,'authorized_keys') if File.exist?(authfile) authkeys = IO.readlines(authfile).collect{|v| v.chomp} hostauthkeys = IO.readlines(hostauthfile).collect{|v| v.chomp} hostauthkeys.each do |key| File.open(authfile,'a') { |f| f.puts key } unless \ authkeys.include?(key) end else Lib::Shell.run("cp -f #{hostauthfile} #{authfile}") if File.exist?(hostauthfile) end # Adding public keys to SSH authorized_keys file pubkeys = Daemon::Admin.ssh_keys_pub.collect{ |v| IO.read(v).chomp } pubkeys << @vnode.sshkey['public'] if @vnode.sshkey and @vnode.sshkey['public'] if File.exist?(authfile) authkeys = IO.readlines(authfile).collect{|v| v.chomp} unless authkeys pubkeys.each do |key| File.open(authfile,'a') { |f| f.puts key } unless \ authkeys.include?(key) end else pubkeys.each do |key| File.open(authfile,'a') { |f| f.puts key } end end end |
- (Object) start
Start all the resources associated to a virtual node (Run the virtual node)
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/distem/node/container.rb', line 142 def start raise @vnode.name if @vnode.status == Resource::Status::RUNNING @@contsem.synchronize do LXCWrapper::Command.start(@vnode.name) @vnode.vifaces.each do |viface| Lib::Shell::run("ethtool -K #{Lib::NetTools.get_iface_name(@vnode,viface)} gso off || true") Lib::Shell::run("ethtool -K #{Lib::NetTools.get_iface_name(@vnode,viface)} tso off || true") end @cpuforge.apply @networkforges.each_value { |netforge| netforge.apply } end if @vnode.filesystem.disk_throttling # On jessie, this does not return a correct value ... #major = File.stat(@vnode.filesystem.disk_throttling['device']).dev_major major = `stat --printf %t #{@vnode.filesystem.disk_throttling['device']}` cgroup_path = File.join(Distem::Node::Admin::PATH_CGROUP, 'lxc', @vnode.name) # In the description, read and write limits are supposed to be specified in bytes if @vnode.filesystem.disk_throttling['read_limit'] limit = @vnode.filesystem.disk_throttling['read_limit'].to_i Lib::Shell::run("echo \"#{major}:0 #{limit}\" > #{cgroup_path}/blkio.throttle.read_bps_device") end if @vnode.filesystem.disk_throttling['write_limit'] limit = @vnode.filesystem.disk_throttling['write_limit'].to_i Lib::Shell::run("echo \"#{major}:0 #{limit}\" > #{cgroup_path}/blkio.throttle.write_bps_device") end end @stopped = false end |
- (Object) stop
Stop all the resources associated to a virtual node (Shutdown the virtual node)
172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/distem/node/container.rb', line 172 def stop if @vnode.filesystem.disk_throttling cgroup_path = File.join(Distem::Node::Admin::PATH_CGROUP, 'lxc', @vnode.name) Lib::Shell::run("echo -n > #{cgroup_path}/blkio.throttle.read_bps_device") if @vnode.filesystem.disk_throttling['read_limit'] Lib::Shell::run("echo -n > #{cgroup_path}/blkio.throttle.write_bps_device") if @vnode.filesystem.disk_throttling['write_limit'] end @@contsem.synchronize do @cpuforge.undo @networkforges.each_value { |netforge| netforge.undo } LXCWrapper::Command.stop(@vnode.name) end @stopped = true end |
- (Object) unfreeze
207 208 209 |
# File 'lib/distem/node/container.rb', line 207 def unfreeze LXCWrapper::Command.unfreeze(@vnode.name) end |