kitchen-docker-2.7.0/0000755000175000017500000000000013410514304014257 5ustar mathieumathieukitchen-docker-2.7.0/CHANGELOG.md0000644000175000017500000000570613410514304016100 0ustar mathieumathieu# Kitchen-Docker Changelog ## 2.7.0 * Support for SUSE-based container images. * Improved support for build context shipping. * Changed `use_sudo` to default to `false` in keeping with modern Docker usage. ## 2.6.0 * Set container name with information from the run so you can identify them later on. * Upgrade to new driver base class structure. ## 2.5.0 * [#209](https://github.com/portertech/kitchen-docker/pulls/209) Fix usage with Kitchen rake tasks. * Add `run_options` and `build_options` configuration. * [#195](https://github.com/portertech/kitchen-docker/pulls/195) Fix Arch Linux support. * Fix shell escaping for build paths and SSH keys. ## 2.4.0 * [#148](https://github.com/portertech/kitchen-docker/issues/148) Restored support for older versions of Ruby. * [#149](https://github.com/portertech/kitchen-docker/pulls/149) Handle connecting to a container directly as root. * [#154](https://github.com/portertech/kitchen-docker/pulls/154) Improve container caching by reordering the build steps. * [#176](https://github.com/portertech/kitchen-docker/pulls/176) Expose proxy environment variables to the container automatically. * [#192](https://github.com/portertech/kitchen-docker/pulls/192) Set `$container=docker` for CentOS images. * [#196](https://github.com/portertech/kitchen-docker/pulls/196) Mutex SSH key generation for use with `kitchen -c`. * [#192](https://github.com/portertech/kitchen-docker/pulls/192) Don't wait when stopping a container. ## 2.3.0 * `build_context` option (boolean) to enable/disable sending the build context to Docker. ## 2.2.0 * Use a temporary file for each suite instance Docker container Dockerfile, instead of passing their contents via STDIN. This allows for the use of commands like ADD and COPY. **Users must now use Docker >= 1.5.0** * Passwordless suite instance Docker container login (SSH), using a generated key pair. * Support for sharing a host device with suite instance Docker containers. * README YAML highlighting. ## 2.1.0 * Use `NUL` instead of `/dev/null` on Windows for output redirection ## 2.0.0 * Use Docker `top` and `port` instead of `inspect` * Don't create the kitchen user if it already exists * Docker container capabilities options: cap_add, cap_drop * Docker security profile option (SELinux/AppArmor): security_opt * wait_for_sshd option (boolean) * Create `/etc/sudoers.d` if missing * Fixed option deprecation warnings, require Docker >= 1.2 ## 1.7.0 * Ensure a container id is set before attempting to inspect a container ## 1.6.0 * `publish_all` option to publish all ports to the host interface * `instance_name` option to name the Docker container * `links` option to link suite instance Docker containers * `socket` option will now default to ENV `DOCKER_HOST` if set * Fixed verify dependencies output redirection * Added `fedora` to platform names * Support for `gentoo` and `gentoo-paludis` platforms * Adding sudo rule to `/etc/sudoers.d/#{username}` in addition to `/etc/sudoers` kitchen-docker-2.7.0/.kitchen.yml0000644000175000017500000000225213410514304016506 0ustar mathieumathieu<% # Make sure the local copy of the driver is loaded %> <% lib = File.expand_path('../lib', __FILE__) %> <% $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) %> --- driver: name: docker provision_command: curl -L https://www.chef.io/chef/install.sh | bash provisioner: name: dummy platforms: - name: ubuntu-14.04 - name: ubuntu-16.04 - name: centos-6 - name: centos-7 - name: debian-8 - name: opensuse-42.2 driver: image: opensuse:42.2 # - name: arch # driver: # image: base/archlinux # provision_command: true - name: unknown driver: image: ubuntu:16.04 platform: ubuntu - name: dockerfile driver: username: dockerfile password: dockerfile dockerfile: test/Dockerfile run_command: /sbin/init suites: - name: default excludes: [arch] - name: context excludes: [arch] driver: build_context: false - name: capabilities excludes: [arch,unknown,centos-7,centos-6,dockerfile,opensuse-42.2] driver: provision_command: - curl -L https://www.chef.io/chef/install.sh | bash - apt-get install -y net-tools cap_drop: - NET_ADMIN - name: inspec driver: provision_command: true verifier: name: inspec kitchen-docker-2.7.0/LICENSE0000644000175000017500000002613613410514304015274 0ustar mathieumathieu Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. kitchen-docker-2.7.0/.tailor0000644000175000017500000000013113410514304015545 0ustar mathieumathieuTailor.config do |config| config.formatters "text" config.file_set 'lib/**/*.rb' end kitchen-docker-2.7.0/.travis.yml0000644000175000017500000000044113410514304016367 0ustar mathieumathieusudo: required dist: trusty language: ruby rvm: - "2.3.1" - "2.4.3" - "2.5.1" services: - docker cache: bundler: true directories: - /var/lib/docker script: - bundle exec docker version - bundle exec kitchen --version - bundle exec rake spec - bundle exec kitchen test -d always kitchen-docker-2.7.0/Rakefile0000644000175000017500000000177613410514304015737 0ustar mathieumathieurequire "bundler/gem_tasks" require 'cane/rake_task' require 'tailor/rake_task' desc "Run cane to check quality metrics" Cane::RakeTask.new do |cane| cane.canefile = './.cane' end Tailor::RakeTask.new desc "Display LOC stats" task :stats do puts "\n## Production Code Stats" sh "countloc -r lib" end desc "Run all quality tasks" task :quality => [:cane, :tailor, :stats] task :default => [:quality] # begin # require 'kitchen/rake_tasks' # Kitchen::RakeTasks.new # rescue LoadError # puts ">>>>> Kitchen gem not loaded, omitting tasks" unless ENV['CI'] # end # Create the spec task. require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec, :tag) do |t, args| t.rspec_opts = [].tap do |a| a << '--color' a << "--format #{ENV['CI'] ? 'documentation' : 'Fuubar'}" a << '--backtrace' if ENV['VERBOSE'] || ENV['DEBUG'] a << "--seed #{ENV['SEED']}" if ENV['SEED'] a << "--tag #{args[:tag]}" if args[:tag] a << "--default-path test" a << '-I test/spec' end.join(' ') end kitchen-docker-2.7.0/.gitignore0000644000175000017500000000026713410514304016254 0ustar mathieumathieu*.gem *.rbc .bundle .config .yardoc Gemfile.lock InstalledFiles _yardoc coverage doc/ lib/bundler/man pkg rdoc spec/reports test/tmp test/version_tmp tmp .kitchen/ .kitchen.local.yml kitchen-docker-2.7.0/test/0000755000175000017500000000000013410514304015236 5ustar mathieumathieukitchen-docker-2.7.0/test/Dockerfile0000644000175000017500000000160213410514304017227 0ustar mathieumathieuFROM centos:6 RUN yum clean all RUN yum install -y sudo openssh-server openssh-clients which curl htop RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key RUN mkdir -p /var/run/sshd RUN useradd -d /home/<%= @username %> -m -s /bin/bash <%= @username %> RUN echo <%= "#{@username}:#{@password}" %> | chpasswd RUN echo '<%= @username %> ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers RUN mkdir -p /home/<%= @username %>/.ssh RUN chown -R <%= @username %> /home/<%= @username %>/.ssh RUN chmod 0700 /home/<%= @username %>/.ssh RUN touch /home/<%= @username %>/.ssh/authorized_keys RUN chown <%= @username %> /home/<%= @username %>/.ssh/authorized_keys RUN chmod 0600 /home/<%= @username %>/.ssh/authorized_keys RUN curl -L https://www.chef.io/chef/install.sh | bash RUN echo '<%= IO.read(@public_key).strip %>' >> /home/<%= @username %>/.ssh/authorized_keys kitchen-docker-2.7.0/test/integration/0000755000175000017500000000000013410514304017561 5ustar mathieumathieukitchen-docker-2.7.0/test/integration/inspec/0000755000175000017500000000000013410514304021042 5ustar mathieumathieukitchen-docker-2.7.0/test/integration/inspec/inspec_spec.rb0000644000175000017500000000130713410514304023663 0ustar mathieumathieu# # Copyright 2016, Noah Kantrowitz # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Just make sure the image launched and is reachable. describe command('true') do its(:exit_status) { is_expected.to eq 0 } end kitchen-docker-2.7.0/test/integration/default/0000755000175000017500000000000013410514304021205 5ustar mathieumathieukitchen-docker-2.7.0/test/integration/default/serverspec/0000755000175000017500000000000013410514304023366 5ustar mathieumathieukitchen-docker-2.7.0/test/integration/default/serverspec/default_spec.rb0000644000175000017500000000136113410514304026352 0ustar mathieumathieu# # Copyright 2016, Noah Kantrowitz # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # require 'serverspec' set :backend, :exec # Just make sure the image launched and is reachable. describe command('true') do its(:exit_status) { is_expected.to eq 0 } end kitchen-docker-2.7.0/test/integration/capabilities/0000755000175000017500000000000013410514304022212 5ustar mathieumathieukitchen-docker-2.7.0/test/integration/capabilities/serverspec/0000755000175000017500000000000013410514304024373 5ustar mathieumathieukitchen-docker-2.7.0/test/integration/capabilities/serverspec/capabilities_drop_spec.rb0000644000175000017500000000143213410514304031407 0ustar mathieumathieu# # Copyright 2016, Noah Kantrowitz # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # require 'serverspec' set :backend, :exec describe command('/sbin/ifconfig eth0 multicast') do its(:exit_status) { is_expected.to_not eq 0 } its(:stderr) { is_expected.to match /Operation not permitted/ } end kitchen-docker-2.7.0/test/spec/0000755000175000017500000000000013410514304016170 5ustar mathieumathieukitchen-docker-2.7.0/test/spec/spec_helper.rb0000644000175000017500000000272413410514304021013 0ustar mathieumathieu# # Copyright 2016, Noah Kantrowitz # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # require 'rake' require 'rspec' require 'rspec/its' require 'simplecov' # Check for coverage stuffs formatters = [] if ENV['CODECOV_TOKEN'] || ENV['TRAVIS'] require 'codecov' formatters << SimpleCov::Formatter::Codecov end unless formatters.empty? SimpleCov.formatters = formatters end SimpleCov.start do # Don't get coverage on the test cases themselves. add_filter '/spec/' add_filter '/test/' # Codecov doesn't automatically ignore vendored files. add_filter '/vendor/' end require 'kitchen/driver/docker' RSpec.configure do |config| # Basic configuraiton config.run_all_when_everything_filtered = true config.filter_run(:focus) # Run specs in random order to surface order dependencies. If you find an # order dependency and want to debug it, you can fix the order by providing # the seed, which is printed after each run. # --seed 1234 config.order = 'random' end kitchen-docker-2.7.0/test/spec/docker_spec.rb0000644000175000017500000000417713410514304021007 0ustar mathieumathieu# # Copyright 2016, Noah Kantrowitz # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # require 'spec_helper' describe Kitchen::Driver::Docker do describe '#config_to_options' do let(:config) { } subject { described_class.new.send(:config_to_options, config) } context 'with nil' do let(:config) { nil } it { is_expected.to eq '' } end # /context with nil context 'with a string' do let(:config) { '--foo' } it { is_expected.to eq '--foo' } end # /context with a string context 'with a string with spaces' do let(:config) { '--foo bar' } it { is_expected.to eq '--foo bar' } end # /context with a string with spaces context 'with an array of strings' do let(:config) { %w{--foo --bar} } it { is_expected.to eq '--foo --bar' } end # /context with an array of strings context 'with an array of hashes' do let(:config) { [{foo: 'bar'}, {other: 'baz'}] } it { is_expected.to eq '--foo=bar --other=baz' } end # /context with an array of hashes context 'with a hash of strings' do let(:config) { {foo: 'bar', other: 'baz'} } it { is_expected.to eq '--foo=bar --other=baz' } end # /context with a hash of strings context 'with a hash of arrays' do let(:config) { {foo: %w{bar baz}} } it { is_expected.to eq '--foo=bar --foo=baz' } end # /context with a hash of arrays context 'with a hash of strings with spaces' do let(:config) { {foo: 'bar two', other: 'baz'} } it { is_expected.to eq '--foo=bar\\ two --other=baz' } end # /context with a hash of strings with spaces end # /describe #config_to_options end kitchen-docker-2.7.0/Gemfile0000644000175000017500000000004713410514304015553 0ustar mathieumathieusource 'https://rubygems.org' gemspec kitchen-docker-2.7.0/lib/0000755000175000017500000000000013410514304015025 5ustar mathieumathieukitchen-docker-2.7.0/lib/kitchen/0000755000175000017500000000000013410514304016452 5ustar mathieumathieukitchen-docker-2.7.0/lib/kitchen/driver/0000755000175000017500000000000013410514304017745 5ustar mathieumathieukitchen-docker-2.7.0/lib/kitchen/driver/docker.rb0000644000175000017500000003645413410514304021555 0ustar mathieumathieu# -*- encoding: utf-8 -*- # # Copyright (C) 2014, Sean Porter # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'kitchen' require 'json' require 'securerandom' require 'uri' require 'net/ssh' require 'tempfile' require 'shellwords' require 'kitchen/driver/base' require_relative './docker/erb' module Kitchen module Driver # Docker driver for Kitchen. # # @author Sean Porter class Docker < Kitchen::Driver::Base include ShellOut default_config :binary, 'docker' default_config :socket, ENV['DOCKER_HOST'] || 'unix:///var/run/docker.sock' default_config :privileged, false default_config :cap_add, nil default_config :cap_drop, nil default_config :security_opt, nil default_config :use_cache, true default_config :remove_images, false default_config :run_command, '/usr/sbin/sshd -D -o UseDNS=no -o UsePAM=no -o PasswordAuthentication=yes ' + '-o UsePrivilegeSeparation=no -o PidFile=/tmp/sshd.pid' default_config :username, 'kitchen' default_config :tls, false default_config :tls_verify, false default_config :tls_cacert, nil default_config :tls_cert, nil default_config :tls_key, nil default_config :publish_all, false default_config :wait_for_sshd, true default_config :private_key, File.join(Dir.pwd, '.kitchen', 'docker_id_rsa') default_config :public_key, File.join(Dir.pwd, '.kitchen', 'docker_id_rsa.pub') default_config :build_options, nil default_config :run_options, nil default_config :use_sudo, false default_config :image do |driver| driver.default_image end default_config :platform do |driver| driver.default_platform end default_config :disable_upstart, true default_config :build_context do |driver| !driver.remote_socket? end default_config :instance_name do |driver| # Borrowed from kitchen-rackspace [ driver.instance.name.gsub(/\W/, ''), (Etc.getlogin || 'nologin').gsub(/\W/, ''), Socket.gethostname.gsub(/\W/, '')[0..20], Array.new(8) { rand(36).to_s(36) }.join ].join('-') end MUTEX_FOR_SSH_KEYS = Mutex.new def verify_dependencies run_command("#{config[:binary]} >> #{dev_null} 2>&1", quiet: true, use_sudo: config[:use_sudo]) rescue raise UserError, 'You must first install the Docker CLI tool http://www.docker.io/gettingstarted/' end def dev_null case RbConfig::CONFIG["host_os"] when /mswin|msys|mingw|cygwin|bccwin|wince|emc/ "NUL" else "/dev/null" end end def default_image platform, release = instance.platform.name.split('-') if platform == 'centos' && release release = 'centos' + release.split('.').first end release ? [platform, release].join(':') : platform end def default_platform instance.platform.name.split('-').first end def create(state) generate_keys state[:username] = config[:username] state[:ssh_key] = config[:private_key] state[:image_id] = build_image(state) unless state[:image_id] state[:container_id] = run_container(state) unless state[:container_id] state[:hostname] = remote_socket? ? socket_uri.host : 'localhost' state[:port] = container_ssh_port(state) if config[:wait_for_sshd] instance.transport.connection(state) do |conn| conn.wait_until_ready end end end def destroy(state) rm_container(state) if container_exists?(state) if config[:remove_images] && state[:image_id] rm_image(state) end end def remote_socket? config[:socket] ? socket_uri.scheme == 'tcp' : false end protected def socket_uri URI.parse(config[:socket]) end def docker_command(cmd, options={}) docker = config[:binary].dup docker << " -H #{config[:socket]}" if config[:socket] docker << " --tls" if config[:tls] docker << " --tlsverify" if config[:tls_verify] docker << " --tlscacert=#{config[:tls_cacert]}" if config[:tls_cacert] docker << " --tlscert=#{config[:tls_cert]}" if config[:tls_cert] docker << " --tlskey=#{config[:tls_key]}" if config[:tls_key] run_command("#{docker} #{cmd}", options.merge({ quiet: !logger.debug?, use_sudo: config[:use_sudo], log_subject: Thor::Util.snake_case(self.class.to_s), })) end def generate_keys MUTEX_FOR_SSH_KEYS.synchronize do if !File.exist?(config[:public_key]) || !File.exist?(config[:private_key]) private_key = OpenSSL::PKey::RSA.new(2048) blobbed_key = Base64.encode64(private_key.to_blob).gsub("\n", '') public_key = "ssh-rsa #{blobbed_key} kitchen_docker_key" File.open(config[:private_key], 'w') do |file| file.write(private_key) file.chmod(0600) end File.open(config[:public_key], 'w') do |file| file.write(public_key) file.chmod(0600) end end end end def build_dockerfile from = "FROM #{config[:image]}" env_variables = '' if config[:http_proxy] env_variables << "ENV http_proxy #{config[:http_proxy]}\n" env_variables << "ENV HTTP_PROXY #{config[:http_proxy]}\n" end if config[:https_proxy] env_variables << "ENV https_proxy #{config[:https_proxy]}\n" env_variables << "ENV HTTPS_PROXY #{config[:https_proxy]}\n" end if config[:no_proxy] env_variables << "ENV no_proxy #{config[:no_proxy]}\n" env_variables << "ENV NO_PROXY #{config[:no_proxy]}\n" end platform = case config[:platform] when 'debian', 'ubuntu' disable_upstart = <<-eos RUN [ ! -f "/sbin/initctl" ] || dpkg-divert --local --rename --add /sbin/initctl && ln -sf /bin/true /sbin/initctl eos packages = <<-eos ENV DEBIAN_FRONTEND noninteractive ENV container docker RUN apt-get update RUN apt-get install -y sudo openssh-server curl lsb-release eos config[:disable_upstart] ? disable_upstart + packages : packages when 'rhel', 'centos', 'fedora' <<-eos ENV container docker RUN yum clean all RUN yum install -y sudo openssh-server openssh-clients which curl RUN [ -f "/etc/ssh/ssh_host_rsa_key" ] || ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N '' RUN [ -f "/etc/ssh/ssh_host_dsa_key" ] || ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key -N '' eos when 'opensuse', 'sles' <<-eos ENV container docker RUN zypper install -y sudo openssh which curl RUN [ -f "/etc/ssh/ssh_host_rsa_key" ] || ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N '' RUN [ -f "/etc/ssh/ssh_host_dsa_key" ] || ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key -N '' eos when 'arch' # See https://bugs.archlinux.org/task/47052 for why we # blank out limits.conf. <<-eos RUN pacman --noconfirm -Sy archlinux-keyring RUN pacman-db-upgrade RUN pacman --noconfirm -Sy openssl openssh sudo curl RUN [ -f "/etc/ssh/ssh_host_rsa_key" ] || ssh-keygen -A -t rsa -f /etc/ssh/ssh_host_rsa_key RUN [ -f "/etc/ssh/ssh_host_dsa_key" ] || ssh-keygen -A -t dsa -f /etc/ssh/ssh_host_dsa_key RUN echo >/etc/security/limits.conf eos when 'gentoo' <<-eos RUN emerge --sync RUN emerge net-misc/openssh app-admin/sudo RUN [ -f "/etc/ssh/ssh_host_rsa_key" ] || ssh-keygen -A -t rsa -f /etc/ssh/ssh_host_rsa_key RUN [ -f "/etc/ssh/ssh_host_dsa_key" ] || ssh-keygen -A -t dsa -f /etc/ssh/ssh_host_dsa_key eos when 'gentoo-paludis' <<-eos RUN cave sync RUN cave resolve -zx net-misc/openssh app-admin/sudo RUN [ -f "/etc/ssh/ssh_host_rsa_key" ] || ssh-keygen -A -t rsa -f /etc/ssh/ssh_host_rsa_key RUN [ -f "/etc/ssh/ssh_host_dsa_key" ] || ssh-keygen -A -t dsa -f /etc/ssh/ssh_host_dsa_key eos else raise ActionFailed, "Unknown platform '#{config[:platform]}'" end username = config[:username] public_key = IO.read(config[:public_key]).strip homedir = username == 'root' ? '/root' : "/home/#{username}" base = <<-eos RUN if ! getent passwd #{username}; then \ useradd -d #{homedir} -m -s /bin/bash -p '*' #{username}; \ fi RUN echo "#{username} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers RUN echo "Defaults !requiretty" >> /etc/sudoers RUN mkdir -p #{homedir}/.ssh RUN chown -R #{username} #{homedir}/.ssh RUN chmod 0700 #{homedir}/.ssh RUN touch #{homedir}/.ssh/authorized_keys RUN chown #{username} #{homedir}/.ssh/authorized_keys RUN chmod 0600 #{homedir}/.ssh/authorized_keys eos custom = '' Array(config[:provision_command]).each do |cmd| custom << "RUN #{cmd}\n" end ssh_key = "RUN echo #{Shellwords.escape(public_key)} >> #{homedir}/.ssh/authorized_keys" # Empty string to ensure the file ends with a newline. [from, env_variables, platform, base, custom, ssh_key, ''].join("\n") end def dockerfile if config[:dockerfile] template = IO.read(File.expand_path(config[:dockerfile])) context = DockerERBContext.new(config.to_hash) ERB.new(template).result(context.get_binding) else build_dockerfile end end def parse_image_id(output) output.each_line do |line| if line =~ /image id|build successful|successfully built/i return line.split(/\s+/).last end end raise ActionFailed, 'Could not parse Docker build output for image ID' end def build_image(state) cmd = "build" cmd << " --no-cache" unless config[:use_cache] extra_build_options = config_to_options(config[:build_options]) cmd << " #{extra_build_options}" unless extra_build_options.empty? dockerfile_contents = dockerfile build_context = config[:build_context] ? '.' : '-' file = Tempfile.new('Dockerfile-kitchen', Dir.pwd) output = begin file.write(dockerfile) file.close docker_command("#{cmd} -f #{Shellwords.escape(dockerfile_path(file))} #{build_context}", :input => dockerfile_contents) ensure file.close unless file.closed? file.unlink end parse_image_id(output) end def parse_container_id(output) container_id = output.chomp unless [12, 64].include?(container_id.size) raise ActionFailed, 'Could not parse Docker run output for container ID' end container_id end def build_run_command(image_id) cmd = "run -d -p 22" Array(config[:forward]).each {|port| cmd << " -p #{port}"} Array(config[:dns]).each {|dns| cmd << " --dns #{dns}"} Array(config[:add_host]).each {|host, ip| cmd << " --add-host=#{host}:#{ip}"} Array(config[:volume]).each {|volume| cmd << " -v #{volume}"} Array(config[:volumes_from]).each {|container| cmd << " --volumes-from #{container}"} Array(config[:links]).each {|link| cmd << " --link #{link}"} Array(config[:devices]).each {|device| cmd << " --device #{device}"} cmd << " --name #{config[:instance_name]}" if config[:instance_name] cmd << " -P" if config[:publish_all] cmd << " -h #{config[:hostname]}" if config[:hostname] cmd << " -m #{config[:memory]}" if config[:memory] cmd << " -c #{config[:cpu]}" if config[:cpu] cmd << " -e http_proxy=#{config[:http_proxy]}" if config[:http_proxy] cmd << " -e https_proxy=#{config[:https_proxy]}" if config[:https_proxy] cmd << " --privileged" if config[:privileged] Array(config[:cap_add]).each {|cap| cmd << " --cap-add=#{cap}"} if config[:cap_add] Array(config[:cap_drop]).each {|cap| cmd << " --cap-drop=#{cap}"} if config[:cap_drop] Array(config[:security_opt]).each {|opt| cmd << " --security-opt=#{opt}"} if config[:security_opt] extra_run_options = config_to_options(config[:run_options]) cmd << " #{extra_run_options}" unless extra_run_options.empty? cmd << " #{image_id} #{config[:run_command]}" cmd end def run_container(state) cmd = build_run_command(state[:image_id]) output = docker_command(cmd) parse_container_id(output) end def container_exists?(state) state[:container_id] && !!docker_command("top #{state[:container_id]}") rescue false end def parse_container_ssh_port(output) begin _host, port = output.split(':') port.to_i rescue raise ActionFailed, 'Could not parse Docker port output for container SSH port' end end def container_ssh_port(state) begin output = docker_command("port #{state[:container_id]} 22/tcp") parse_container_ssh_port(output) rescue raise ActionFailed, 'Docker reports container has no ssh port mapped' end end def rm_container(state) container_id = state[:container_id] docker_command("stop -t 0 #{container_id}") docker_command("rm #{container_id}") end def rm_image(state) image_id = state[:image_id] docker_command("rmi #{image_id}") end # Convert the config input for `:build_options` or `:run_options` in to a # command line string for use with Docker. # # @since 2.5.0 # @param config [nil, String, Array, Hash] Config data to convert. # @return [String] def config_to_options(config) case config when nil '' when String config when Array config.map {|c| config_to_options(c) }.join(' ') when Hash config.map {|k, v| Array(v).map {|c| "--#{k}=#{Shellwords.escape(c)}" }.join(' ') }.join(' ') end end def dockerfile_path(file) config[:build_context] ? Pathname.new(file.path).relative_path_from(Pathname.pwd).to_s : file.path end end end end kitchen-docker-2.7.0/lib/kitchen/driver/docker/0000755000175000017500000000000013410514304021214 5ustar mathieumathieukitchen-docker-2.7.0/lib/kitchen/driver/docker/erb.rb0000644000175000017500000000157713410514304022323 0ustar mathieumathieu# -*- encoding: utf-8 -*- # # Copyright (C) 2014, Sean Porter # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. require 'erb' module Kitchen module Driver class DockerERBContext def initialize(config={}) config.each do |key, value| instance_variable_set('@' + key.to_s, value) end end def get_binding binding end end end end kitchen-docker-2.7.0/lib/kitchen/driver/docker_version.rb0000644000175000017500000000132713410514304023311 0ustar mathieumathieu# -*- encoding: utf-8 -*- # # Copyright (C) 2014, Sean Porter # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. module Kitchen module Driver # Version string for Docker Kitchen driver DOCKER_VERSION = "2.7.0" end end kitchen-docker-2.7.0/kitchen-docker.gemspec0000644000175000017500000000264413410514304020524 0ustar mathieumathieu# coding: utf-8 lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'kitchen/driver/docker_version' Gem::Specification.new do |spec| spec.name = 'kitchen-docker' spec.version = Kitchen::Driver::DOCKER_VERSION spec.authors = ['Sean Porter'] spec.email = ['portertech@gmail.com'] spec.description = %q{A Docker Driver for Test Kitchen} spec.summary = spec.description spec.homepage = 'https://github.com/portertech/kitchen-docker' spec.license = 'Apache 2.0' spec.files = `git ls-files`.split($/) spec.executables = [] spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ['lib'] spec.add_dependency 'test-kitchen', '>= 1.0.0' spec.add_development_dependency 'bundler' spec.add_development_dependency 'rake' # Style checker gems. spec.add_development_dependency 'cane' spec.add_development_dependency 'tailor' spec.add_development_dependency 'countloc' # Unit testing gems. spec.add_development_dependency 'rspec', '~> 3.2' spec.add_development_dependency 'rspec-its', '~> 1.2' spec.add_development_dependency 'fuubar', '~> 2.0' spec.add_development_dependency 'simplecov', '~> 0.9' spec.add_development_dependency 'codecov', '~> 0.0', '>= 0.0.2' # Integration testing gems. spec.add_development_dependency 'kitchen-inspec', '~> 0.14' end kitchen-docker-2.7.0/.cane0000644000175000017500000000000013410514304015154 0ustar mathieumathieukitchen-docker-2.7.0/README.md0000644000175000017500000002571013410514304015543 0ustar mathieumathieu# Kitchen-Docker [![Build Status](https://img.shields.io/travis/test-kitchen/kitchen-docker.svg)](https://travis-ci.org/test-kitchen/kitchen-docker) [![Gem Version](https://img.shields.io/gem/v/kitchen-docker.svg)](https://rubygems.org/gems/kitchen-docker) [![Coverage](https://img.shields.io/codecov/c/github/test-kitchen/kitchen-docker.svg)](https://codecov.io/github/test-kitchen/kitchen-docker) [![License](https://img.shields.io/badge/license-Apache_2-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0) A Test Kitchen Driver for Docker. ## Requirements * [Docker][docker_installation] **(>= 1.5)** ## Installation and Setup Please read the Test Kitchen [docs][test_kitchen_docs] for more details. Example `.kitchen.local.yml`: ```yaml --- driver: name: docker platforms: - name: ubuntu run_list: - recipe[apt] - name: centos driver_config: image: centos platform: rhel run_list: - recipe[yum] ``` ## Default Configuration This driver can determine an image and platform type for a select number of platforms. Examples: ```yaml --- platforms: - name: ubuntu-12.04 - name: centos-6.4 ``` This will effectively generate a configuration similar to: ```yaml --- platforms: - name: ubuntu-12.04 driver_config: image: ubuntu:12.04 platform: ubuntu - name: centos-6.4 driver_config: image: centos:6.4 platform: centos ``` ## Configuration ### binary The Docker binary to use. The default value is `docker`. Examples: ```yaml binary: docker.io ``` ```yaml binary: /opt/docker ``` ### socket The Docker daemon socket to use. By default, Docker will listen on `unix:///var/run/docker.sock`, and no configuration here is required. If Docker is binding to another host/port or Unix socket, you will need to set this option. If a TCP socket is set, its host will be used for SSH access to suite containers. Examples: ```yaml socket: unix:///tmp/docker.sock ``` ```yaml socket: tcp://docker.example.com:4242 ``` If you use [Docker for Windows](https://docs.docker.com/docker-for-windows/) ```yaml socket: npipe:////./pipe/docker_engine ``` If you use [Boot2Docker](https://github.com/boot2docker/boot2docker) or [docker-machine](https://docs.docker.com/machine/get-started/) set your `DOCKER_HOST` environment variable properly with `export DOCKER_HOST=tcp://192.168.59.103:2375` or `eval "$(docker-machine env $MACHINE)"` then use the following: ```yaml socket: tcp://192.168.59.103:2375 ``` ### image The Docker image to use as the base for the suite containers. You can find images using the [Docker Index][docker_index]. The default will be computed, using the platform name (see the Default Configuration section for more details). ### platform The platform of the chosen image. This is used to properly bootstrap the suite container for Test Kitchen. Kitchen Docker currently supports: * `debian` or `ubuntu` * `rhel` or `centos` * `gentoo` or `gentoo-paludis` * `opensuse` or `sles` The default will be computed, using the platform name (see the Default Configuration section for more details). ### require\_chef\_omnibus Determines whether or not a Chef [Omnibus package][chef_omnibus_dl] will be installed. There are several different behaviors available: * `true` - the latest release will be installed. Subsequent converges will skip re-installing if chef is present. * `latest` - the latest release will be installed. Subsequent converges will always re-install even if chef is present. * `` (ex: `10.24.0`) - the desired version string will be passed the the install.sh script. Subsequent converges will skip if the installed version and the desired version match. * `false` or `nil` - no chef is installed. The default value is `true`. ### disable\_upstart Disables upstart on Debian/Ubuntu containers, as many images do not support a working upstart. The default value is `true`. ### provision\_command Custom command(s) to be run when provisioning the base for the suite containers. Examples: ```yaml provision_command: curl -L https://www.opscode.com/chef/install.sh | bash ``` ```yaml provision_command: - apt-get install dnsutils - apt-get install telnet ``` ```yaml driver_config: provision_command: curl -L https://www.opscode.com/chef/install.sh | bash require_chef_omnibus: false ``` ### use\_cache This determines if the Docker cache is used when provisioning the base for suite containers. The default value is `true`. ### use\_sudo This determines if Docker commands are run with `sudo`. The default value depends on the type of socket being used. For local sockets, the default value is `true`. For remote sockets, the default value is `false`. This should be set to `false` if you're using boot2docker, as every command passed into the VM runs as root by default. ### remove\_images This determines if images are automatically removed when the suite container is destroyed. The default value is `false`. ### run\_command Sets the command used to run the suite container. The default value is `/usr/sbin/sshd -D -o UseDNS=no -o UsePAM=no -o PasswordAuthentication=yes -o UsePrivilegeSeparation=no -o PidFile=/tmp/sshd.pid`. Examples: ```yaml run_command: /sbin/init ``` ### memory Sets the memory limit for the suite container in bytes. Otherwise use Dockers default. You can read more about `memory.limit_in_bytes` [here][memory_limit]. ### cpu Sets the CPU shares (relative weight) for the suite container. Otherwise use Dockers defaults. You can read more about cpu.shares [here][cpu_shares]. ### volume Adds a data volume(s) to the suite container. Examples: ```yaml volume: /ftp ``` ```yaml volume: - /ftp - /srv ``` ### volumes\_from Mount volumes managed by other containers. Examples: ```yaml volumes_from: repos ``` ```yaml volumes_from: - repos - logging - rvm ``` ### dns Adjusts `resolv.conf` to use the dns servers specified. Otherwise use Dockers defaults. Examples: ```yaml dns: 8.8.8.8 ``` ```yaml dns: - 8.8.8.8 - 8.8.4.4 ``` ### http\_proxy Sets an http proxy for the suite container using the `http_proxy` environment variable. Examples: ```yaml http_proxy: http://proxy.host.com:8080 ``` ### https\_proxy Sets an https proxy for the suite container using the `https_proxy` environment variable. Examples: ```yaml https_proxy: http://proxy.host.com:8080 ``` ### forward Set suite container port(s) to forward to the host machine. You may specify the host (public) port in the mappings, if not, Docker chooses for you. Examples: ```yaml forward: 80 ``` ```yaml forward: - 22:2222 - 80:8080 ``` ### hostname Set the suite container hostname. Otherwise use Dockers default. Examples: ```yaml hostname: foobar.local ``` ### privileged Run the suite container in privileged mode. This allows certain functionality inside the Docker container which is not otherwise permitted. The default value is `false`. Examples: ```yaml privileged: true ``` ### cap\_add Adds a capability to the running container. Examples: ```yaml cap_add: - SYS_PTRACE ``` ### cap\_drop Drops a capability from the running container. Examples: ```yaml cap_drop: - CHOWN ``` ### security\_opt Apply a security profile to the Docker container. Allowing finer granularity of access control than privileged mode, through leveraging SELinux/AppArmor profiles to grant access to specific resources. Examples: ```yaml security_opt: - apparmor:my_profile ``` ### dockerfile Use a custom Dockerfile, instead of having Kitchen-Docker build one for you. Examples: ```yaml dockerfile: test/Dockerfile ``` ### instance\_name Set the name of container to link to other container(s). Examples: ```yaml instance_name: web ``` ### links Set ```instance_name```(and alias) of other container(s) that connect from the suite container. Examples: ```yaml links: db:db ``` ```yaml links: - db:db - kvs:kvs ``` ### publish\_all Publish all exposed ports to the host interfaces. This option used to communicate between some containers. The default value is `false`. Examples: ```yaml publish_all: true ``` ### devices Share a host device with the container. Host device must be an absolute path. Examples: ``` devices: /dev/vboxdrv ``` ``` devices: - /dev/vboxdrv - /dev/vboxnetctl ``` ### build_context Transfer the cookbook directory (cwd) as build context. This is required for Dockerfile commands like ADD and COPY. When using a remote Docker server, the whole directory has to be copied, which can be slow. The default value is `true` for local Docker and `false` for remote Docker. Examples: ```yaml build_context: true ``` ### build_options Extra command-line options to pass to `docker build` when creating the image. Examples: ```yaml build_options: --rm=false ``` ```yaml build_options: rm: false build-arg: something ``` ### run_options Extra command-line options to pass to `docker run` when starting the container. Examples: ```yaml run_options: --ip=1.2.3.4 ``` ```yaml run_options: tmpfs: - /run/lock - /tmp net: br3 ``` ## Development * Source hosted at [GitHub][repo] * Report issues/questions/feature requests on [GitHub Issues][issues] Pull requests are very welcome! Make sure your patches are well tested. Ideally create a topic branch for every separate change you make. For example: 1. Fork the repo 2. Create your feature branch (`git checkout -b my-new-feature`) 3. Commit your changes (`git commit -am 'Added some feature'`) 4. Push to the branch (`git push origin my-new-feature`) 5. Create new Pull Request ## License Copyright 2013-2016, [Sean Porter](https://github.com/portertech) Copyright 2015-2016, [Noah Kantrowitz](https://github.com/coderanger) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. [issues]: https://github.com/test-kitchen/kitchen-docker/issues [license]: https://github.com/test-kitchen/kitchen-docker/blob/master/LICENSE [repo]: https://github.com/test-kitchen/kitchen-docker [docker_installation]: https://docs.docker.com/installation/#installation [docker_upstart_issue]: https://github.com/dotcloud/docker/issues/223 [docker_index]: https://index.docker.io/ [docker_default_image]: https://index.docker.io/_/base/ [test_kitchen_docs]: http://kitchen.ci/docs/getting-started/ [chef_omnibus_dl]: https://downloads.chef.io/chef-client/ [cpu_shares]: https://docs.fedoraproject.org/en-US/Fedora/17/html/Resource_Management_Guide/sec-cpu.html [memory_limit]: https://docs.fedoraproject.org/en-US/Fedora/17/html/Resource_Management_Guide/sec-memory.html