train-kubernetes 0.1.10 → 0.1.12

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: 7e4bbb998822377221a31b8839373f73d298d6f2bd4226300ff8428742ca247c
4
- data.tar.gz: e87a4add57561718dc7780d20aa0741de23e9bc615108dd139609377edb4d05b
3
+ metadata.gz: fcca2f4cc7de5b099cb5a3ee64e8ec7e935fdb986234d4ca9a3659d73efa874e
4
+ data.tar.gz: 15006a25d2cc0a823e21025d0b9f02cdd75bcefcac6965a28b17735147c1a4df
5
5
  SHA512:
6
- metadata.gz: dfd9ca8003441da0bb8abd13f6a5ceae755239f406201b76d94ec2088a07ea12cc29e2fbe0a7132e4e6745910752823c9753a3b17585b39de62e1a5527192c6c
7
- data.tar.gz: c50d9c99fe60b9b51b71b789f7c233815cf0391a89d8ffa6bc2faaae3f5f74e416211400b02e273da1f8c4348f4e749ce368eba5148acefa91faf43a533610fc
6
+ metadata.gz: 17df60f7afdf0948ea15ce899b97b3aa33ba2173e87715c2b736783644a48aae037112188c570aab65f2cc3f40978e16c43c716c489623a7f556757b9204bfa6
7
+ data.tar.gz: 47f38cc6b1b41873f411da7a6fc3be723d2ead3cf5a0b225367a5bd6bfe518a57eb06f1805e1557d708d8e3c161881a4b4dbc6747aaaf0e760573795c5a43f38
data/README.md CHANGED
@@ -28,6 +28,13 @@ describe k8sobject(api: 'v1', type: 'pod', namespace: 'default', name: 'my-pod')
28
28
  end
