lib/elecksee/lxc_file_config.rb in elecksee-1.1.8 vs lib/elecksee/lxc_file_config.rb in elecksee-2.0.0

- old
+ new

@@ -1,146 +1,102 @@ require 'elecksee' +require 'attribute_struct' -class Lxc - # Configuration file interface - class FileConfig +class LxcStruct < AttributeStruct - # @return [Array] - attr_reader :network - # @return [String] path to configuration file - attr_reader :base + def network(*args, &block) + unless(self[:network]) + set!(:network, ::AttributeStruct::CollapseArray.new) + self[:network].push(_klass_new) + end + if(self[:network].last._data[:type].is_a?(::AttributeStruct::CollapseArray)) + val = self[:network].last._data[:type].pop + self[:network].push(_klass_new) + self[:network].last.set!(:type, val) + end + self[:network].last + end - class << self + def _klass + ::LxcStruct + end - # Convert object to Hash if possible - # - # @param thing [Object] - # @return [Hash] - # @note used mostly for the lxc resource within chef - def convert_to_hash(thing) - if(defined?(Chef) && thing.is_a?(Chef::Resource)) - result = Hash[*( - (thing.methods - Chef::Resource.instance_methods).map{ |key| - unless(key.to_s.start_with?('_') || thing.send(key).nil?) - [key, thing.send(key)] - end - }.compact.flatten(1) - )] - else - unless(thing.is_a?(Hash)) - result = defined?(Mash) ? Mash.new : {} - thing.to_hash.each do |k,v| - result[k] = v.respond_to?(:keys) && v.respond_to?(:values) ? convert_to_hash(v) : v - end - end - end - result || thing - end +end - # Symbolize keys within hash - # - # @param thing [Hashish] - # @return [Hash] - def symbolize_hash(thing) - if(defined?(Mash)) - Mash.new(thing) - else - result = {} - thing.each do |k,v| - result[k.to_sym] = v.is_a?(Hash) ? symbolize_hash(v) : v - end - result - end - end +class Lxc + # Configuration file interface + class FileConfig - # Generate configuration file contents - # - # @param resource [Hashish] - # @return [String] - def generate_config(resource) - resource = symbolize_hash(convert_to_hash(resource)) - config = [] - config << "lxc.utsname = #{resource[:utsname]}" - if(resource[:aa_profile]) - config << "lxc.aa_profile = #{resource[:aa_profile]}" - end - [resource[:network]].flatten.each do |net_hash| - nhsh = Mash.new(net_hash) - flags = nhsh.delete(:flags) - %w(type link).each do |k| - config << "lxc.network.#{k} = #{nhsh.delete(k)}" if nhsh[k] - end - nhsh.each_pair do |k,v| - config << "lxc.network.#{k} = #{v}" - end - if(flags) - config << "lxc.network.flags = #{flags}" - end - end - if(resource[:cap_drop]) - config << "lxc.cap.drop = #{Array(resource[:cap_drop]).join(' ')}" - end - %w(include pts tty arch devttydir mount mount_entry rootfs rootfs_mount pivotdir).each do |k| - config << "lxc.#{k.sub('_', '.')} = #{resource[k.to_sym]}" if resource[k.to_sym] - end - prefix = 'lxc.cgroup' - resource[:cgroup].each_pair do |key, value| - if(value.is_a?(Array)) - value.each do |val| - config << "#{prefix}.#{key} = #{val}" - end - else - config << "#{prefix}.#{key} = #{value}" - end - end - config.join("\n") + "\n" - end + # @return [String] path to config file + attr_reader :path + # @return [AttrubuteStruct] config file contents + attr_accessor :state - end - # Create new instance # # @param path [String] def initialize(path) - raise 'LXC config file not found' unless File.exists?(path) @path = path - @network = [] - @base = defined?(Mash) ? Mash.new : {} - parse! + if(File.exists?(path)) + parse! + else + @state = LxcStruct.new + end end + # @return [Smash] hash like dump of state + def state_hash + state._dump.to_smash + end + + # Overwrite the config file + # + # @return [Integer] + def write! + File.write(path, generate_content) + end + + # Generate config file content from current value of state + # + # @return [String] + def generate_content + process_item(state_hash).flatten.join("\n") + end + private + # Convert item to configuration file line + # + # @param item [Object] + # @param parents [Array<String>] parent hash keys + # @return [Array<String>] + def process_item(item, parents=[]) + case item + when Hash + item.map do |k,v| + process_item(v, parents + [k]) + end + when Array + item.map do |v| + process_item(v, parents) + end + else + ["#{parents.join('.')} = #{item}"] + end + end + # Parse the configuration file # - # @return [TrueClass] + # @return [AttributeStruct] def parse! - cur_net = nil - File.readlines(@path).each do |line| - if(line.start_with?('lxc.network')) - parts = line.split('=') - name = parts.first.split('.').last.strip - if(name.to_sym == :type) - @network << cur_net if cur_net - cur_net = Mash.new - end - if(cur_net) - cur_net[name] = parts.last.strip - else - raise "Expecting 'lxc.network.type' to start network config block. Found: 'lxc.network.#{name}'" - end - else - parts = line.split('=') - name = parts.first.sub('lxc.', '').strip - if(@base[name]) - @base[name] = [@base[name], parts.last.strip].flatten - else - @base[name] = parts.last - end - end + struct = LxcStruct.new + struct._set_state(:value_collapse => true) + File.read(path).split("\n").each do |line| + parts = line.split('=').map(&:strip) + parts.last.replace("'#{parts.last}'") + struct.instance_eval(parts.join(' = ')) end - @network << cur_net if cur_net - true + @state = struct end end end