elecksee 1.1.8 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3c76cb776b49ae4be0b00557d87abbe6d82a9da7
4
- data.tar.gz: bc2bc7f0e9442eafde3541317b757411b81621ca
3
+ metadata.gz: 1fa238c10437677255df26d118e761553342b5a6
4
+ data.tar.gz: f22d8b320fde7d3a531728bf77b3613883d2e6d1
5
5
  SHA512:
6
- metadata.gz: 7a39c2bde1d990e87956fc80ca5681a018a0e81e139435cda4aa66dce4095c2dc2be68873a410fef276733dfe76efc2f4a5146c1b9523357549538df9bec9c15
7
- data.tar.gz: 272f78213b4d9c2b1ec5d447f57b16e1e6e79c66a302428e2ea037e4f847f578096347a54fb9a777bace9d7c72039f45c2b967b14f99e9e93333909e831fb098
6
+ metadata.gz: de48a9a73b02e227bffbc8f8094355157acdd54bdb1214f3e2b281009827de15ac4261cb084749a840f5b30a1090796eb036eace96badb3ef91d1237eee6d2d0
7
+ data.tar.gz: 2cd3efa4127547d4ecb1f5f09abf93dfad46313bd38a0baac1686fe29506908c9405d22398fdd4e72423862e34c0f7c262cca99ec2865e6186d487747f14d620
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## v2.0.0
2
+ * [fix] Use sudo helper when cloning
3
+ * [enhancement] Disable retry on ephemeral command
4
+ * [enhancement] Dynamic parsing/generation of configuration files
5
+ * [fix] Do not register traps when executing inline
6
+ * [fix] Synchronize childprocess access to prevent race
7
+
8
+ _WARNING: Updated configuration file handling may cause breakage_
9
+
1
10
  ## v1.1.8
2
11
  * Add `include` support for file config
3
12
 
data/elecksee.gemspec CHANGED
@@ -10,6 +10,8 @@ Gem::Specification.new do |s|
10
10
  s.description = 'LXC helpers'
11
11
  s.require_path = 'lib'
12
12
  s.executables = %w(lxc-awesome-ephemeral)
13
+ s.add_dependency 'bogo'
14
+ s.add_dependency 'attribute_struct'
13
15
  s.add_dependency 'childprocess'
14
16
  s.add_dependency 'rye'
15
17
  s.files = Dir['{bin,lib}/**/**/*'] + %w(elecksee.gemspec README.md CHANGELOG.md LICENSE CONTRIBUTING.md)
data/lib/elecksee.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'elecksee/version'
2
+ require 'bogo'
2
3
 
3
4
  # LXC interface
4
5
  class Lxc
@@ -93,7 +93,7 @@ class Lxc
93
93
  lxc.start
94
94
  if(ephemeral_command)
95
95
  lxc.wait_for_state(:running)
96
- lxc.container_command(ephemeral_command)
96
+ lxc.container_command(ephemeral_command, 0) # no retries on ephemeral commands
97
97
  else
98
98
  cli_output
99
99
  lxc.wait_for_state(:stopped)
@@ -137,7 +137,6 @@ class Lxc
137
137
  start_action
138
138
  end
139
139
  else
140
- register_traps
141
140
  start_action
142
141
  end
143
142
  true
@@ -194,7 +193,9 @@ class Lxc
194
193
  content << 'trap scrub SIGTERM SIGINT SIGQUIT'
195
194
  content << "lxc-start -n #{lxc.name} -d"
196
195
  content << 'sleep 1'
197
- content << "lxc-wait -n #{lxc.name} -s STOPPED"
196
+ content << 'until [ `lxc-wait -n #{lxc.name} -s STOPPED -t 2` ]'
197
+ content << 'do'
198
+ content << 'done'
198
199
  content << 'scrub'
199
200
  tmp = Tempfile.new('elecksee')
200
201
  tmp.chmod(0700)
@@ -4,6 +4,10 @@ class Lxc
4
4
  # Helper modules
5
5
  module Helpers
6
6
 
7
+ class << self
8
+ attr_accessor :child_process_lock
9
+ end
10
+
7
11
  autoload :Copies, 'elecksee/helpers/copies'
8
12
  autoload :Options, 'elecksee/helpers/options'
9
13
 
@@ -56,11 +60,14 @@ class Lxc
56
60
  s_err = Tempfile.new('stderr')
57
61
  s_out.sync
58
62
  s_err.sync
