lxd-common 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 3ca7ef26b1a5f3811c395b2c90ab29bf5f0e8127
4
- data.tar.gz: 56e6fd7f480fd6278bb011ba1052bebcea703172
2
+ SHA256:
3
+ metadata.gz: 2862f300294934ad732a85a91460a901ddca30a1371b59f3c52d4823f845ba22
4
+ data.tar.gz: cf9f7a414093dce415a457d144ea222ae8bc5e106d18df00a9d0510c61876ce2
5
5
  SHA512:
6
- metadata.gz: c2719010fc06f675be0ae6c8720ecb5144119f962a4be36392a4b8e9c404532f784c81a3a3ef237a761d5cb70ca2dea2b8cf3afd3c7f6a62dfce11724d56b311
7
- data.tar.gz: ffccf9fa39e661c337be6e04145da71dda189612db57fb87e21aba68e185e97f476af06e0f5b84517b5a4547b3e89436f61d0afea5277d5e1b20e66170a938eb
6
+ metadata.gz: d21f7a64be74067ff98a0170f0acb5006c1827000c3cc5dbe87f944c74fd362fd1b20202b3936e36ea84544b53159122b565732065a63d764f2bee5838a185fc
7
+ data.tar.gz: 91f6e12a53b3255b53f04dd875777b79c548d01aa4c88fcae6e5a240a45071704e1ab62c84480e56bb251627e7054df675a9cebe697c7e5a93a2d0485f346267
data/.gitignore CHANGED
@@ -1,6 +1,6 @@
1
1
  /.bundle/
2
2
  /.yardoc
3
- /Gemfile.lock
3
+ *.lock
4
4
  /_yardoc/
5
5
  /coverage/
6
6
  /doc/
data/.travis.yml CHANGED
@@ -9,7 +9,6 @@ matrix:
9
9
  allow_failures:
10
10
  - rvm: ruby-head
11
11
  before_install:
12
- - gem update --system
13
12
  - curl -L https://www.chef.io/chef/install.sh | sudo bash
14
13
  - sudo chef-apply spec/provision_recipe.rb
15
14
  - ip a && ip r
@@ -26,3 +25,11 @@ after_script:
26
25
  notifications:
27
26
  slack:
28
27
  secure: cMKi0hpXPZt8loD84alldIn3FCB0XBwHyOmh94MYnJ2GwtqGmrdDod5WLa36123z6XaDqpX0d/kXUZGWoVPTRK5QKWzlp/2bR6ZNGcWGFtB37UCjDweF9NRKgi56Nn2z3ws7qz/tG0MtH2991KjBh+Q5StaKHSTSh5BTHkLXFJ+YSW4ucY0PUctenF0sAz6vrLVNiYyrfWlGG6JBAd5LjinB6NdZHIDAl3yZ+IGrfxLXKAbLDgWcEVbXGOpQ0XSe7jiAzg7gi1ofOYuOR7JJzemQ8BzT6X42KPAAJxySz04UrTtxWkIPfX1OMwjlJB3RL932H+Ovv5KtU96VG8Z9npPK8li5uWYFLTwesH86sT1Kuah5Ct46D9d1LpZUzFt+sntGAQ5RY90QDItbr2OvkvPQ2kKjQpAsPb80x60yyhzWsJ3kZVejIuxv6pM7KF0hF1IHjj8YGRFtZxZx8NyYCoZaSUZQ+vl4djyHpvnKViNcXckgsMlJtQKfeluY1lOjGvciLctP/6rVKbOjGeENZc8TcwpnCZtmmBgrzW8wnY2/7f8q/kMILNqfu5YXTFQRYoJ3Nn7NP8oWlZ/hJN+Zt0ywIcxTswwzNfEM2/H8A4dSp8YZlI0kf09nAsLAgPQmaRcZjl8INzmlHEfy8vD+ooNDoPt7m7DlPpcNPKWzwjQ=
