kitchen-dockerwin 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +39 -18
- data/lib/docker/version.rb +4 -0
- data/lib/kitchen/driver/dockerwin.rb +10 -2
- data/lib/kitchen/transport/dockercli.rb +8 -19
- data/lib/train/transports/docker.rb +114 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5e16d92ee864f0a22897d63b80edebc3a9599d973305015c42cfd5a4bdf9c499
|
4
|
+
data.tar.gz: ce7831bee20da9da43d039218513ec0dad660686fc5a0b67ef86328bb799388c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31da27b932da0714fd1d59aaffcc3e8d0035e3763a4c415065bde6cefcfa9a623bf4d83b5d61c86d14f2495ca215abde454147094ae531e3ec300b16d12c07c7
|
7
|
+
data.tar.gz: 1d24a81b2203221c11ec0f2f8410861e0f6eb103742baafcaaff61e2c3f5b9abd151f450923c59c5982da905001abf9b1e645d78ec3da66de5b399253951eebd
|
data/README.md
CHANGED
@@ -1,40 +1,49 @@
|
|
1
1
|
# kitchen-dockerwin
|
2
2
|
|
3
|
-
An experimental Test Kitchen driver that supports Windows
|
4
|
-
|
5
|
-
**NOTE: `kitchen verify` is not yet supported when using this tool with InSpec.**
|
3
|
+
An experimental Test Kitchen driver that supports Windows Containers via Docker on a Windows workstation.
|
6
4
|
|
7
5
|
# Quickstart
|
8
6
|
|
9
|
-
You'll need
|
7
|
+
You'll need a workstation (Windows 10, Windows Server 2016 or higher) with Docker for Windows installed, running and configured to be able to run Windows Containers, and a working ChefDK installation (alternatively Ruby + Devkit + Test Kitchen gem).
|
8
|
+
|
9
|
+
## Docker Configuration
|
10
10
|
|
11
|
-
|
11
|
+
Edit the configuration file (usually located at `C:\ProgramData\docker\config\daemon.json`) and replace the configuration with the following, (i.e. adding the "hosts" value):
|
12
12
|
|
13
13
|
```
|
14
|
-
|
14
|
+
{
|
15
|
+
"registry-mirrors": [],
|
16
|
+
"insecure-registries": [],
|
17
|
+
"debug": true,
|
18
|
+
"experimental": false,
|
19
|
+
"hosts": ["tcp://0.0.0.0:2375"]
|
20
|
+
}
|
15
21
|
```
|
22
|
+
Restart Docker. You may wish to remove any previously-running images using `docker rm $(docker ps -a -q)`
|
23
|
+
|
24
|
+
Ensure that Docker is running in Windows Container mode (right click the Docker icon in the System Notification area > **Switch to Windows containers** to be sure).
|
16
25
|
|
17
|
-
|
26
|
+
## Install the gem (assumes Chef Workstation/Chef DK installation)
|
18
27
|
|
19
28
|
```
|
20
29
|
chef gem install kitchen-dockerwin
|
21
30
|
```
|
22
31
|
|
23
|
-
##
|
32
|
+
## Create base container image
|
24
33
|
|
25
|
-
Whilst
|
34
|
+
Whilst you can use any compatible Windows Server image for your kernel, converge time will be improved if you can build your own image that adds the Chef Infra Client to the Windows Server Core image.
|
26
35
|
|
27
|
-
|
36
|
+
To build your own image, create a `Dockerfile` as follows:
|
28
37
|
|
29
38
|
```
|
30
39
|
FROM mcr.microsoft.com/windows/servercore:ltsc2019
|
31
|
-
RUN ["powershell", "-executionpolicy unrestricted", "-noninteractive", "-command", ". { iwr -useb https://omnitruck.chef.io/install.ps1 } | iex; install;"]
|
40
|
+
RUN ["powershell.exe", "-executionpolicy unrestricted", "-noninteractive", "-command", ". { iwr -useb https://omnitruck.chef.io/install.ps1 } | iex; install; remove-item $env:TEMP\\*.msi -force"]
|
32
41
|
```
|
33
42
|
|
34
|
-
Example command line to build image:
|
43
|
+
Example command line to build the Docker image:
|
35
44
|
|
36
45
|
```
|
37
|
-
PS> docker build -t stuartpreston/chef-client:
|
46
|
+
PS> docker build . -t stuartpreston/chef-client:latest
|
38
47
|
```
|
39
48
|
|
40
49
|
## Example kitchen.yml
|
@@ -50,22 +59,34 @@ provisioner:
|
|
50
59
|
install_strategy: skip
|
51
60
|
chef_client_path: c:\opscode\chef\bin\chef-client.bat
|
52
61
|
|
53
|
-
transport:
|
54
|
-
name: dockercli
|
55
|
-
|
56
62
|
verifier:
|
57
|
-
name:
|
63
|
+
name: inspec
|
58
64
|
|
59
65
|
platforms:
|
60
66
|
- name: windows2019
|
61
67
|
driver:
|
62
|
-
image: stuartpreston/chef-client:
|
68
|
+
image: stuartpreston/chef-client:latest
|
63
69
|
skip_pull: true
|
64
70
|
|
65
71
|
suites:
|
66
72
|
- name: default
|
67
73
|
```
|
68
74
|
|
75
|
+
# Troubleshooting
|
76
|
+
|
77
|
+
## "No such container"
|
78
|
+
```
|
79
|
+
>>>>>> Failed to complete #verify action: [{"message":"No such container: f362e060cdc97feb4ff12ac22d072891558a80c93f207e31e8ccb9d7924fc6b4"}
|
80
|
+
] on default-windows2019
|
81
|
+
```
|
82
|
+
Probable cause: Stale state file. If the container has been killed and removed (check with `docker ps -a`), then remove the .kitchen/*.yml file and retry.
|
83
|
+
|
84
|
+
# Known Issues/Limitations
|
85
|
+
|
86
|
+
* No support for Linux Containers on Windows (yet!)
|
87
|
+
* Some Chef Infra Client features are unsupported when running in Windows Containers, such as resources that are dependent on the WMI stack (including WinRM)
|
88
|
+
* `kitchen destroy` (i.e. kill and remove container) can take in excess of 1 minute on Windows.
|
89
|
+
|
69
90
|
# License
|
70
91
|
|
71
92
|
Apache License 2.0
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'kitchen/shell_out'
|
2
|
+
require 'kitchen/transport/dockercli'
|
2
3
|
|
3
4
|
module Kitchen
|
4
5
|
module Driver
|
@@ -12,8 +13,8 @@ module Kitchen
|
|
12
13
|
|
13
14
|
def create(state)
|
14
15
|
run_command("docker pull #{instance.driver[:image]}") unless config[:skip_pull]
|
15
|
-
mount_options = "
|
16
|
-
container_id = run_command("docker run -idt #{mount_options} --name #{instance.name} #{instance.driver[:image]}").strip
|
16
|
+
mount_options = config[:mount_options] || "type=bind,source=\"#{ENV['TEMP']}\",target=\"#{ENV['TEMP']},readonly\""
|
17
|
+
container_id = run_command("docker run -idt --mount #{mount_options} --name #{instance.name} #{instance.driver[:image]}").strip
|
17
18
|
state[:container_id] = container_id
|
18
19
|
end
|
19
20
|
|
@@ -26,6 +27,13 @@ module Kitchen
|
|
26
27
|
run_command("docker rm #{container_id} > nul")
|
27
28
|
state.delete(:container_id)
|
28
29
|
end
|
30
|
+
|
31
|
+
# Force the driver to use the Dockercli transport
|
32
|
+
def finalize_config!(instance)
|
33
|
+
super.tap do
|
34
|
+
instance.transport = Kitchen::Transport::Dockercli.new
|
35
|
+
end
|
36
|
+
end
|
29
37
|
end
|
30
38
|
end
|
31
39
|
end
|
@@ -20,46 +20,35 @@ module Kitchen
|
|
20
20
|
|
21
21
|
class Connection < Kitchen::Transport::Base::Connection
|
22
22
|
include ShellOut
|
23
|
-
|
23
|
+
|
24
24
|
def execute(command)
|
25
25
|
return if command.nil?
|
26
|
-
|
27
|
-
|
28
|
-
translated_path = translate_path(tempfile_path)
|
26
|
+
debug command
|
27
|
+
tempfile = File.join(ENV['TEMP'], "#{SecureRandom.hex(4)}.ps1")
|
29
28
|
begin
|
30
|
-
File.open((
|
31
|
-
dockered_command = "docker exec #{options[:container_id]} powershell.exe -noprofile -
|
29
|
+
File.open((tempfile), 'w') { |file| file.write(command) }
|
30
|
+
dockered_command = "docker exec #{options[:container_id]} powershell.exe -noprofile -executionpolicy unrestricted -file #{tempfile}"
|
32
31
|
run_command(dockered_command)
|
33
32
|
ensure
|
34
|
-
File.unlink(
|
33
|
+
File.unlink(tempfile)
|
35
34
|
end
|
36
35
|
end
|
37
36
|
|
38
37
|
def upload(locals, remote)
|
39
38
|
powershell_commands = Array.new
|
40
39
|
Array(locals).each do |local|
|
41
|
-
|
40
|
+
powershell_commands << "copy-item #{local} #{remote} -force -recurse;"
|
42
41
|
end
|
43
42
|
execute(powershell_commands.join)
|
44
43
|
end
|
45
44
|
|
46
45
|
def download(remotes, local)
|
47
|
-
|
48
|
-
Array(remotes).each do |remote|
|
49
|
-
powershell_commands << "copy-item #{remote} #{translate_path(local)} -force -recurse;"
|
50
|
-
end
|
51
|
-
execute(powershell_commands.join)
|
46
|
+
raise "Download not supported."
|
52
47
|
end
|
53
48
|
|
54
49
|
def login_command
|
55
50
|
LoginCommand.new("docker exec -it #{options[:container_id]} powershell.exe -noprofile -executionpolicy unresticted", nil)
|
56
51
|
end
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
def translate_path(path)
|
61
|
-
path.downcase.gsub("c:", "\/mnt\/c")
|
62
|
-
end
|
63
52
|
end
|
64
53
|
end
|
65
54
|
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Author:: Dominik Richter
|
4
|
+
# Author:: Christoph Hartmann
|
5
|
+
|
6
|
+
require 'docker'
|
7
|
+
|
8
|
+
module Train::Transports
|
9
|
+
class Docker < Train.plugin(1)
|
10
|
+
name 'docker'
|
11
|
+
|
12
|
+
include_options Train::Extras::CommandWrapper
|
13
|
+
option :host, required: true
|
14
|
+
|
15
|
+
def connection(state = {}, &block)
|
16
|
+
opts = merge_options(options, state || {})
|
17
|
+
validate_options(opts)
|
18
|
+
|
19
|
+
if @connection && @connection_options == opts
|
20
|
+
reuse_connection(&block)
|
21
|
+
else
|
22
|
+
create_new_connection(opts, &block)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# Creates a new Docker connection instance and save it for potential future
|
29
|
+
# reuse.
|
30
|
+
#
|
31
|
+
# @param options [Hash] connection options
|
32
|
+
# @return [Docker::Connection] a Docker connection instance
|
33
|
+
# @api private
|
34
|
+
def create_new_connection(options, &block)
|
35
|
+
if @connection
|
36
|
+
logger.debug("[Docker] shutting previous connection #{@connection}")
|
37
|
+
@connection.close
|
38
|
+
end
|
39
|
+
|
40
|
+
@connection_options = options
|
41
|
+
@connection = Connection.new(options, &block)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Return the last saved Docker connection instance.
|
45
|
+
#
|
46
|
+
# @return [Docker::Connection] a Docker connection instance
|
47
|
+
# @api private
|
48
|
+
def reuse_connection
|
49
|
+
logger.debug("[Docker] reusing existing connection #{@connection}")
|
50
|
+
yield @connection if block_given?
|
51
|
+
@connection
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class Train::Transports::Docker
|
57
|
+
class Connection < BaseConnection
|
58
|
+
def initialize(conf)
|
59
|
+
super(conf)
|
60
|
+
@id = options[:host]
|
61
|
+
@container = ::Docker::Container.get(@id) ||
|
62
|
+
fail("Can't find Docker container #{@id}")
|
63
|
+
@cmd_wrapper = nil
|
64
|
+
@cmd_wrapper = CommandWrapper.load(self, @options)
|
65
|
+
self
|
66
|
+
end
|
67
|
+
|
68
|
+
def close
|
69
|
+
# nothing to do at the moment
|
70
|
+
end
|
71
|
+
|
72
|
+
def uri
|
73
|
+
if @container.nil?
|
74
|
+
"docker://#{@id}"
|
75
|
+
else
|
76
|
+
"docker://#{@container.id}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def file_via_connection(path)
|
83
|
+
if os.aix?
|
84
|
+
Train::File::Remote::Aix.new(self, path)
|
85
|
+
elsif os.solaris?
|
86
|
+
Train::File::Remote::Unix.new(self, path)
|
87
|
+
elsif os.windows?
|
88
|
+
Train::File::Remote::Windows.new(self, path)
|
89
|
+
else
|
90
|
+
Train::File::Remote::Linux.new(self, path)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def platform_specific_cmd(cmd)
|
95
|
+
return cmd if @container.info.nil?
|
96
|
+
if @container.info['Platform'] == 'windows'
|
97
|
+
return ['cmd.exe', '/c', cmd]
|
98
|
+
else
|
99
|
+
return ['/bin/sh', '-c', cmd]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def run_command_via_connection(cmd, &_data_handler)
|
104
|
+
cmd = @cmd_wrapper.run(cmd) unless @cmd_wrapper.nil?
|
105
|
+
stdout, stderr, exit_status = @container.exec(platform_specific_cmd(cmd))
|
106
|
+
CommandResult.new(stdout.join, stderr.join, exit_status)
|
107
|
+
rescue ::Docker::Error::DockerError => _
|
108
|
+
raise
|
109
|
+
rescue => _
|
110
|
+
# @TODO: differentiate any other error
|
111
|
+
raise
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kitchen-dockerwin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stuart Preston
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-05-
|
11
|
+
date: 2019-05-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -75,8 +75,10 @@ extra_rdoc_files: []
|
|
75
75
|
files:
|
76
76
|
- LICENSE
|
77
77
|
- README.md
|
78
|
+
- lib/docker/version.rb
|
78
79
|
- lib/kitchen/driver/dockerwin.rb
|
79
80
|
- lib/kitchen/transport/dockercli.rb
|
81
|
+
- lib/train/transports/docker.rb
|
80
82
|
homepage: https://github.com/stuartpreston/kitchen-dockerwin
|
81
83
|
licenses:
|
82
84
|
- Apache-2.0
|