29
29
  ```
30
30
 
31
+ ## File resource
32
+ ```ruby
33
+ inspec.backend.file('PATH', pod: 'POD', container: 'CONTAINER', namespace: 'NAMESPACE')
34
+ ```
35
+ Currently it supports only Linux based containers
36
+
37
+
31
38
  ## Preconditions
32
39
 
33
40
  - InSpec 3.7+ or 4.x+
@@ -36,7 +36,7 @@ module TrainPlugins
36
36
 
37
37
  def parse_kubeconfig
38
38
  kubeconfig_file = @options[:kubeconfig] if @options[:kubeconfig]
39
- @client = K8s::Client.config(K8s::Config.load_file(File.expand_path(kubeconfig_file)))
39
+ @client = K8s::Client.config(K8s::Config.load_file(::File.expand_path(kubeconfig_file)))
40
40
  end
41
41
 
42
42
  private
@@ -49,6 +49,10 @@ module TrainPlugins
49
49
  namespace: opts[:namespace] || namespace)
50
50
  .execute(cmd)
51
51
  end
52
+
53
+ def file_via_connection(path, **args)
54
+ TrainPlugins::TrainKubernetes::File::Linux.new(self, path, pod: args[:pod], container: args[:container], namespace: args[:namespace])
55
+ end
52
56
  end
53
57
  end
54
58
  end
@@ -0,0 +1,149 @@
1
+ require 'train/file/remote/linux'
2
+ require 'train/extras/stat'
3
+
4
+ module TrainPlugins
5
+ module TrainKubernetes
6
+ module File
7
+ class Linux < ::Train::File::Remote::Linux
8
+ def initialize(backend, path, follow_symlink = true, pod:, **args)
9
+ @backend = backend
10
+ @path = path || ''
11
+ @follow_symlink = follow_symlink
12
+ @pod = pod
13
+ @container = args[:container]
14
+ @namespace = args[:namespace]
15
+
16
+ sanitize_filename(path)
17
+ super(backend, path, follow_symlink)
18
+ end
19
+
20
+ def content
21
+ return @content if defined?(@content)
22
+
23
+ @content = @backend.run_command("cat #{@spath} || echo -n",
24
+ { pod: pod, namespace: namespace, container: container })
25
+ .stdout
26
+ return @content unless @content.empty?
27
+
28
+ @content = nil if directory? || size.nil? || (size > 0)
29
+ @content
30
+ end
31
+
32
+ def content=(new_content)
33
+ execute_result = @backend.run_command('base64 --help', { pod: pod, namespace: namespace, container: container })
34
+ if execute_result.exit_status != 0
35
+ raise TransportError, "#{self.class} found no base64 binary for file writes"
36
+ end
37
+
38
+ unix_cmd = format("echo '%<base64>s' | base64 --decode > %<file>s",
39
+ base64: Base64.strict_encode64(new_content),
40
+ file: @spath)
41
+
42
+ @backend.run_command(unix_cmd, { pod: pod, namespace: namespace, container: container })
43
+
44
+ @content = new_content
45
+ end
46
+
47
+ def exist?
48
+ @exist ||= begin
49
+ f = @follow_symlink ? '' : " || test -L #{@spath}"
50
+ @backend.run_command("test -e #{@spath}" + f,
51
+ { pod: pod, namespace: namespace, container: container })
52
+ .exit_status == 0
53
+ end
54
+ end
55
+
56
+ def mounted
57
+ @mounted ||=
58
+ @backend.run_command("mount | grep -- ' on #{@path} '",
59
+ { pod: pod, namespace: namespace, container: container })
60
+ end
61
+
62
+ def path
63
+ return @path unless @follow_symlink && symlink?
64
+
65
+ @link_path ||= read_target_path
66
+ end
67
+
68
+ def shallow_link_path
69
+ return nil unless symlink?
70
+
71
+ @shallow_link_path ||=
72
+ @backend.run_command("readlink #{@spath}", { pod: pod, namespace: namespace, container: container })
73
+ .stdout
74
+ .chomp
75
+ end
76
+
77
+ def stat
78
+ @stat ||= begin
79
+ shell_escaped_path = @spath
80
+ backend = @backend
81
+ follow_symlink = @follow_symlink
82
+ lstat = follow_symlink ? ' -L' : ''
83
+ format = '--printf'
84
+ res = backend.run_command("stat#{lstat} #{shell_escaped_path} 2>/dev/null #{format} '%s\n%f\n%U\n%u\n%G\n%g\n%X\n%Y\n%C'",
85
+ { pod: pod, namespace: namespace, container: container })
86
+ # ignore the exit_code: it is != 0 if selinux labels are not supported
87
+ # on the system.
88
+
89
+ fields = res.stdout.split("\n")
90
+ return {} if fields.length != 9
91
+
92
+ tmask = fields[1].to_i(16)
93
+ selinux = fields[8]
94
+ ## selinux security context string not available on esxi
95
+ selinux = nil if (selinux == '?') || (selinux == '(null)') || (selinux == 'C')
96
+ {
97
+ type: Train::Extras::Stat.find_type(tmask),
98
+ mode: tmask & 07777,
99
+ owner: fields[2],
100
+ uid: fields[3].to_i,
101
+ group: fields[4],
102
+ gid: fields[5].to_i,
103
+ mtime: fields[7].to_i,
104
+ size: fields[0].to_i,
105
+ selinux_label: selinux
106
+ }
107
+ end
108
+ end
109
+
110
+ def source
111
+ if @follow_symlink
112
+ self.class.new(@backend, @path, false, pod: pod, container: container, namespace: namespace)
113
+ else
114
+ self
115
+ end
116
+ end
117
+
118
+ def user_permissions
119
+ return {} unless exist?
120
+
121
+ skip_reource '`user_permissions` is not supported on your Linux Containers yet.'
122
+ end
123
+
124
+ def inherited?
125
+ return false unless exist?
126
+
127
+ skip_resource '`inherited?` is not supported on your Linux Containers yet.'
128
+ end
129
+
130
+ private
131
+
132
+ # Returns full path of a symlink target(real dest) or '' on symlink loop
133
+ def read_target_path
134
+ full_path = @backend.run_command("readlink -n #{@spath} -f",
135
+ { pod: pod, namespace: namespace, container: container })
136
+ .stdout
137
+ # Needed for some OSes like OSX that returns relative path
138
+ # when the link and target are in the same directory
139
+ if !full_path.start_with?('/') && full_path != ''
140
+ full_path = ::File.expand_path("../#{full_path}", @spath)
141
+ end
142
+ full_path
143
+ end
144
+
145
+ attr_reader :pod, :container, :namespace
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,50 @@
1
+ require 'inspec/resources/file'
2
+ require 'inspec/exceptions'
3
+
4
+ module TrainPlugins
5
+ module TrainKubernetes
6
+ module File
7
+ class LinuxImmutableFileCheck < Inspec::Resources::LinuxImmutableFlagCheck
8
+ def initialize(inspec, file, pod:, container: nil, namespace: nil)
9
+ @pod = pod
10
+ @container = container
11
+ @namespace = namespace
12
+ super(inspec, file)
13
+ end
14
+
15
+ def find_utility_or_error(utility_name)
16
+ %W(/usr/sbin/#{utility_name} /sbin/#{utility_name} /usr/bin/#{utility_name} /bin/#{utility_name} #{utility_name}).each do |cmd|
17
+ if inspec.backend
18
+ .run_command("sh -c 'type \"#{cmd}\"'", { pod: pod, container: container, namespace: namespace })
19
+ .exit_status.to_i == 0
20
+ return cmd
21
+ end
22
+ end
23
+
24
+ raise Inspec::Exceptions::ResourceFailed, "Could not find `#{utility_name}`"
25
+ end
26
+
27
+ def is_immutable?
28
+ # Check if lsattr is available. In general, all linux system has lsattr & chattr
29
+ # This logic check is valid for immutable flag set with chattr
30
+ utility = find_utility_or_error('lsattr')
31
+
32
+ utility_cmd = inspec.backend.run_command("#{utility} #{file_path}",
33
+ { pod: pod, container: container, namespace: namespace })
34
+
35
+ raise Inspec::Exceptions::ResourceFailed, "Executing #{utility} #{file_path} failed: #{utility_cmd.stderr}" if utility_cmd.exit_status.to_i != 0
36
+
37
+ # General output for lsattr file_name is:
38
+ # ----i---------e----- file_name
39
+ # The fifth char resembles the immutable flag. Total 20 flags are allowed.
40
+ lsattr_info = utility_cmd.stdout.strip.squeeze(' ')
41
+ lsattr_info =~ /^.{4}i.{15} .*/
42
+ end
43
+
44
+ private
45
+
46
+ attr_reader :pod, :container, :namespace
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,25 @@
1
+ module TrainPlugins
2
+ module TrainKubernetes
3
+ module File
4
+ class LinuxPermissions < Inspec::Resources::UnixFilePermissions
5
+ def initialize(inspec, pod:, namespace: nil, container: nil)
6
+ @pod = pod
7
+ @namespace = namespace
8
+ @container = container
9
+ super(inspec)
10
+ end
11
+
12
+ def check_file_permission_by_user(access_type, user, path)
13
+ flag = permission_flag(access_type)
14
+ perm_cmd = "su -s /bin/sh -c \"test -#{flag} #{path}\" #{user}"
15
+ cmd = inspec.backend.run_command(perm_cmd, { pod: pod, namespace: namespace, container: container })
16
+ cmd.exit_status == 0
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :pod, :container, :namespace
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,9 +1,11 @@
1
1
  require 'mixlib/shellout'