28
+ deploy:
29
+ provider: rubygems
30
+ api_key:
31
+ secure: ggaLaFKzqIR4B8ofCVwEXAdEwgnvzDx++UTRS6hVNsLVA6QQxl4EmZvOhX/Dfv/M/CaeWSB5N04Rlo4h95KkCmCh4UHH9aCK/N5CK2NpbVuyVF8JVOiCaqEvGkPcQ6kHZE53E1w+xU6ag/I97ZXxwO0biSCiTgeFXXKPotXtBbDk2Kr3CPJ7zw5ry7n3ZBWeqrkoVzatBBLL+SONSnDvkL/rqVqffdYmyDz4Y/8tcn/Suk+FesARid4/J6DPgINgE4jNBu9VLwwb29QyN0hJAsE1csbEaOGXoI8xm444PF2HHlZdlfkpNf0ecX8h60mPqEKAztZLWT86asMrD337dpdVkWmQEgGU1bq4CGtJMqnGP4Yw+Qmip+jYaJu1Cc9/IKy/SzdtA4zzSjljrj3THxlnMMYILp50q9r+qyOPNoab3KutTis1ZOqD08pfQEfgsVVjmoSOFjRjbVMIVk89Si5pqehMdZKyV2n3KdEbyG/2MCsNDuBlV9ZaYShCMxSsDOo/x9vRwAP/E2Byud76crcoqGKS3if9oPj+bPPTjSLbYkSzoCYkus9TVp4sV43vgQ7FR9QwEY5oGQbSMdAXp65d43/SmSFRhBTqT6E4yfc18ivSyz6m0/ItHXTQHzHdfjfp5M2wnOWzWGO6oYM07L+XIWwUpzAI+KiXcRYe7PE=
32
+ gem: lxd-common
33
+ on:
34
+ tags: true
35
+ rvm: 2.4.2
data/Vagrantfile CHANGED
@@ -4,11 +4,7 @@
4
4
  Vagrant.configure('2') do |config|
5
5
  config.vm.box = 'ubuntu/xenial64'
6
6
  # config.vm.box = 'ubuntu/trusty64'
7
- # config.vm.provider 'virtualbox' do |vb|
8
- # vb.memory = '512'
9
- # end
10
7
 
11
- # apt-get install -y -t xenial-backports lxd lxd-client
12
8
  config.vm.provision 'chef_apply' do |chef|
13
9
  chef.recipe = File.read 'spec/provision_recipe.rb'
14
10
  end
data/bin/console CHANGED
File without changes
data/bin/setup CHANGED
File without changes
@@ -86,14 +86,19 @@ module NexusSW
86
86
 
87
87
  def delete_container(container_id)
88
88
  return unless container_exists? container_id
89
- stop_container container_id, force: true
90
-
91
- # overcome a race condition where the host is busy doing 'something' async causing the delete command to pop an error
92
- # https://github.com/lxc/lxd/issues/4063
93
- # sleep 1
94
-
95
- id = @hk.delete_container(container_id, sync: false)[:id]
96
- @hk.wait_for_operation id
89
+ stop_container container_id, force: true
90
+
91
+ # ISSUE 17: something upstream is causing a double-tap on the REST endpoint
92
+ begin
93
+ @hk.delete_container container_id
94
+ rescue ::Faraday::ConnectionFailed, ::Hyperkit::BadRequest
95
+ LXD.with_timeout_and_retries timeout: 120 do
96
+ loop do
97
+ return unless container_exists? container_id
98
+ sleep 0.3
99
+ end
100
+ end
101
+ end
97
102
  end
98
103
 
99
104
  def container_status(container_id)
@@ -110,10 +115,7 @@ module NexusSW
110
115
  end
111
116
 
112
117
  def container_exists?(container_id)
113
- return true if container_status(container_id)
114
- return false
115
- rescue
116
- false
118
+ hk.containers.include? container_id
117
119
  end
118
120
 
119
121
  protected
@@ -19,7 +19,7 @@ module NexusSW
19
19
 
20
20
  include Helpers::UploadFolder
21
21
 
22
- def execute(command, options = {})
22
+ def execute(command, options = {}, &block)
23
23
  mycommand = command.is_a?(Array) ? command.join(' ') : command
24
24
  subcommand = options[:subcommand] || "exec #{container_name} --"
25
25
  mycommand = "lxc #{subcommand} #{mycommand}"
@@ -27,13 +27,13 @@ module NexusSW
27
27
  # We would have competing timeout logic depending on who the inner transport is
28
28
  # I'll just let rest & local do the timeouts, and if inner is a chef sourced transport, they have timeout logic of their own
29
29
  # with_timeout_and_retries(options) do
30
- inner_transport.execute mycommand, options
30
+ inner_transport.execute mycommand, options, &block
31
31
  end
32
32
 
33
33
  def read_file(path)
34
34
  tfile = inner_mktmp