59
- c_proc = ChildProcess.build(*Shellwords.split(cmd))
60
- c_proc.environment.merge('HOME' => detect_home)
61
- c_proc.io.stdout = s_out
62
- c_proc.io.stderr = s_err
63
- c_proc.start
63
+ c_proc = nil
64
+ Lxc::Helpers.child_process_lock.synchronize do
65
+ c_proc = ChildProcess.build(*Shellwords.split(cmd))
66
+ c_proc.environment.merge('HOME' => detect_home)
67
+ c_proc.io.stdout = s_out
68
+ c_proc.io.stderr = s_err
69
+ c_proc.start
70
+ end
64
71
  begin
65
72
  c_proc.poll_for_exit(args[:timeout] || 1200)
66
73
  rescue ChildProcess::TimeoutError
@@ -228,3 +235,5 @@ class Lxc
228
235
 
229
236
  end
230
237
  end
238
+
239
+ Lxc::Helpers.child_process_lock = Mutex.new
@@ -1,145 +1,101 @@
1
1
  require 'elecksee'
2
+ require 'attribute_struct'
2
3
 
3
- class Lxc
4
- # Configuration file interface
5
- class FileConfig
4
+ class LxcStruct < AttributeStruct
6
5
 
7
- # @return [Array]
8
- attr_reader :network
9
- # @return [String] path to configuration file
10
- attr_reader :base
11
-
12
- class << self
6
+ def network(*args, &block)
7
+ unless(self[:network])
8
+ set!(:network, ::AttributeStruct::CollapseArray.new)
9
+ self[:network].push(_klass_new)
10
+ end
11
+ if(self[:network].last._data[:type].is_a?(::AttributeStruct::CollapseArray))
12
+ val = self[:network].last._data[:type].pop
13
+ self[:network].push(_klass_new)
14
+ self[:network].last.set!(:type, val)
15
+ end
16
+ self[:network].last
17
+ end
13
18
 
14
- # Convert object to Hash if possible
15
- #
16
- # @param thing [Object]
17
- # @return [Hash]
18
- # @note used mostly for the lxc resource within chef
19
- def convert_to_hash(thing)
20
- if(defined?(Chef) && thing.is_a?(Chef::Resource))
21
- result = Hash[*(
22
- (thing.methods - Chef::Resource.instance_methods).map{ |key|
23
- unless(key.to_s.start_with?('_') || thing.send(key).nil?)
24
- [key, thing.send(key)]
25
- end
26
- }.compact.flatten(1)
27
- )]
28
- else
29
- unless(thing.is_a?(Hash))
30
- result = defined?(Mash) ? Mash.new : {}
31
- thing.to_hash.each do |k,v|
32
- result[k] = v.respond_to?(:keys) && v.respond_to?(:values) ? convert_to_hash(v) : v
33
- end
34
- end
35
- end
36
- result || thing
37
- end
19
+ def _klass
20
+ ::LxcStruct
21
+ end
38
22
 
39
- # Symbolize keys within hash
40
- #
41
- # @param thing [Hashish]
42
- # @return [Hash]
43
- def symbolize_hash(thing)
44
- if(defined?(Mash))
45
- Mash.new(thing)
46
- else
47
- result = {}
48
- thing.each do |k,v|
49
- result[k.to_sym] = v.is_a?(Hash) ? symbolize_hash(v) : v
50
- end
51
- result
52
- end
53
- end
23
+ end
54
24
 
55
- # Generate configuration file contents
56
- #
57
- # @param resource [Hashish]
58
- # @return [String]
59
- def generate_config(resource)
60
- resource = symbolize_hash(convert_to_hash(resource))
61
- config = []
62
- config << "lxc.utsname = #{resource[:utsname]}"
63
- if(resource[:aa_profile])
64
- config << "lxc.aa_profile = #{resource[:aa_profile]}"
65
- end
66
- [resource[:network]].flatten.each do |net_hash|
67
- nhsh = Mash.new(net_hash)
68
- flags = nhsh.delete(:flags)
69
- %w(type link).each do |k|
70
- config << "lxc.network.#{k} = #{nhsh.delete(k)}" if nhsh[k]
71
- end
72
- nhsh.each_pair do |k,v|
73
- config << "lxc.network.#{k} = #{v}"
74
- end
75
- if(flags)
76
- config << "lxc.network.flags = #{flags}"
77
- end
78
- end
79
- if(resource[:cap_drop])
80
- config << "lxc.cap.drop = #{Array(resource[:cap_drop]).join(' ')}"
81
- end
82
- %w(include pts tty arch devttydir mount mount_entry rootfs rootfs_mount pivotdir).each do |k|
83
- config << "lxc.#{k.sub('_', '.')} = #{resource[k.to_sym]}" if resource[k.to_sym]
84
- end
85
- prefix = 'lxc.cgroup'
86
- resource[:cgroup].each_pair do |key, value|
87
- if(value.is_a?(Array))
88
- value.each do |val|
89
- config << "#{prefix}.#{key} = #{val}"
90
- end
91
- else
92
- config << "#{prefix}.#{key} = #{value}"
93
- end
94
- end
95
- config.join("\n") + "\n"
96
- end
25
+ class Lxc
26
+ # Configuration file interface
27
+ class FileConfig
97
28
 
