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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c3b313fb472cf7a3b8990f786fc57ef612119bd3915a760c80eec94d7f1d78c1
4
- data.tar.gz: 73eea1c8cec0da5c67991fd808951b6aa8f9a69baacee3d5e87e7d548282f441
3
+ metadata.gz: 5e16d92ee864f0a22897d63b80edebc3a9599d973305015c42cfd5a4bdf9c499
4
+ data.tar.gz: ce7831bee20da9da43d039218513ec0dad660686fc5a0b67ef86328bb799388c
5
5
  SHA512:
6
- metadata.gz: 4e309052f0887c708ac0164ae4fc1810aaea105e819dc1e6ee6b69fc5fd8f279b84504316f5591089bb6c8eecee0283d036141d08c0cd7972f117b8814d6e3e7
7
- data.tar.gz: 0fe13ddb456d5cff73bccaaa5fc8db58a3311717c638b394956957017426de351384b789bee5ab98d170bbfe7643a96418c2e3f050452f4463320b7059728b8f
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-based via Docker on a Windows workstation
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 an environment with Docker for Windows installed, running and configured to run Windows Containers, and a working ChefDK installation (alternatively Ruby + Devkit + Test Kitchen gem).
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
- ## Install the gem
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
- gem install kitchen-dockerwin
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
- If you are installing inside a Chef Workstation installation:
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
- ## Dockerfile
32
+ ## Create base container image
24
33
 
25
- Whilst not necessary, the example shown assumes you have created your own Docker image with Chef Client inside, this will dramatically speed up the testing process because the Chef Client will not need to be installed each time.
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
- An example `Dockerfile` follows:
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:15
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: dummy
63
+ name: inspec
58
64
 
59
65
  platforms:
60
66
  - name: windows2019
61
67
  driver:
62
- image: stuartpreston/chef-client:15
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
@@ -0,0 +1,4 @@
1
+ module Docker
2
+ VERSION = '0.0.0'
3
+ API_VERSION = '1.24'
4
+ end
@@ -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 = "--mount type=bind,source=\"c:\/\",target=\"c:\/mnt\/c\""
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
- tempfile = "#{SecureRandom.hex(4)}.ps1"
27
- tempfile_path = File.join(ENV['TEMP'], tempfile)
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((tempfile_path), 'w') { |file| file.write(command) }
31
- dockered_command = "docker exec #{options[:container_id]} powershell.exe -noprofile -noninteractive -executionpolicy unrestricted -file #{translated_path}"
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(tempfile_path)
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
- powershell_commands << "copy-item #{translate_path(local)} #{remote} -force -recurse;"
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
- powershell_commands = Array.new
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.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-20 00:00:00.000000000 Z
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