35
35
  retval = execute("#{@container_name}#{path} #{tfile}", subcommand: 'file pull', capture: false)
36
- return '' if retval.exitstatus == 1
36
+ # return '' if retval.exitstatus == 1
37
37
  retval.error!
38
38
  return inner_transport.read_file tfile
39
39
  ensure
@@ -67,8 +67,8 @@ module NexusSW
67
67
  end
68
68
 
69
69
  def upload_folder(local_path, path)
70
- return super unless config[:info] && config[:info][:api_extensions] && config[:info][:api_extensions].include?('directory_manipulation')
71
- execute("-r #{localname} #{container_name}#{path}", subcommand: 'file push', capture: false).error!
70
+ return super unless config[:info] && config[:info]['api_extensions'] && config[:info]['api_extensions'].include?('directory_manipulation')
71
+ execute("-r #{local_path} #{container_name}#{path}", subcommand: 'file push', capture: false).error!
72
72
  end
73
73
 
74
74
  def add_remote(host_name)
@@ -11,7 +11,7 @@ module NexusSW
11
11
  @exitstatus = exitstatus
12
12
  end
13
13
 
14
- attr_reader :exitstatus, :options, :command
14
+ attr_reader :options, :command, :exitstatus
15
15
 
16
16
  def stdout
17
17
  options[:capture_options][:stdout] if options.key? :capture_options
@@ -24,8 +24,8 @@ module NexusSW
24
24
  def error!
25
25
  return self if exitstatus == 0
26
26
  msg = "Error: '#{command}' failed with exit code #{exitstatus}.\n"
27
- msg += "STDOUT: #{stdout}" if stdout && !stdout.empty?
28
- msg += "STDERR: #{stderr}" if stderr && !stderr.empty?
27
+ msg += "STDOUT: #{stdout}" if stdout.is_a?(String) && !stdout.empty?
28
+ msg += "STDERR: #{stderr}" if stderr.is_a?(String) && !stderr.empty?
29
29
  raise msg
30
30
  end
31
31
  end
@@ -45,6 +45,31 @@ module NexusSW
45
45
 
46
46
  execute_chunked(command, options.merge(capture_options: capture_options), &capture_options[:capture])
47
47
  end
48
+
49
+ class InteractiveResult < ExecuteResult
50
+ def initialize(command, options, exitstatus, stdin, thread = nil)
51
+ super(command, options, exitstatus)
52
+ @stdin = stdin
53
+ @thread = thread
54
+ end
55
+
56
+ attr_reader :stdin, :thread
57
+ attr_accessor :exitstatus
58
+
59
+ def capture_output(&block)
60
+ @block = block if block_given?
61
+ end
62
+
63
+ def send_output(stdout_chunk)
64
+ return unless @block
65
+ @block.call stdout_chunk
66
+ end
67
+
68
+ def error!
69
+ thread.join if thread.respond_to? :join
70
+ super
71
+ end
72
+ end
48
73
  end
49
74
  end
50
75
  end
@@ -36,7 +36,7 @@ module NexusSW
36
36
  # TODO: serious: make sure the tar extract does an overwrite of existing files
37
37
  # multiple converge support as well as CI cycle/dev updated files get updated instead of .1 suffixed (?)
38
38
  # I think I need a flag (it's been a while)
39
- execute("bash -c 'mkdir -p #{path} && cd #{path} && tar -xf #{fname} && rm -rf #{fname}'", capture: false).error!
39
+ execute("bash -c 'mkdir -p #{path} && cd #{path} && tar -xf #{fname} && rm -rf #{fname}'").error!
40
40
  ensure
41
41
  tfile.unlink
42
42
  end
@@ -15,37 +15,34 @@ module NexusSW
15
15
 
16
16
  include Helpers::ExecuteMixin
17
17
 
18
- def execute_chunked(command, options)
18
+ def execute_chunked(command, options, &block)
19
19
  NIO::WebSocket::Reactor.start
20
20
  LXD.with_timeout_and_retries options do
