kitchen-kubernetes 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.travis.yml +50 -0
- data/Gemfile +21 -0
- data/LICENSE +201 -0
- data/README.md +191 -0
- data/Rakefile +17 -0
- data/kitchen-kubernetes.gemspec +50 -0
- data/lib/kitchen-kubernetes/helper.rb +45 -0
- data/lib/kitchen-kubernetes/version.rb +20 -0
- data/lib/kitchen/driver/kubernetes.rb +216 -0
- data/lib/kitchen/driver/pod.yaml.erb +96 -0
- data/lib/kitchen/transport/kubernetes.rb +84 -0
- data/lib/kitchen/verifier/train_kubernetes_hack.rb +90 -0
- data/rsync/Dockerfile +21 -0
- data/test/.kitchen.yml +57 -0
- data/test/cookbooks/test/metadata.rb +17 -0
- data/test/cookbooks/test/recipes/default.rb +30 -0
- data/test/cookbooks/test/recipes/service.rb +28 -0
- data/test/cookbooks/test/templates/template.erb +1 -0
- data/test/gemfiles/master.gemfile +22 -0
- data/test/gemfiles/train-new.gemfile +19 -0
- data/test/gemfiles/train-old.gemfile +19 -0
- data/test/integration/default/serverspec/default_spec.rb +32 -0
- data/test/integration/inspec/default_spec.rb +29 -0
- data/test/integration/service/serverspec/service_spec.rb +23 -0
- metadata +212 -0
@@ -0,0 +1,84 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2017, Noah Kantrowitz
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
require 'shellwords'
|
18
|
+
|
19
|
+
require 'kitchen/login_command'
|
20
|
+
require 'kitchen/shell_out'
|
21
|
+
require 'kitchen/transport/base'
|
22
|
+
|
23
|
+
require 'kitchen-kubernetes/helper'
|
24
|
+
|
25
|
+
|
26
|
+
module Kitchen
|
27
|
+
module Transport
|
28
|
+
|
29
|
+
# Kubernetes transport for Kitchen. Uses kubectl exec.
|
30
|
+
#
|
31
|
+
# @author Noah Kantrowitz <noah@coderanger>
|
32
|
+
# @since 1.0.0
|
33
|
+
# @see Kitchen::Driver::Kubernetes
|
34
|
+
class Kubernetes < Kitchen::Transport::Base
|
35
|
+
# All configuration options can be found in the Driver class.
|
36
|
+
|
37
|
+
# (see Base#connection)
|
38
|
+
def connection(state, &block)
|
39
|
+
# No persistent anything so no need to reuse connections.
|
40
|
+
Connection.new(
|
41
|
+
pod_id: state[:pod_id],
|
42
|
+
kubectl_command: config[:kubectl_command],
|
43
|
+
rsync_command: config[:rsync_command],
|
44
|
+
rsync_rsh: config[:rsync_rsh],
|
45
|
+
log_level: config[:log_level],
|
46
|
+
logger: logger
|
47
|
+
).tap do |conn|
|
48
|
+
block.call(conn) if block
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class Connection < Kitchen::Transport::Base::Connection
|
53
|
+
include ShellOut
|
54
|
+
include KitchenKubernetes::Helper
|
55
|
+
|
56
|
+
# (see Base::Connection#execute)
|
57
|
+
def execute(command)
|
58
|
+
return if command.nil?
|
59
|
+
# Run via kubectl exec.
|
60
|
+
run_command(kubectl_command('exec', '--tty', '--container=default', options[:pod_id], '--', *Shellwords.split(command)))
|
61
|
+
end
|
62
|
+
|
63
|
+
# (see Base::Connection#upload)
|
64
|
+
def upload(locals, remote)
|
65
|
+
return if locals.empty?
|
66
|
+
# Use rsync over kubectl exec to send files.
|
67
|
+
run_command([options[:rsync_command], '--archive', '--progress', '--blocking-io', '--rsh', options[:rsync_rsh]] + (options[:log_level] == :debug ? %w{--verbose --verbose --verbose} : []) + locals + ["#{options[:pod_id]}:#{remote}"])
|
68
|
+
end
|
69
|
+
|
70
|
+
# (see Base::Connection#login_command)
|
71
|
+
def login_command
|
72
|
+
# Find a valid login shell and exec it. This is so weridly complex
|
73
|
+
# because it has to work with a /bin/sh that might be bash, dash, or
|
74
|
+
# busybox. Also CentOS images doesn't have `which` for some reason.
|
75
|
+
# Dash's `type` is super weird so use `which` first in case of dash but
|
76
|
+
# fall back to `type` for basically just CentOS.
|
77
|
+
login_cmd = "IFS=$'\n'; for f in `which bash zsh sh 2>/dev/null || type -P bash zsh sh`; do exec \"$f\" -l; done"
|
78
|
+
cmd = kubectl_command('exec', '--stdin', '--tty', '--container=default', options[:pod_id], '--', '/bin/sh', '-c', login_cmd)
|
79
|
+
LoginCommand.new(cmd[0], cmd.drop(1))
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2017, Noah Kantrowitz
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
# This is copied from https://github.com/chef/train/pull/205 until InSpec can
|
17
|
+
# support it internally. The only changes are to rename with _hack and
|
18
|
+
# back-compat support for the changes in the files API (LinuxFile vs File::Remote::Linux).
|
19
|
+
|
20
|
+
require 'mixlib/shellout'
|
21
|
+
|
22
|
+
require 'train'
|
23
|
+
|
24
|
+
module Train::Transports
|
25
|
+
class KubernetesHack < Train.plugin(1)
|
26
|
+
name 'kubernetes_hack'
|
27
|
+
|
28
|
+
include_options Train::Extras::CommandWrapper
|
29
|
+
option :pod, required: true
|
30
|
+
option :container, default: nil
|
31
|
+
option :kubectl_path, default: 'kubectl'
|
32
|
+
option :context, default: nil
|
33
|
+
|
34
|
+
def connection(state = {})
|
35
|
+
opts = merge_options(options, state || {})
|
36
|
+
validate_options(opts)
|
37
|
+
opts[:logger] ||= logger
|
38
|
+
unless @connection && @connection_opts == opts
|
39
|
+
@connection ||= Connection.new(opts)
|
40
|
+
@connection_opts = opts.dup
|
41
|
+
end
|
42
|
+
@connection
|
43
|
+
end
|
44
|
+
|
45
|
+
class Connection < BaseConnection
|
46
|
+
if Gem::Requirement.create('< 0.30').satisfied_by?(Gem::Version.create(Train::VERSION))
|
47
|
+
# The API for a connection changed a lot in 0.30, this is a compat shim.
|
48
|
+
def os
|
49
|
+
@os ||= OSCommon.new(self, family: 'unix')
|
50
|
+
end
|
51
|
+
|
52
|
+
def file(path)
|
53
|
+
@files[path] ||= file_via_connection(path)
|
54
|
+
end
|
55
|
+
|
56
|
+
def run_command(cmd)
|
57
|
+
run_command_via_connection(cmd)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def file_via_connection(path)
|
62
|
+
defined?(Train::File::Remote::Linux) ? Train::File::Remote::Linux.new(self, path) : LinuxFile.new(self, path)
|
63
|
+
end
|
64
|
+
|
65
|
+
def run_command_via_connection(cmd)
|
66
|
+
kubectl_cmd = [options[:kubectl_path], 'exec']
|
67
|
+
kubectl_cmd.concat(['--context', options[:context]]) if options[:context]
|
68
|
+
kubectl_cmd.concat(['--container', options[:container]]) if options[:container]
|
69
|
+
kubectl_cmd.concat([options[:pod], '--', '/bin/sh', '-c', cmd])
|
70
|
+
|
71
|
+
so = Mixlib::ShellOut.new(kubectl_cmd, logger: logger)
|
72
|
+
so.run_command
|
73
|
+
if so.error?
|
74
|
+
# Trim the "command terminated with exit code N" line from the end
|
75
|
+
# of the stderr content.
|
76
|
+
so.stderr.gsub!(/command terminated with exit code #{so.exitstatus}\n\Z/, '')
|
77
|
+
end
|
78
|
+
CommandResult.new(so.stdout, so.stderr, so.exitstatus)
|
79
|
+
end
|
80
|
+
|
81
|
+
def uri
|
82
|
+
if options[:container]
|
83
|
+
"kubernetes://#{options[:pod]}/#{options[:container]}"
|
84
|
+
else
|
85
|
+
"kubernetes://#{options[:pod]}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/rsync/Dockerfile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2017, Noah Kantrowitz
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
# This is used to build the kitchenkubernetes/rsync image.
|
18
|
+
|
19
|
+
FROM alpine
|
20
|
+
RUN apk add --update-cache rsync
|
21
|
+
ENTRYPOINT ["/bin/sh", "-c", "trap 'exit 0' TERM; sleep 2147483647 & wait"]
|
data/test/.kitchen.yml
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2017, Noah Kantrowitz
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
driver:
|
18
|
+
name: kubernetes
|
19
|
+
|
20
|
+
provisioner:
|
21
|
+
cookbooks_path: test/cookbooks/
|
22
|
+
|
23
|
+
kitchen:
|
24
|
+
test_base_path: <%= File.expand_path('../integration', __FILE__) %>
|
25
|
+
|
26
|
+
platforms:
|
27
|
+
- name: centos-6
|
28
|
+
- name: centos-7
|
29
|
+
- name: ubuntu-14.04
|
30
|
+
- name: ubuntu-16.04
|
31
|
+
- name: debian-7
|
32
|
+
- name: debian-8
|
33
|
+
- name: debian-9
|
34
|
+
- name: amazonlinux-2016.09
|
35
|
+
- name: amazonlinux-2017.03
|
36
|
+
- name: amazonlinux-2017.09
|
37
|
+
- name: fedora-25
|
38
|
+
- name: fedora-26
|
39
|
+
|
40
|
+
suites:
|
41
|
+
- name: default
|
42
|
+
run_list:
|
43
|
+
- recipe[test]
|
44
|
+
- name: service
|
45
|
+
run_list:
|
46
|
+
- recipe[test::service]
|
47
|
+
driver:
|
48
|
+
init_system: systemd
|
49
|
+
includes:
|
50
|
+
- centos-7
|
51
|
+
- ubuntu-16.04
|
52
|
+
- fedora-26
|
53
|
+
- name: inspec
|
54
|
+
run_list:
|
55
|
+
- recipe[test]
|
56
|
+
verifier:
|
57
|
+
name: inspec
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2017, Noah Kantrowitz
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
name 'test'
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2017, Noah Kantrowitz
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
file '/testfile' do
|
18
|
+
owner 'root'
|
19
|
+
group 'root'
|
20
|
+
mode '741'
|
21
|
+
content "I am a teapot\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
template '/testtemplate' do
|
25
|
+
owner 'root'
|
26
|
+
group 'root'
|
27
|
+
mode '444'
|
28
|
+
source 'template.erb'
|
29
|
+
variables chef_version: Chef::VERSION
|
30
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2017, Noah Kantrowitz
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
apt_update if platform_family?('debian')
|
18
|
+
|
19
|
+
package_name = platform_family?('rhel', 'amazon', 'fedora') ? 'httpd' : 'apache2'
|
20
|
+
|
21
|
+
package package_name
|
22
|
+
|
23
|
+
service package_name do
|
24
|
+
action [:enable, :start]
|
25
|
+
end
|
26
|
+
|
27
|
+
# For tests.
|
28
|
+
package 'curl'
|
@@ -0,0 +1 @@
|
|
1
|
+
ver=<%= @chef_version %>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2017, Noah Kantrowitz
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
eval_gemfile File.expand_path('../../../Gemfile', __FILE__)
|
18
|
+
|
19
|
+
gem 'train', github: 'chef/train'
|
20
|
+
gem 'inspec', github: 'chef/inspec'
|
21
|
+
gem 'kitchen-inspec', github: 'chef/kitchen-inspec'
|
22
|
+
gem 'test-kitchen', github: 'test-kitchen/test-kitchen'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2017, Noah Kantrowitz
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
eval_gemfile File.expand_path('../../../Gemfile', __FILE__)
|
18
|
+
|
19
|
+
gem 'train', '>= 0.30'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2017, Noah Kantrowitz
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
eval_gemfile File.expand_path('../../../Gemfile', __FILE__)
|
18
|
+
|
19
|
+
gem 'train', '< 0.30'
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2017, Noah Kantrowitz
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
require 'serverspec'
|
18
|
+
set :backend, :exec
|
19
|
+
|
20
|
+
describe file('/testfile') do
|
21
|
+
it { is_expected.to be_a_file }
|
22
|
+
it { is_expected.to be_owned_by 'root' }
|
23
|
+
it { is_expected.to be_mode 741 }
|
24
|
+
its(:content) { is_expected.to eq "I am a teapot\n" }
|
25
|
+
end
|
26
|
+
|
27
|
+
describe file('/testtemplate') do
|
28
|
+
it { is_expected.to be_a_file }
|
29
|
+
it { is_expected.to be_owned_by 'root' }
|
30
|
+
it { is_expected.to be_mode 444 }
|
31
|
+
its(:content) { is_expected.to match /^ver=13/ }
|
32
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2017, Noah Kantrowitz
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
describe file('/testfile') do
|
18
|
+
it { is_expected.to be_a_file }
|
19
|
+
it { is_expected.to be_owned_by 'root' }
|
20
|
+
it { is_expected.to be_mode 0741 }
|
21
|
+
its(:content) { is_expected.to eq "I am a teapot\n" }
|
22
|
+
end
|
23
|
+
|
24
|
+
describe file('/testtemplate') do
|
25
|
+
it { is_expected.to be_a_file }
|
26
|
+
it { is_expected.to be_owned_by 'root' }
|
27
|
+
it { is_expected.to be_mode 0444 }
|
28
|
+
its(:content) { is_expected.to match /^ver=13/ }
|
29
|
+
end
|