lxd-common 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/nexussw/lxd/rest_api.rb +9 -4
- data/lib/nexussw/lxd/rest_api/connection.rb +3 -6
- data/lib/nexussw/lxd/transport.rb +7 -3
- data/lib/nexussw/lxd/transport/mixins/cli.rb +31 -15
- data/lib/nexussw/lxd/transport/mixins/helpers/execute.rb +2 -0
- data/lib/nexussw/lxd/transport/mixins/helpers/upload_folder.rb +13 -9
- data/lib/nexussw/lxd/transport/mixins/helpers/users.rb +37 -0
- data/lib/nexussw/lxd/transport/mixins/rest.rb +12 -4
- data/lib/nexussw/lxd/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43d858bed713fa5394649fad875abd9cbf868cf572fb02599e3811e170f8f9fc
|
4
|
+
data.tar.gz: 47e0b0fb09991a4ef903a0ec4b2ddb89308a057e28923e7a5647f50247305ce9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f3840c037a9364eec153a4f9cc67ff4a4c81e0df0efa5f1fe6eb6e6d89e9c976ef69ba59386bd58e9c8510b79d51180fc37469a1e4c623d8fc2d55579dad5e7e
|
7
|
+
data.tar.gz: b0c51acca0425ccedf6285d9da0c616baf5b25c9c73de12855e8f4652d5331572b107b93b0dd7a73fe0db682bf49ae72c52fedc9f6cac8e868168d118a146cf1
|
data/lib/nexussw/lxd/rest_api.rb
CHANGED
@@ -54,12 +54,17 @@ module NexusSW
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def write_file(container_name, path, options)
|
57
|
-
post "/1.0/containers/#{container_name}/files?path=#{path}", options[:content]
|
57
|
+
post "/1.0/containers/#{container_name}/files?path=#{path}", options[:content] do |req|
|
58
|
+
req.headers['Content-Type'] = 'application/octet-stream'
|
59
|
+
req.headers['X-LXD-uid'] = options[:uid] if options[:uid]
|
60
|
+
req.headers['X-LXD-gid'] = options[:gid] if options[:gid]
|
61
|
+
req.headers['X-LXD-mode'] = options[:file_mode] if options[:file_mode]
|
62
|
+
end
|
58
63
|
end
|
59
64
|
|
60
|
-
def push_file(local_path, container_name, remote_path)
|
61
|
-
|
62
|
-
end
|
65
|
+
# def push_file(local_path, container_name, remote_path)
|
66
|
+
# write_file container_name, remote_path, content: IO.binread(local_path)
|
67
|
+
# end
|
63
68
|
|
64
69
|
def pull_file(container_name, remote_path, local_path)
|
65
70
|
IO.binwrite(local_path, read_file(container_name, remote_path))
|
@@ -74,11 +74,8 @@ module NexusSW
|
|
74
74
|
if content.is_a? Hash
|
75
75
|
req.headers['Content-Type'] = 'application/json'
|
76
76
|
req.body = content.to_json
|
77
|
-
elsif content # Only upon file upload
|
78
|
-
req
|
79
|
-
req.headers['X-LXD-uid'] = '0'
|
80
|
-
req.headers['X-LXD-gid'] = '0'
|
81
|
-
req.headers['X-LXD-mode'] = '0600'
|
77
|
+
elsif content # Only upon file upload at this time
|
78
|
+
yield req if block_given?
|
82
79
|
req.body = content.to_s
|
83
80
|
end
|
84
81
|
end
|
@@ -87,7 +84,7 @@ module NexusSW
|
|
87
84
|
case err['error_code']
|
88
85
|
when 404 then raise RestAPI::Error::NotFound, err['error']
|
89
86
|
when 400 then raise RestAPI::Error::BadRequest, err['error']
|
90
|
-
else raise "Error #{err['error_code']}: #{err['error']}"
|
87
|
+
else raise RestAPI::Error, "Error #{err['error_code']}: #{err['error']}"
|
91
88
|
end
|
92
89
|
end
|
93
90
|
block_given? ? yield(response) : parse_response(response)
|
@@ -7,11 +7,15 @@ module NexusSW
|
|
7
7
|
raise "#{self.class}#execute not implemented"
|
8
8
|
end
|
9
9
|
|
10
|
+
def user(_user, _options = {})
|
11
|
+
raise "#{self.class}#user not implemented"
|
12
|
+
end
|
13
|
+
|
10
14
|
def read_file(_path)
|
11
15
|
raise "#{self.class}#read_file not implemented"
|
12
16
|
end
|
13
17
|
|
14
|
-
def write_file(_path, _content)
|
18
|
+
def write_file(_path, _content, _options = {})
|
15
19
|
raise "#{self.class}#write_file not implemented"
|
16
20
|
end
|
17
21
|
|
@@ -19,11 +23,11 @@ module NexusSW
|
|
19
23
|
raise "#{self.class}#download_file not implemented"
|
20
24
|
end
|
21
25
|
|
22
|
-
def upload_file(_local_path, _path)
|
26
|
+
def upload_file(_local_path, _path, _options = {})
|
23
27
|
raise "#{self.class}#upload_file not implemented"
|
24
28
|
end
|
25
29
|
|
26
|
-
def upload_folder(_local_path, _path)
|
30
|
+
def upload_folder(_local_path, _path, _options = {})
|
27
31
|
raise "#{self.class}#upload_folder not implemented"
|
28
32
|
end
|
29
33
|
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'nexussw/lxd/transport/mixins/local'
|
2
|
+
require 'nexussw/lxd/transport/mixins/helpers/users'
|
2
3
|
require 'nexussw/lxd/transport/mixins/helpers/upload_folder'
|
3
4
|
require 'tempfile'
|
4
|
-
require '
|
5
|
+
require 'shellwords'
|
5
6
|
|
6
7
|
module NexusSW
|
7
8
|
module LXD
|
@@ -18,17 +19,17 @@ module NexusSW
|
|
18
19
|
attr_reader :inner_transport, :punt, :container_name, :config
|
19
20
|
|
20
21
|
include Helpers::UploadFolder
|
22
|
+
include Helpers::UsersMixin
|
21
23
|
|
22
24
|
def execute(command, options = {}, &block)
|
23
|
-
|
25
|
+
command = runas_command(command, options) unless options[:subcommand]
|
26
|
+
command = command.shelljoin if command.is_a?(Array)
|
24
27
|
subcommand = options[:subcommand] || "exec #{container_name} --"
|
25
|
-
|
26
|
-
|
27
|
-
options
|
28
|
-
|
29
|
-
|
30
|
-
# with_timeout_and_retries(options) do
|
31
|
-
inner_transport.execute mycommand, options, &block
|
28
|
+
command = "lxc #{subcommand} #{command}"
|
29
|
+
|
30
|
+
options.reject! { |k, _| [:subcommand, :runas].include? k }
|
31
|
+
|
32
|
+
inner_transport.execute command, options, &block
|
32
33
|
end
|
33
34
|
|
34
35
|
def read_file(path)
|
@@ -41,10 +42,12 @@ module NexusSW
|
|
41
42
|
inner_transport.execute("rm -rf #{tfile}", capture: false) if tfile
|
42
43
|
end
|
43
44
|
|
44
|
-
def write_file(path, content)
|
45
|
+
def write_file(path, content, options = {})
|
46
|
+
perms = file_perms(options)
|
47
|
+
|
45
48
|
tfile = inner_mktmp
|
46
49
|
inner_transport.write_file tfile, content
|
47
|
-
execute("#{tfile} #{container_name}#{path}", subcommand:
|
50
|
+
execute("#{tfile} #{container_name}#{path}", subcommand: "file push#{perms}", capture: false).error!
|
48
51
|
ensure
|
49
52
|
inner_transport.execute("rm -rf #{tfile}", capture: false) if tfile
|
50
53
|
end
|
@@ -58,18 +61,22 @@ module NexusSW
|
|
58
61
|
inner_transport.execute("rm -rf #{tfile}", capture: false) if tfile
|
59
62
|
end
|
60
63
|
|
61
|
-
def upload_file(local_path, path)
|
64
|
+
def upload_file(local_path, path, options = {})
|
65
|
+
perms = file_perms(options)
|
66
|
+
|
62
67
|
tfile = inner_mktmp if punt
|
63
68
|
localname = tfile || local_path
|
64
69
|
inner_transport.upload_file local_path, tfile if tfile
|
65
|
-
execute("#{localname} #{container_name}#{path}", subcommand:
|
70
|
+
execute("#{localname} #{container_name}#{path}", subcommand: "file push#{perms}", capture: false).error!
|
66
71
|
ensure
|
67
72
|
inner_transport.execute("rm -rf #{tfile}", capture: false) if tfile
|
68
73
|
end
|
69
74
|
|
70
|
-
def upload_folder(local_path, path)
|
75
|
+
def upload_folder(local_path, path, options = {})
|
71
76
|
return super unless config[:info] && config[:info]['api_extensions'] && config[:info]['api_extensions'].include?('directory_manipulation')
|
72
|
-
|
77
|
+
|
78
|
+
perms = file_perms(options)
|
79
|
+
execute("-r #{local_path} #{container_name}#{path}", subcommand: "file push#{perms}", capture: false).error!
|
73
80
|
end
|
74
81
|
|
75
82
|
def add_remote(host_name)
|
@@ -101,6 +108,15 @@ module NexusSW
|
|
101
108
|
ensure
|
102
109
|
tfile.unlink
|
103
110
|
end
|
111
|
+
|
112
|
+
def file_perms(options = {})
|
113
|
+
perms = ''
|
114
|
+
perms += " --uid=#{options[:uid] || uid || 0}"
|
115
|
+
perms += " --gid=#{options[:gid] || gid || 0}"
|
116
|
+
fmode = options[:file_mode] || file_mode
|
117
|
+
perms += " --mode=#{fmode}" if fmode
|
118
|
+
perms
|
119
|
+
end
|
104
120
|
end
|
105
121
|
end
|
106
122
|
end
|
@@ -26,12 +26,14 @@ module NexusSW
|
|
26
26
|
def error!
|
27
27
|
return self if exitstatus == 0
|
28
28
|
msg = "Error: '#{command}' failed with exit code #{exitstatus}.\n"
|
29
|
+
# msg += (" while running as '#{username}'.\n" if username) || ".\n"
|
29
30
|
msg += "STDOUT: #{stdout}" if stdout.is_a?(String) && !stdout.empty?
|
30
31
|
msg += "STDERR: #{stderr}" if stderr.is_a?(String) && !stderr.empty?
|
31
32
|
raise ::NexusSW::LXD::RestAPI::Error, msg
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
36
|
+
# LocalTransport does not have the users mixin, so code the `su` command on the rest & cli transports directly
|
35
37
|
def execute(command, options = {}, &block)
|
36
38
|
options ||= {}
|
37
39
|
return execute_chunked(command, options) if options[:capture] == false && !block_given?
|
@@ -4,19 +4,19 @@ module NexusSW
|
|
4
4
|
module Mixins
|
5
5
|
module Helpers
|
6
6
|
module UploadFolder
|
7
|
-
def upload_folder(local_path, path)
|
8
|
-
upload_using_tarball(local_path, path) || upload_files_individually(local_path, path)
|
7
|
+
def upload_folder(local_path, path, options = {})
|
8
|
+
upload_using_tarball(local_path, path, options) || upload_files_individually(local_path, path, options)
|
9
9
|
end
|
10
10
|
|
11
|
-
def upload_files_individually(local_path, path)
|
11
|
+
def upload_files_individually(local_path, path, options = {})
|
12
12
|
Dir.entries(local_path).map { |f| (f == '.' || f == '..') ? nil : File.join(local_path, f) }.compact.each do |f|
|
13
13
|
dest = File.join(path, File.basename(local_path))
|
14
|
-
upload_files_individually f, dest if File.directory? f
|
15
|
-
upload_file f, File.join(dest, File.basename(f)) if File.file? f
|
14
|
+
upload_files_individually f, dest, options if File.directory? f
|
15
|
+
upload_file f, File.join(dest, File.basename(f)), options if File.file? f
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
def upload_using_tarball(local_path, path)
|
19
|
+
def upload_using_tarball(local_path, path, options = {})
|
20
20
|
return false unless can_archive?
|
21
21
|
# TODO: should I return false upon error? i.e. retry with individual file uploads if this fails?
|
22
22
|
# lets see how this does in the wild before deciding
|
@@ -32,12 +32,16 @@ module NexusSW
|
|
32
32
|
return false
|
33
33
|
end
|
34
34
|
fname = '/tmp/' + File.basename(tfile.path) + ".tar#{ext}"
|
35
|
-
upload_file tfile.path, fname
|
35
|
+
upload_file tfile.path, fname, options
|
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
|
-
|
40
|
-
|
39
|
+
myuid = options[:uid] || uid || (0 if is_a?(Mixins::CLI))
|
40
|
+
mygid = options[:gid] || gid || (0 if is_a?(Mixins::CLI))
|
41
|
+
mymode = options[:file_mode] || file_mode
|
42
|
+
chown = " && chown -R #{myuid}:#{mygid} #{File.basename(local_path)}" if myuid
|
43
|
+
chmod = " && chmod -R #{mymode} #{File.basename(local_path)}" if mymode
|
44
|
+
execute("bash -c 'mkdir -p #{path} && cd #{path} && tar -xf #{fname} && rm -rf #{fname}#{chmod}#{chown}'").error!
|
41
45
|
ensure
|
42
46
|
tfile.unlink
|
43
47
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'shellwords'
|
2
|
+
|
3
|
+
module NexusSW
|
4
|
+
module LXD
|
5
|
+
class Transport
|
6
|
+
module Mixins
|
7
|
+
module Helpers
|
8
|
+
module UsersMixin
|
9
|
+
def user(user_nameorid, options = {})
|
10
|
+
passwd = read_file options[:passwd_file] || '/etc/passwd'
|
11
|
+
|
12
|
+
# rework into .split(':') if this gets more complicated
|
13
|
+
@uid = user_nameorid.is_a?(String) ? passwd[/^#{user_nameorid}:[^:]*:([^:]*):/, 1] : user_nameorid
|
14
|
+
@username = user_nameorid.is_a?(String) ? user_nameorid : passwd[/^([^:]*):[^:]*:#{user_nameorid}:/, 1]
|
15
|
+
|
16
|
+
# gotcha: we're always setting the default group here, but it's changeable by the user, afterwards
|
17
|
+
# so if `user` gets called again, and the caller wants an alternative gid, the caller will need to re-set the gid
|
18
|
+
@gid = passwd[/^[^:]*:[^:]*:#{uid}:([^:]*):/, 1]
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_accessor :file_mode, :gid
|
22
|
+
attr_reader :uid, :username
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def runas_command(command, options = {})
|
27
|
+
uname = options[:runas] || username
|
28
|
+
return command unless uname
|
29
|
+
command = command.shelljoin if command.is_a? Array
|
30
|
+
['su', uname, '-c', command]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
require 'nexussw/lxd/transport/mixins/helpers/execute'
|
2
|
+
require 'nexussw/lxd/transport/mixins/helpers/users'
|
2
3
|
require 'nexussw/lxd/transport/mixins/helpers/upload_folder'
|
3
4
|
require 'nio/websocket'
|
4
5
|
require 'tempfile'
|
5
6
|
require 'json'
|
7
|
+
require 'shellwords'
|
6
8
|
|
7
9
|
module NexusSW
|
8
10
|
module LXD
|
@@ -22,6 +24,7 @@ module NexusSW
|
|
22
24
|
|
23
25
|
include Helpers::ExecuteMixin
|
24
26
|
include Helpers::UploadFolder
|
27
|
+
include Helpers::UsersMixin
|
25
28
|
|
26
29
|
class StdinStub
|
27
30
|
# return self as an IO (un)like object
|
@@ -62,6 +65,7 @@ module NexusSW
|
|
62
65
|
opid = nil
|
63
66
|
backchannel = nil
|
64
67
|
getlogs = false
|
68
|
+
command = runas_command(command, options)
|
65
69
|
if block_given? && (options[:capture] || !config[:info][:api_extensions].include?('container_exec_recording'))
|
66
70
|
apiopts = { :'wait-for-websocket' => true, interactive: false, sync: false }
|
67
71
|
apiopts[:interactive] = true if options[:capture] == :interactive
|
@@ -114,17 +118,21 @@ module NexusSW
|
|
114
118
|
api.read_file container_name, path
|
115
119
|
end
|
116
120
|
|
117
|
-
def write_file(path, content)
|
118
|
-
|
121
|
+
def write_file(path, content, options = {})
|
122
|
+
options = options.merge content: content
|
123
|
+
options[:uid] ||= uid if uid
|
124
|
+
options[:gid] ||= gid if gid
|
125
|
+
options[:file_mode] ||= file_mode if file_mode
|
126
|
+
api.write_file container_name, path, options
|
119
127
|
end
|
120
128
|
|
121
129
|
def download_file(path, local_path)
|
122
130
|
api.pull_file container_name, path, local_path
|
123
131
|
end
|
124
132
|
|
125
|
-
def upload_file(local_path, path)
|
133
|
+
def upload_file(local_path, path, options = {})
|
126
134
|
# return api.push_file(local_path, container_name, path)
|
127
|
-
write_file(path, IO.binread(local_path))
|
135
|
+
write_file(path, IO.binread(local_path), options)
|
128
136
|
end
|
129
137
|
|
130
138
|
protected
|
data/lib/nexussw/lxd/version.rb
CHANGED
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.
|
4
|
+
version: 0.8.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: 2018-01-
|
11
|
+
date: 2018-01-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -127,6 +127,7 @@ files:
|
|
127
127
|
- lib/nexussw/lxd/transport/mixins/cli.rb
|
128
128
|
- lib/nexussw/lxd/transport/mixins/helpers/execute.rb
|
129
129
|
- lib/nexussw/lxd/transport/mixins/helpers/upload_folder.rb
|
130
|
+
- lib/nexussw/lxd/transport/mixins/helpers/users.rb
|
130
131
|
- lib/nexussw/lxd/transport/mixins/local.rb
|
131
132
|
- lib/nexussw/lxd/transport/mixins/rest.rb
|
132
133
|
- lib/nexussw/lxd/transport/rest.rb
|