21
- # Let's borrow the NIO::WebSocket reactor
22
- Open3.popen3(command) do |_stdin, stdout, stderr, th|
23
- mon_out = mon_err = nil
24
- NIO::WebSocket::Reactor.queue_task do
25
- mon_out = NIO::WebSocket::Reactor.selector.register(stdout, :r)
26
- mon_out.value = proc do
27
- data = read(mon_out) # read regardless of block_given? so that we don't spin out on :r availability
28
- yield(data) if data && block_given?
21
+ Open3.popen3(command) do |stdin, stdout, stderr, th|
22
+ if options[:capture] == :interactive
23
+ # return immediately if interactive so that stdin may be used
24
+ return Helpers::ExecuteMixin::InteractiveResult.new(command, options, -1, stdin, th).tap do |active|
25
+ chunk_callback(stdout, stderr) do |stdout_chunk, stderr_chunk|
26
+ active.send_output stdout_chunk if stdout_chunk
27
+ active.send_output stderr_chunk if stderr_chunk
28
+ end
29
+ yield active
30
+ active.exitstatus = th.value.exitstatus
29
31
  end
30
- end
31
- NIO::WebSocket::Reactor.queue_task do
32
- mon_err = NIO::WebSocket::Reactor.selector.register(stderr, :r)
33
- mon_err.value = proc do
34
- data = read(mon_err) # read regardless of block_given? so that we don't spin out on :r availability
35
- yield(nil, data) if data && block_given?
32
+ else
33
+ chunk_callback(stdout, stderr, &block) if block_given?
34
+ th.join
35
+ loop do
36
+ return Helpers::ExecuteMixin::ExecuteResult.new(command, options, th.value.exitstatus) if th.value.exited? && mon_out && mon_err && mon_out.closed? && mon_err.closed?
37
+ Thread.pass
36
38
  end
37
39
  end
38
- th.join
39
- loop do
40
- return Helpers::ExecuteMixin::ExecuteResult.new(command, options, th.value.exitstatus) if th.value.exited? && mon_out && mon_err && mon_out.closed? && mon_err.closed?
41
- Thread.pass
42
- end
43
40
  end
44
41
  end
45
42
  end
46
43
 
47
44
  def read_file(path)
48
- return '' unless File.exist? path
45
+ # return '' unless File.exist? path
49
46
  File.read path
50
47
  end
51
48
 
@@ -57,6 +54,8 @@ module NexusSW
57
54
 
58
55
  private
59
56
 
57
+ attr_reader :mon_out, :mon_err
58
+
60
59
  def read(monitor)
61
60
  monitor.io.read_nonblock(16384)
62
61
  rescue IO::WaitReadable # rubocop:disable Lint/ShadowedException
@@ -65,6 +64,23 @@ module NexusSW
65
64
  monitor.close
66
65
  return nil
67
66
  end
67
+
68
+ def chunk_callback(stdout, stderr)
69
+ NIO::WebSocket::Reactor.queue_task do
70
+ @mon_out = NIO::WebSocket::Reactor.selector.register(stdout, :r)
71
+ @mon_out.value = proc do
72
+ data = read(@mon_out) # read regardless of block_given? so that we don't spin out on :r availability
73
+ yield(data) if data
74
+ end
75
+ end
76
+ NIO::WebSocket::Reactor.queue_task do
77
+ @mon_err = NIO::WebSocket::Reactor.selector.register(stderr, :r)
78
+ @mon_err.value = proc do
79
+ data = read(@mon_err) # read regardless of block_given? so that we don't spin out on :r availability
80
+ yield(nil, data) if data
81
+ end
82
+ end
83
+ end
68
84
  end
69
85
  end
70
86
  end
@@ -22,20 +22,85 @@ module NexusSW
22
22
  include Helpers::ExecuteMixin
23
23
  include Helpers::UploadFolder
24
24
 
25
+ class StdinStub
26
+ # return self as an IO (un)like object
27
+ def initialize(driver)
28
+ @driver = driver
29
+ end
30
+ attr_reader :driver
31
+
32
+ # return a real IO object for parity with Local Transport
33
+ def self.pipe(driver)
34
+ NIO::WebSocket::Reactor.start
35
+ reader, writer = IO.pipe
36
+ NIO::WebSocket::Reactor.queue_task do
37
+ iomon = NIO::WebSocket::Reactor.selector.register(reader, :r)
38
+ iomon.value = proc do
39
+ data = read(iomon)
40
+ driver.binary data if data
41
+ end
42
+ end
43
+ writer
44
+ end
45
+
46
+ def write(data)
47
+ driver.binary data
48
+ end
49
+
50
+ def self.read(monitor)
51
+ monitor.io.read_nonblock(16384)
52
+ rescue IO::WaitReadable # rubocop:disable Lint/ShadowedException
53
+ return nil
54
+ rescue Errno::ECONNRESET, EOFError, IOError
55
+ monitor.close
56
+ return nil
57
+ end
58
+ end
59
+
25
60
  def execute_chunked(command, options = {}, &block)
