lxd-common 0.4.1
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 +7 -0
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/.travis.yml +28 -0
- data/Gemfile +4 -0
- data/LICENSE +202 -0
- data/README.md +34 -0
- data/Rakefile +9 -0
- data/Vagrantfile +15 -0
- data/bin/console +17 -0
- data/bin/setup +8 -0
- data/lib/nexussw/lxd.rb +32 -0
- data/lib/nexussw/lxd/driver.rb +89 -0
- data/lib/nexussw/lxd/driver/cli.rb +12 -0
- data/lib/nexussw/lxd/driver/mixins/cli.rb +182 -0
- data/lib/nexussw/lxd/driver/mixins/rest.rb +128 -0
- data/lib/nexussw/lxd/driver/rest.rb +12 -0
- data/lib/nexussw/lxd/transport.rb +73 -0
- data/lib/nexussw/lxd/transport/cli.rb +12 -0
- data/lib/nexussw/lxd/transport/local.rb +12 -0
- data/lib/nexussw/lxd/transport/mixins/cli.rb +98 -0
- data/lib/nexussw/lxd/transport/mixins/local.rb +71 -0
- data/lib/nexussw/lxd/transport/mixins/rest.rb +120 -0
- data/lib/nexussw/lxd/transport/rest.rb +12 -0
- data/lib/nexussw/lxd/version.rb +5 -0
- data/lxd-common.gemspec +35 -0
- metadata +152 -0
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'open3'
|
2
|
+
require 'nio/websocket'
|
3
|
+
|
4
|
+
module NexusSW
|
5
|
+
module LXD
|
6
|
+
class Transport
|
7
|
+
module Mixins
|
8
|
+
module Local
|
9
|
+
def initialize(config = {})
|
10
|
+
@config = config
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :config
|
14
|
+
|
15
|
+
include ExecuteMixin
|
16
|
+
|
17
|
+
def execute_chunked(command, options)
|
18
|
+
NIO::WebSocket::Reactor.start
|
19
|
+
LXD.with_timeout_and_retries options do
|
20
|
+
# Let's borrow the NIO::WebSocket reactor
|
21
|
+
Open3.popen3(command) do |_stdin, stdout, stderr, th|
|
22
|
+
mon_out = mon_err = nil
|
23
|
+
NIO::WebSocket::Reactor.queue_task do
|
24
|
+
mon_out = NIO::WebSocket::Reactor.selector.register(stdout, :r)
|
25
|
+
mon_out.value = proc do
|
26
|
+
data = read(mon_out) # read regardless of block_given? so that we don't spin out on :r availability
|
27
|
+
yield(data) if data && block_given?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
NIO::WebSocket::Reactor.queue_task do
|
31
|
+
mon_err = NIO::WebSocket::Reactor.selector.register(stderr, :r)
|
32
|
+
mon_err.value = proc do
|
33
|
+
data = read(mon_err) # read regardless of block_given? so that we don't spin out on :r availability
|
34
|
+
yield(nil, data) if data && block_given?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
th.join
|
38
|
+
loop do
|
39
|
+
return LXDExecuteResult.new(command, options, th.value.exitstatus) if th.value.exited? && mon_out && mon_err && mon_out.closed? && mon_err.closed?
|
40
|
+
Thread.pass
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def read_file(path)
|
47
|
+
return '' unless File.exist? path
|
48
|
+
File.read path
|
49
|
+
end
|
50
|
+
|
51
|
+
def write_file(path, content)
|
52
|
+
File.open path, 'w' do |f|
|
53
|
+
f.write content
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def read(monitor)
|
60
|
+
monitor.io.read_nonblock(16384)
|
61
|
+
rescue IO::WaitReadable # rubocop:disable Lint/ShadowedException
|
62
|
+
return nil
|
63
|
+
rescue Errno::ECONNRESET, EOFError, IOError
|
64
|
+
monitor.close
|
65
|
+
return nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'nio/websocket'
|
2
|
+
|
3
|
+
module NexusSW
|
4
|
+
module LXD
|
5
|
+
class Transport
|
6
|
+
module Mixins
|
7
|
+
module Rest
|
8
|
+
def initialize(driver, container_name, config = {})
|
9
|
+
@container_name = container_name
|
10
|
+
@config = config
|
11
|
+
raise "The rest transport requires the Rest Driver. You supplied #{driver}" unless driver.respond_to?(:hk) && driver.respond_to?(:rest_endpoint) # driver.is_a? NexusSW::LXD::Driver::Rest
|
12
|
+
@rest_endpoint = driver.rest_endpoint
|
13
|
+
@driver_options = driver.driver_options
|
14
|
+
@hk = driver.hk
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :hk, :rest_endpoint, :container_name, :config
|
18
|
+
|
19
|
+
include ExecuteMixin
|
20
|
+
|
21
|
+
def execute_chunked(command, options = {}, &block)
|
22
|
+
opid = nil
|
23
|
+
backchannel = nil
|
24
|
+
if block_given? # Allow for an optimized case that doesn't require the support of 3 new websocket connections
|
25
|
+
retval = hk.execute_command(container_name, command, wait_for_websocket: true, interactive: false, sync: false)
|
26
|
+
opid = retval[:id]
|
27
|
+
backchannel = ws_connect opid, retval[:metadata][:fds], &block
|
28
|
+
else
|
29
|
+
opid = hk.execute_command(container_name, command, sync: false)[:id]
|
30
|
+
end
|
31
|
+
LXD.with_timeout_and_retries({ timeout: 0 }.merge(options)) do
|
32
|
+
begin
|
33
|
+
retval = hk.wait_for_operation opid
|
34
|
+
backchannel.exit if backchannel.respond_to? :exit
|
35
|
+
return LXDExecuteResult.new command, options, retval[:metadata][:return].to_i
|
36
|
+
rescue Faraday::TimeoutError => e
|
37
|
+
raise Timeout::Retry.new e # rubocop:disable Style/RaiseArgs
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def read_file(path)
|
43
|
+
hk.read_file container_name, path
|
44
|
+
rescue ::Hyperkit::NotFound
|
45
|
+
return ''
|
46
|
+
end
|
47
|
+
|
48
|
+
def write_file(path, content)
|
49
|
+
hk.write_file container_name, path, content: content
|
50
|
+
end
|
51
|
+
|
52
|
+
def download_file(path, local_path)
|
53
|
+
hk.pull_file container_name, path, local_path
|
54
|
+
end
|
55
|
+
|
56
|
+
def upload_file(local_path, path)
|
57
|
+
hk.push_file local_path, container_name, path
|
58
|
+
end
|
59
|
+
|
60
|
+
protected
|
61
|
+
|
62
|
+
class WSWrapper
|
63
|
+
def initialize(waitlist)
|
64
|
+
@waitlist = waitlist.compact
|
65
|
+
end
|
66
|
+
attr_reader :waitlist
|
67
|
+
|
68
|
+
def exit
|
69
|
+
loop do
|
70
|
+
allclosed = true
|
71
|
+
waitlist.each do |driver|
|
72
|
+
allclosed = false unless driver.state == :closed
|
73
|
+
end
|
74
|
+
break if allclosed
|
75
|
+
Thread.pass
|
76
|
+
sleep 0.1
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def ws_connect(opid, endpoints)
|
82
|
+
# NIO::WebSocket.log_traffic = true
|
83
|
+
verify_ssl = OpenSSL::SSL::VERIFY_NONE if @driver_options[:verify_ssl] == false
|
84
|
+
ws_options = { ssl_context: { verify_mode: verify_ssl } } unless verify_ssl.nil?
|
85
|
+
ws_options ||= {}
|
86
|
+
baseurl = rest_endpoint.sub(%r{^http([s]?://)}, 'ws\1')
|
87
|
+
baseurl += '/' unless baseurl.end_with? '/'
|
88
|
+
baseurl += "1.0/operations/#{opid}/websocket?secret="
|
89
|
+
|
90
|
+
pipes = {}
|
91
|
+
NIO::WebSocket.connect(baseurl + endpoints[:control], ws_options) do |driver|
|
92
|
+
driver.on :io_error do # usually I get an EOF
|
93
|
+
pipes.each { |_, v| v.close if v.respond_to? :close }
|
94
|
+
end
|
95
|
+
driver.on :close do # but on occasion I get a legit close
|
96
|
+
pipes.each { |_, v| v.close if v.respond_to? :close }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
pipes[:'1'] = NIO::WebSocket.connect(baseurl + endpoints[:'1'], ws_options) do |driver|
|
100
|
+
driver.on :message do |ev|
|
101
|
+
data = ev.data.is_a?(String) ? ev.data : ev.data.pack('U*')
|
102
|
+
yield data
|
103
|
+
end
|
104
|
+
end
|
105
|
+
endpoints.each do |fd, secret|
|
106
|
+
next if [:control, :'1'].include? fd
|
107
|
+
pipes[fd] = NIO::WebSocket.connect(baseurl + secret, ws_options) do |driver|
|
108
|
+
driver.on :message do |ev|
|
109
|
+
data = ev.data.is_a?(String) ? ev.data : ev.data.pack('U*')
|
110
|
+
yield nil, data
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
WSWrapper.new [pipes[:'1'], pipes[:'2']]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
data/lxd-common.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'nexussw/lxd/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'lxd-common'
|
8
|
+
spec.version = NexusSW::LXD::VERSION
|
9
|
+
spec.authors = ['Sean Zachariasen']
|
10
|
+
spec.email = ['thewyzard@hotmail.com']
|
11
|
+
|
12
|
+
spec.summary = 'Shared LXD Container Access Library'
|
13
|
+
# spec.description = %q{TODO: Write a longer description or delete this line.}
|
14
|
+
spec.homepage = 'http://github.com/NexusSW/lxd-common'
|
15
|
+
|
16
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
17
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
18
|
+
|
19
|
+
# spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'" if spec.respond_to?(:metadata)
|
20
|
+
|
21
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
22
|
+
f.match(%r{^(test|spec|features)/})
|
23
|
+
end
|
24
|
+
spec.bindir = 'exe'
|
25
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
26
|
+
spec.require_paths = ['lib']
|
27
|
+
|
28
|
+
spec.add_dependency 'hyperkit', '~> 1.1'
|
29
|
+
spec.add_dependency 'nio4r-websocket', '~> 0.6'
|
30
|
+
|
31
|
+
spec.add_development_dependency 'bundler'
|
32
|
+
spec.add_development_dependency 'rake'
|
33
|
+
spec.add_development_dependency 'rspec'
|
34
|
+
spec.add_development_dependency 'simplecov'
|
35
|
+
end
|
metadata
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lxd-common
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sean Zachariasen
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-11-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: hyperkit
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: nio4r-websocket
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.6'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: simplecov
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description:
|
98
|
+
email:
|
99
|
+
- thewyzard@hotmail.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- ".gitignore"
|
105
|
+
- ".rspec"
|
106
|
+
- ".travis.yml"
|
107
|
+
- Gemfile
|
108
|
+
- LICENSE
|
109
|
+
- README.md
|
110
|
+
- Rakefile
|
111
|
+
- Vagrantfile
|
112
|
+
- bin/console
|
113
|
+
- bin/setup
|
114
|
+
- lib/nexussw/lxd.rb
|
115
|
+
- lib/nexussw/lxd/driver.rb
|
116
|
+
- lib/nexussw/lxd/driver/cli.rb
|
117
|
+
- lib/nexussw/lxd/driver/mixins/cli.rb
|
118
|
+
- lib/nexussw/lxd/driver/mixins/rest.rb
|
119
|
+
- lib/nexussw/lxd/driver/rest.rb
|
120
|
+
- lib/nexussw/lxd/transport.rb
|
121
|
+
- lib/nexussw/lxd/transport/cli.rb
|
122
|
+
- lib/nexussw/lxd/transport/local.rb
|
123
|
+
- lib/nexussw/lxd/transport/mixins/cli.rb
|
124
|
+
- lib/nexussw/lxd/transport/mixins/local.rb
|
125
|
+
- lib/nexussw/lxd/transport/mixins/rest.rb
|
126
|
+
- lib/nexussw/lxd/transport/rest.rb
|
127
|
+
- lib/nexussw/lxd/version.rb
|
128
|
+
- lxd-common.gemspec
|
129
|
+
homepage: http://github.com/NexusSW/lxd-common
|
130
|
+
licenses: []
|
131
|
+
metadata: {}
|
132
|
+
post_install_message:
|
133
|
+
rdoc_options: []
|
134
|
+
require_paths:
|
135
|
+
- lib
|
136
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
requirements: []
|
147
|
+
rubyforge_project:
|
148
|
+
rubygems_version: 2.6.13
|
149
|
+
signing_key:
|
150
|
+
specification_version: 4
|
151
|
+
summary: Shared LXD Container Access Library
|
152
|
+
test_files: []
|