train-kubernetes 0.1.10 → 0.2.1

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: f788de94eac3afedbc4427c3eae60e65993db25a5ce55e8797218f580f7a080a
4
+ data.tar.gz: 34a3701bdd160f580ac711b7cbfd61373205327431d90f617de7e566f0c4d6a6
5
5
  SHA512:
6
- metadata.gz: dfd9ca8003441da0bb8abd13f6a5ceae755239f406201b76d94ec2088a07ea12cc29e2fbe0a7132e4e6745910752823c9753a3b17585b39de62e1a5527192c6c
7
- data.tar.gz: c50d9c99fe60b9b51b71b789f7c233815cf0391a89d8ffa6bc2faaae3f5f74e416211400b02e273da1f8c4348f4e749ce368eba5148acefa91faf43a533610fc
6
+ metadata.gz: 337bd696715b5da5c78788eaa2d896d36275d43106c929376bfb8515ec7aeaf86b2a0581f360462762a7c42187e73178fbe031cf58f77513a87ad184653635b7
7
+ data.tar.gz: d50c0cd6308a3dc2d4fd5cd7b0648797e74d6f908146f725454639d9f670c8252705fe9f045931964c9a2d81274731583c166352f37804b6d7ddb2897e843ad7
data/README.md CHANGED
@@ -4,7 +4,7 @@ This plugin allows applications that rely on Train to communicate with the Kuber
4
4
 
5
5
  ## Usage
6
6
 
7
- When used in combination with the [InSpec Kubernetes Resource Pack](https://github.com/bgeesaman/inspec-k8s) you can validate the spec of any Kubernetes resource you have access to:
7
+ When used in combination with the [InSpec Kubernetes Resource Pack](https://github.com/inspec/inspec-k8s) you can validate the spec of any Kubernetes resource you have access to:
8
8
 
9
9
  ```ruby
10
10
  describe k8sobjects(api: 'v1', type: 'pods', namespace: 'default', labelSelector: 'run=nginx') do
@@ -28,15 +28,23 @@ 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+
34
41
  - Ruby 2.4+
35
42
  - You have set the env var KUBECONFIG or have a valid ~/.kube/config
36
43
 
37
-
38
44
  ## Installation
39
45
 
46
+ **_NOTE:_** **_The train-kubernetes plugin now comes included with InSpec 5.22.0 and later, and does not require installation separately._**
47
+
40
48
  Train plugins are distributed as gems. You may choose to manage the gem yourself, but if you are an InSpec user, InSPec can handle it for you.
41
49
 
42
50
  First, run:
@@ -75,18 +83,18 @@ Families: cloud, api
75
83
  Release: 0.1.3
76
84
  ```
77
85
 
78
- ## Troubleshooting
86
+ ## Troubleshooting (Only applicable for InSpec version 5.21.* and earlier)
79
87
 
80
88
  If you run into issues installing via `inspec plugin install train-kubernetes`, try:
81
89
 
82
90
  * Try running `gem install train-kubernetes` before `inspec plugin install train-kubernetes`.
83
- * Ensure the `~/.inspec/plugins.json` has `"0.1.3"` and not `"= 0.1.3"` for the `version` value. Modify it by hand if needed.
91
+ * Ensure the `~/.inspec/plugins.json` has `"0.1.3"` and not `"= 0.1.3"` for the `version` value. Modify it by hand if needed.
84
92
  * Ensure you can cleanly install the `k8s-ruby` gem version `0.10.4` or greater. e.g. `gem install k8s-ruby -v 0.10.4`
85
93
  * Ensure that only one version of the `excon` gem is installed. e.g. `gem list | grep excon`. If you see two versions, `gem uninstall excon` and remove the older version.
86
94
 
87
95
  ## Reporting Issues
88
96
 
89
- Bugs, typos, limitations, and frustrations are welcome to be reported through the [GitHub issues page for the train-kubernetes project](https://github.com/bgeesaman/train-kubernetes/issues).
97
+ Bugs, typos, limitations, and frustrations are welcome to be reported through the [GitHub issues page for the train-kubernetes project](https://github.com/inspec/train-kubernetes/issues).
90
98
 
91
99
  You may also ask questions in the #inspec channel of the Chef Community Slack team. However, for an issue to get traction, please report it as a github issue.
92
100
 
@@ -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.2.1".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'
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.email = ['bradgeesaman@gmail.com']
20
20
  spec.summary = 'Train Kubernetes'
21
21
  spec.description = 'A Train "transport" plugin for Chef Inspec that allows testing of all Kubernetes API resources'
22
- spec.homepage = 'https://github.com/bgeesaman/train-kubernetes'
22
+ spec.homepage = 'https://github.com/inspec/train-kubernetes'
23
23
  spec.license = 'Apache-2.0'
24
24
 
25
25
  spec.required_ruby_version = '>= 2.4'
@@ -44,7 +44,7 @@ Gem::Specification.new do |spec|
44
44
  # Do not list inspec as a dependency of the train plugin.
45
45
 
46
46
  # All plugins should mention train, > 1.4
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'
47
+ # pinning k8s-ruby to 0.16.0 since it has support for Ruby version 3.2
48
+ spec.add_dependency 'k8s-ruby', '~> 0.16.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.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brad Geesaman
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-15 00:00:00.000000000 Z
11
+ date: 2024-02-13 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.16.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.16.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: train
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -50,12 +50,15 @@ 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
56
59
  - lib/train-kubernetes/version.rb
57
60
  - train-kubernetes.gemspec
58
- homepage: https://github.com/bgeesaman/train-kubernetes
61
+ homepage: https://github.com/inspec/train-kubernetes
59
62
  licenses:
60
63
  - Apache-2.0
61
64
  metadata: {}