26
61
  opid = nil
27
62
  backchannel = nil
28
- if block_given? # Allow for an optimized case that doesn't require the support of 3 new websocket connections
29
- retval = hk.execute_command(container_name, command, wait_for_websocket: true, interactive: false, sync: false)
63
+ getlogs = false
64
+ if block_given? && (options[:capture] || !config[:info][:api_extensions].include?('container_exec_recording'))
65
+ hkopts = { wait_for_websocket: true, interactive: false, sync: false }
66
+ hkopts[:interactive] = true if options[:capture] == :interactive
67
+ retval = hk.execute_command(container_name, command, hkopts)
68
+ opid = retval[:id]
69
+ backchannel = options[:capture] == :interactive ? ws_connect(opid, retval[:metadata][:fds]) : ws_connect(opid, retval[:metadata][:fds], &block)
70
+
71
+ # patch for interactive session
72
+ return Helpers::ExecuteMixin::InteractiveResult.new(command, options, -1, StdinStub.pipe(backchannel.waitlist[:'0']), backchannel).tap do |active|
73
+ backchannel.callback = proc do |stdout|
74
+ active.send_output stdout
75
+ end
76
+ yield active
77
+ backchannel.exit if backchannel.respond_to? :exit
78
+ retval = hk.wait_for_operation opid
79
+ active.exitstatus = retval[:metadata][:return].to_i
80
+ end if options[:capture] == :interactive
81
+ elsif block_given? && config[:info][:api_extensions].include?('container_exec_recording')
82
+ getlogs = true
83
+ retval = hk.execute_command(container_name, command, record_output: true, interactive: false, sync: false)
30
84
  opid = retval[:id]
31
- backchannel = ws_connect opid, retval[:metadata][:fds], &block
32
85
  else
33
86
  opid = hk.execute_command(container_name, command, sync: false)[:id]
34
87
  end
35
88
  LXD.with_timeout_and_retries({ timeout: 0 }.merge(options)) do
36
89
  begin
37
90
  retval = hk.wait_for_operation opid
38
- backchannel.exit if backchannel.respond_to? :exit
91
+ backchannel.join if backchannel.respond_to? :join
92
+ if getlogs
93
+ begin
94
+ stdout_log = retval[:metadata][:output][:'1'].split('/').last
95
+ stderr_log = retval[:metadata][:output][:'2'].split('/').last
96
+ stdout = hk.log container_name, stdout_log
97
+ stderr = hk.log container_name, stderr_log
98
+ yield stdout, stderr
99
+ ensure
100
+ hk.delete_log container_name, stdout_log
101
+ hk.delete_log container_name, stderr_log
102
+ end
103
+ end
39
104
  return Helpers::ExecuteMixin::ExecuteResult.new command, options, retval[:metadata][:return].to_i
40
105
  rescue Faraday::TimeoutError => e
41
106
  raise Timeout::Retry.new e # rubocop:disable Style/RaiseArgs
@@ -43,10 +108,11 @@ module NexusSW
43
108
  end
44
109
  end
45
110
 
111
+ # '' instead of Hyperkit::NotFound is a chef-provisioning expectation - at this level we'll let the exception propagate
46
112
  def read_file(path)
47
113
  hk.read_file container_name, path
48
- rescue ::Hyperkit::NotFound
49
- return ''
114
+ # rescue ::Hyperkit::NotFound
115
+ # return ''
50
116
  end
51
117
 
52
118
  def write_file(path, content)
@@ -64,16 +130,51 @@ module NexusSW
64
130
 
65
131
  protected
66
132
 