2
+ require 'train/extras'
2
3
 
3
4
  module TrainPlugins
4
5
  module TrainKubernetes
5
6
  class KubectlClient
6
7
  attr_reader :pod, :container, :namespace
8
+
7
9
  DEFAULT_NAMESPACE = 'default'.freeze
8
10
 
9
11
  def initialize(pod:, namespace: nil, container: nil)
@@ -15,7 +17,10 @@ module TrainPlugins
15
17
  def execute(command, stdin: true, tty: true)
16
18
  instruction = build_instruction(command, stdin, tty)
17
19
  shell = Mixlib::ShellOut.new(instruction)
18
- shell.run_command
20
+ res = shell.run_command
21
+ Train::Extras::CommandResult.new(res.stdout, res.stderr, res.exitstatus)
22
+ rescue Errno::ENOENT => _e
23
+ Train::Extras::CommandResult.new('', '', 1)
19
24
  end
20
25
 
21
26
  private
@@ -24,7 +29,7 @@ module TrainPlugins
24
29
  @shell ||= Mixlib::ShellOut.new(instruction)
25
30
  end
26
31
 
27
- def build_instruction(command, stdin, tty)
32
+ def build_instruction(command, stdin, _tty)
28
33
  ['kubectl exec'].tap do |arr|
29
34
  arr << '--stdin' if stdin