98
- end
29
+ # @return [String] path to config file
30
+ attr_reader :path
31
+ # @return [AttrubuteStruct] config file contents
32
+ attr_accessor :state
99
33
 
100
34
  # Create new instance
101
35
  #
102
36
  # @param path [String]
103
37
  def initialize(path)
104
- raise 'LXC config file not found' unless File.exists?(path)
105
38
  @path = path
106
- @network = []
107
- @base = defined?(Mash) ? Mash.new : {}
108
- parse!
39
+ if(File.exists?(path))
40
+ parse!
41
+ else
42
+ @state = LxcStruct.new
43
+ end
44
+ end
45
+
46
+ # @return [Smash] hash like dump of state
47
+ def state_hash
48
+ state._dump.to_smash
49
+ end
50
+
51
+ # Overwrite the config file
52
+ #
53
+ # @return [Integer]
54
+ def write!
55
+ File.write(path, generate_content)
56
+ end
57
+
58
+ # Generate config file content from current value of state
59
+ #
60
+ # @return [String]
61
+ def generate_content
62
+ process_item(state_hash).flatten.join("\n")
109
63
  end
110
64
 
111
65
  private
112
66
 
67
+ # Convert item to configuration file line
68
+ #
69
+ # @param item [Object]
70
+ # @param parents [Array<String>] parent hash keys
71
+ # @return [Array<String>]
72
+ def process_item(item, parents=[])
73
+ case item
74
+ when Hash
75
+ item.map do |k,v|
76
+ process_item(v, parents + [k])
77
+ end
78
+ when Array
79
+ item.map do |v|
80
+ process_item(v, parents)
81
+ end
82
+ else
83
+ ["#{parents.join('.')} = #{item}"]
84
+ end
85
+ end
86
+
113
87
  # Parse the configuration file
114
88
  #
115
- # @return [TrueClass]
89
+ # @return [AttributeStruct]
116
90
  def parse!
117
- cur_net = nil
118
- File.readlines(@path).each do |line|
119
- if(line.start_with?('lxc.network'))
120
- parts = line.split('=')
121
- name = parts.first.split('.').last.strip
122
- if(name.to_sym == :type)
123
- @network << cur_net if cur_net
124
- cur_net = Mash.new
125
- end
126
- if(cur_net)
127
- cur_net[name] = parts.last.strip
128
- else
129
- raise "Expecting 'lxc.network.type' to start network config block. Found: 'lxc.network.#{name}'"
130
- end
131
- else
132
- parts = line.split('=')
133
- name = parts.first.sub('lxc.', '').strip
134
- if(@base[name])
135
- @base[name] = [@base[name], parts.last.strip].flatten
136
- else
137
- @base[name] = parts.last
138
- end
139
- end
91
+ struct = LxcStruct.new
92
+ struct._set_state(:value_collapse => true)
93
+ File.read(path).split("\n").each do |line|
94
+ parts = line.split('=').map(&:strip)
95
+ parts.last.replace("'#{parts.last}'")
96
+ struct.instance_eval(parts.join(' = '))
140
97
  end
141
- @network << cur_net if cur_net
142
- true
98
+ @state = struct
143
99
  end
144
100
 
145
101
  end
@@ -34,7 +34,7 @@ class Lxc
34
34
  # @return [TrueClass, FalseClass]
35
35
  def create
36
36
  unless(File.directory?(overlay_path))
37
- FileUtils.mkdir_p(overlay_path)
37
+ command("mkdir -p #{overlay_path}", :sudo => true)
38
38
  true
39
39
  else
40
40
  false
@@ -1,4 +1,4 @@
1
1
  module Elecksee
2
2
  # Current library version
3
- VERSION = Gem::Version.new('1.1.8')
3
+ VERSION = Gem::Version.new('2.0.0')
4
4
  end
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elecksee
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.8
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Roberts
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-08 00:00:00.000000000 Z
11
+ date: 2015-09-25 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bogo
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: attribute_struct
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: childprocess
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -83,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
83
111
  version: '0'
84
112
  requirements: []
85
113
  rubyforge_project:
86
- rubygems_version: 2.2.2
114
+ rubygems_version: 2.4.8
87
115
  signing_key:
88
116
  specification_version: 4
89
117
  summary: LXC helpers