67
- class WSWrapper
68
- def initialize(waitlist)
69
- @waitlist = waitlist.compact
133
+ class WSController
134
+ def initialize(ws_options, baseurl, endpoints, &block)
135
+ @waitlist = {}
136
+ @callback = block if block_given?
137
+ waitlist[:control] = NIO::WebSocket.connect(baseurl + endpoints[:control], ws_options) do |driver|
138
+ driver.on :io_error do # usually I get an EOF
139
+ waitlist.each { |_, v| v.close if v.respond_to? :close }
140
+ end
141
+ driver.on :close do # but on occasion I get a legit close
142
+ waitlist.each { |_, v| v.close if v.respond_to? :close }
143
+ end
144
+ end
145
+ waitlist[:'2'] = NIO::WebSocket.connect(baseurl + endpoints[:'2'], ws_options) do |driver|
146
+ driver.on :message do |ev|
147
+ data = ev.data.is_a?(String) ? ev.data : ev.data.pack('U*')
148
+ callback.call nil, data
149
+ end
150
+ end if endpoints[:'2']
151
+ waitlist[:'1'] = NIO::WebSocket.connect(baseurl + endpoints[:'1'], ws_options) do |driver|
152
+ driver.on :message do |ev|
153
+ data = ev.data.is_a?(String) ? ev.data : ev.data.pack('U*')
154
+ callback.call data
155
+ end
156
+ end if endpoints[:'1']
157
+ waitlist[:'0'] = NIO::WebSocket.connect(baseurl + endpoints[:'0'], ws_options) do |driver|
158
+ driver.on :message do |ev|
159
+ data = ev.data.is_a?(String) ? ev.data : ev.data.pack('U*')
160
+ callback.call data
161
+ end
162
+ end
70
163
  end
164
+
71
165
  attr_reader :waitlist
166
+ attr_accessor :callback
72
167
 
73
168
  def exit
169
+ waitlist.each do |_fd, driver|
170
+ driver.close
171
+ end
172
+ end
173
+
174
+ def join
74
175
  loop do
75
176
  allclosed = true
76
- waitlist.each do |driver|
177
+ waitlist.each do |_fd, driver|
77
178
  allclosed = false unless driver.state == :closed
78
179
  end
79
180
  break if allclosed
@@ -83,7 +184,7 @@ module NexusSW
83
184
  end
84
185
  end
85
186
 
86
- def ws_connect(opid, endpoints)
187
+ def ws_connect(opid, endpoints, &block)
87
188
  # NIO::WebSocket.log_traffic = true
88
189
  verify_ssl = OpenSSL::SSL::VERIFY_NONE if @driver_options[:verify_ssl] == false
89
190
  ws_options = { ssl_context: { verify_mode: verify_ssl } } unless verify_ssl.nil?
@@ -92,31 +193,7 @@ module NexusSW
92
193
  baseurl += '/' unless baseurl.end_with? '/'
93
194
  baseurl += "1.0/operations/#{opid}/websocket?secret="
94
195
 
95
- pipes = {}
96
- NIO::WebSocket.connect(baseurl + endpoints[:control], ws_options) do |driver|
97
- driver.on :io_error do # usually I get an EOF
98
- pipes.each { |_, v| v.close if v.respond_to? :close }
99
- end
100
- driver.on :close do # but on occasion I get a legit close
101
- pipes.each { |_, v| v.close if v.respond_to? :close }
102
- end
103
- end
104
- pipes[:'1'] = NIO::WebSocket.connect(baseurl + endpoints[:'1'], ws_options) do |driver|
105
- driver.on :message do |ev|
106
- data = ev.data.is_a?(String) ? ev.data : ev.data.pack('U*')
107
- yield data
108
- end
109
- end
110
- endpoints.each do |fd, secret|
111
- next if [:control, :'1'].include? fd
112
- pipes[fd] = NIO::WebSocket.connect(baseurl + secret, ws_options) do |driver|
113
- driver.on :message do |ev|
114
- data = ev.data.is_a?(String) ? ev.data : ev.data.pack('U*')
115
- yield nil, data
116
- end
117
- end
118
- end
119
- WSWrapper.new [pipes[:'1'], pipes[:'2']]
196
+ WSController.new ws_options, baseurl, endpoints, &block
120
197
  end
121
198
  end
122
199
  end
@@ -1,5 +1,5 @@
1
1
  module NexusSW
2
2
  module LXD
3
- VERSION = '0.5.0'.freeze
3
+ VERSION = '0.6.0'.freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lxd-common
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Zachariasen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-12-16 00:00:00.000000000 Z
11
+ date: 2017-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hyperkit
@@ -148,7 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
148
148
  version: '0'
149
149
  requirements: []
150
150
  rubyforge_project:
151
- rubygems_version: 2.6.13
151
+ rubygems_version: 2.7.4
152
152
  signing_key:
153
153
  specification_version: 4
154
154
  summary: Shared LXD Container Access Library