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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 031530f1093174e61e18c8a58e85805376bbc9b80368c800f7cc28cc3476e8ac
4
- data.tar.gz: 0dea2d0bdb81700c0b0c05b990620fef2ae999b0828d1ddee0714e54a914909f
3
+ metadata.gz: 43d858bed713fa5394649fad875abd9cbf868cf572fb02599e3811e170f8f9fc
4
+ data.tar.gz: 47e0b0fb09991a4ef903a0ec4b2ddb89308a057e28923e7a5647f50247305ce9
5
5
  SHA512:
6
- metadata.gz: 677d8545906f020bb8a485362cc39e8b7d809a96822fdeb05225d65f9da79bd1865c5105c3b3706946fc29ed09d3d0cbab4efb8c67c4acdd8724d6f41184f75f
7
- data.tar.gz: 18772ed5c102a70bc3e0fdacb0742c7de807d210e339ba83d1db5efc61fc529e36ef423f364f630a3215564e99225b2771572d3699e231617fb2dbad3643f8a4
6
+ metadata.gz: f3840c037a9364eec153a4f9cc67ff4a4c81e0df0efa5f1fe6eb6e6d89e9c976ef69ba59386bd58e9c8510b79d51180fc37469a1e4c623d8fc2d55579dad5e7e
7
+ data.tar.gz: b0c51acca0425ccedf6285d9da0c616baf5b25c9c73de12855e8f4652d5331572b107b93b0dd7a73fe0db682bf49ae72c52fedc9f6cac8e868168d118a146cf1
@@ -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
- write_file container_name, remote_path, content: IO.binread(local_path)
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.headers['Content-Type'] = 'application/octet-stream'
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 'pp'
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
- mycommand = command.is_a?(Array) ? command.join(' ') : command
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
- mycommand = "lxc #{subcommand} #{mycommand}"
26
- # options = options.except :subcommand if options.key? :subcommand
27
- options = options.reject { |k, _| k == :subcommand }
28
- # We would have competing timeout logic depending on who the inner transport is
29
- # I'll just let rest & local do the timeouts, and if inner is a chef sourced transport, they have timeout logic of their own
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: 'file push', capture: false).error!
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: 'file push', capture: false).error!
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
- execute("-r #{local_path} #{container_name}#{path}", subcommand: 'file push', capture: false).error!
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
- # TODO: explore the chmod & make the same as if uploaded via CLI
40
- execute("bash -c 'mkdir -p #{path} && cd #{path} && tar -xf #{fname} && rm -rf #{fname} && chmod -R 600 #{File.basename(local_path)}'").error!
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
- api.write_file container_name, path, content: content
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
@@ -1,5 +1,5 @@
1
1
  module NexusSW
2
2
  module LXD
3
- VERSION = '0.7.0'.freeze
3
+ VERSION = '0.8.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.7.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-15 00:00:00.000000000 Z
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