30
35
  arr << pod if pod
@@ -5,6 +5,6 @@
5
5
 
6
6
  module TrainPlugins
7
7
  module TrainKubernetes
8
- VERSION = '0.1.10'.freeze
8
+ VERSION = '0.1.12'.freeze
9
9
  end
10
10
  end
@@ -18,3 +18,4 @@ require 'train-kubernetes/version'
18
18
  # Transport acts as the glue.
19
19
  require 'train-kubernetes/transport'
20
20
  require 'train-kubernetes/platform'
21
+ require 'train-kubernetes/file/linux'
@@ -45,6 +45,6 @@ Gem::Specification.new do |spec|
45
45
 
46
46
  # All plugins should mention train, > 1.4
47
47
  # pinning k8s-ruby to 0.10.5 to avoid broken dry-type gem upgrades from k8s-ruby
48
- spec.add_dependency 'k8s-ruby', '0.10.5'
48
+ spec.add_dependency 'k8s-ruby', '~> 0.14.0'
49
49
  spec.add_dependency 'train', '~> 3.0'
50
50
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: train-kubernetes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.1.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brad Geesaman
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-15 00:00:00.000000000 Z
11
+ date: 2023-04-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: k8s-ruby
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '='
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.10.5
19
+ version: 0.14.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '='
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.10.5
26
+ version: 0.14.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: train
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -50,6 +50,9 @@ files:
50
50
  - README.md
51
51
  - lib/train-kubernetes.rb
52
52
  - lib/train-kubernetes/connection.rb
53
+ - lib/train-kubernetes/file/linux.rb
54
+ - lib/train-kubernetes/file/linux_immutable_file_check.rb
55
+ - lib/train-kubernetes/file/linux_permissions.rb
53
56
  - lib/train-kubernetes/kubectl_client.rb
54
57
  - lib/train-kubernetes/platform.rb
55
58
  - lib/train-kubernetes/transport.rb
@@ -59,7 +62,7 @@ homepage: https://github.com/bgeesaman/train-kubernetes
59
62
  licenses:
60
63
  - Apache-2.0
61
64
  metadata: {}
62
- post_install_message:
65
+ post_install_message:
63
66
  rdoc_options: []
64
67
  require_paths:
65
68
  - lib
@@ -74,8 +77,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
74
77
  - !ruby/object:Gem::Version
75
78
  version: '0'
76
79
  requirements: []
77
- rubygems_version: 3.1.4
78
- signing_key:
80
+ rubygems_version: 3.3.7
81
+ signing_key:
79
82
  specification_version: 4
80
83
  summary: Train Kubernetes
81
84
  test_files: []