puppet_docker_tools 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
  SHA1:
3
- metadata.gz: 0cced50b6cd276b28389615a751ad0946a6e3196
4
- data.tar.gz: 30084e7aebeee1dd037537bdb6ad521ff33376b3
3
+ metadata.gz: 2af7f0af2ac0fb8371c5358179ff8b3d26f10157
4
+ data.tar.gz: 5c82a30a82d4dbaafbf3e8217a9c8f4b96cb4d5d
5
5
  SHA512:
6
- metadata.gz: 2612cf5a9ce5c38bd1518c503f72c0943e4517ad6ba789e5573c562123604f9bd0978b4e4c5ceefeaff286ccef2da78868a93e7d3588263495da970d4551eca7
7
- data.tar.gz: fe1ae2b95ab05230b2aeb780a111c286fde043ebe068af55dd9f4560a59412f44d8d1275fc78f7f72960035e37f6443d5cdb0a91e062586b027c031b1d49427e
6
+ metadata.gz: e3f350e40c4f26824845e9e06d820b3fb47d69e165602feb6a9049a3cf7a18f78514670a0f9a53dcae5d07bafc22e644173b93f2d5ec3e815c04ba7daff79c76
7
+ data.tar.gz: f8092567055f4a50bcecd27682209ff6f3374d46a39806bc6a5a86143d3c3155b9ab5c06b9db87269a109f7e7ab25a1988f7e7e5019fa56f6e0c4c269afec1bd
data/README.md CHANGED
@@ -15,6 +15,7 @@ $ puppet-docker help
15
15
  Usage:
16
16
  puppet-docker build [DIRECTORY] [--dockerfile=<dockerfile>] [--repository=<repo>] [--namespace=<namespace>] [--no-cache]
17
17
  puppet-docker lint [DIRECTORY] [--dockerfile=<dockerfile>]
18
+ puppet-docker local-lint [DIRECTORY] [--dockerfile=<dockerfile>]
18
19
  puppet-docker pull [IMAGE] [--repository=<repo>]
19
20
  puppet-docker push [DIRECTORY] [--dockerfile=<dockerfile>] [--repository=<repo>] [--namespace=<namespace>]
20
21
  puppet-docker rev-labels [DIRECTORY] [--dockerfile=<dockerfile>] [--namespace=<namespace>]
@@ -48,6 +49,10 @@ Run [hadolint](https://github.com/hadolint/hadolint) on the dockerfile in DIRECT
48
49
  * [DL4000](https://github.com/hadolint/hadolint/wiki/DL4000) - MAINTAINER is deprecated
49
50
  * [DL4001](https://github.com/hadolint/hadolint/wiki/DL4001) - Don't use both wget and curl
50
51
 
52
+ ### `puppet-docker local-lint`
53
+
54
+ Run [hadolint](https://github.com/hadolint/hadolint) on the dockerfile in DIRECTORY. The lint task runs using a locally installed `hadolint` executable with the same rule exclusions as `puppet-docker lint`.
55
+
51
56
  ### `puppet-docker pull`
52
57
 
53
58
  Pull the specified image, i.e. 'puppet/puppetserver'. *NOTE*: If you don't include the tag you want to pull, `puppet-docker pull` will pull all tags for that image.
@@ -76,6 +81,15 @@ Output the `version` label for the dockerfile contained in DIRECTORY.
76
81
 
77
82
  Update the base images. Any number of tags to update can be passed, or by default it will pull the latest version of: ['ubuntu:16.04', 'centos:7', 'alpine:3.4', 'debian:9', 'postgres:9.6.8']
78
83
 
84
+ ## Items available to Dockerfiles
85
+
86
+ There are some common variables passed to builds that you can take advantage of in your Dockerfiles.
87
+
88
+ ### `ARG`s
89
+
90
+ * `vcs_ref`: set to `git rev-parse HEAD`
91
+ * `build_date`: set to ruby's `Time.now.utc.iso8601`
92
+
79
93
  ## Issues
80
94
 
81
95
  File issues in the [Community Package Repository (CPR) project](https://tickets.puppet.com/browse/CPR) with the 'Container' component.
@@ -9,6 +9,7 @@ Utilities for building and releasing Puppet docker images.
9
9
  Usage:
10
10
  puppet-docker build [DIRECTORY] [--dockerfile=<dockerfile>] [--repository=<repo>] [--namespace=<namespace>] [--no-cache]
11
11
  puppet-docker lint [DIRECTORY] [--dockerfile=<dockerfile>]
12
+ puppet-docker local-lint [DIRECTORY] [--dockerfile=<dockerfile>]
12
13
  puppet-docker pull [IMAGE] [--repository=<repo>]
13
14
  puppet-docker push [DIRECTORY] [--dockerfile=<dockerfile>] [--repository=<repo>] [--namespace=<namespace>]
14
15
  puppet-docker rev-labels [DIRECTORY] [--dockerfile=<dockerfile>] [--namespace=<namespace>]
@@ -71,6 +72,8 @@ begin
71
72
  command_runner.build(no_cache: options['--no-cache'])
72
73
  elsif options['lint']
73
74
  command_runner.lint
75
+ elsif options['local-lint']
76
+ command_runner.local_lint
74
77
  elsif options['push']
75
78
  command_runner.push
76
79
  elsif options['rev-labels']
@@ -1,5 +1,6 @@
1
1
  require 'date'
2
2
  require 'docker'
3
+ require 'json'
3
4
  require 'rspec/core'
4
5
  require 'time'
5
6
  require 'puppet_docker_tools/utilities'
@@ -29,8 +30,14 @@ class PuppetDockerTools
29
30
  path = "#{repository}/#{image_name}"
30
31
  puts "Building #{path}:latest"
31
32
 
33
+ build_args = {
34
+ 'vcs_ref' => PuppetDockerTools::Utilities.current_git_sha(directory),
35
+ 'build_date' => Time.now.utc.iso8601
36
+ }
37
+
32
38
  # 't' in the build_options sets the tag for the image we're building
33
- build_options = { 't' => "#{path}:latest", 'dockerfile' => dockerfile }
39
+ build_options = { 't' => "#{path}:latest", 'dockerfile' => dockerfile, 'buildargs' => "#{build_args.to_json}"}
40
+
34
41
  if no_cache
35
42
  puts "Ignoring cache for #{path}"
36
43
  build_options['nocache'] = true
@@ -40,29 +47,21 @@ class PuppetDockerTools
40
47
  if version
41
48
  puts "Building #{path}:#{version}"
42
49
 
43
- # 't' in the build_options sets the tag for the image we're building
44
- build_options = { 't' => "#{path}:#{version}", 'dockerfile' => dockerfile }
50
+ build_options['t'] = "#{path}:#{version}"
45
51
  Docker::Image.build_from_dir(directory, build_options)
46
52
  end
47
53
  end
48
54
 
49
- # Run hadolint on the Dockerfile in the specified directory. Hadolint is a
50
- # linter for dockerfiles that also validates inline bash with shellcheck.
51
- # For more info, see the github repo (https://github.com/hadolint/hadolint)
55
+ # Run hadolint on the Dockerfile in the specified directory. This will run
56
+ # hadolint inside of a container. To run a locally-installed hadolint binary
57
+ # see local_lint.
52
58
  #
53
59
  def lint
54
60
  hadolint_container = 'hadolint/hadolint'
55
- ignore_rules = [
56
- 'DL3008',
57
- 'DL3018',
58
- 'DL4000',
59
- 'DL4001',
60
- ]
61
- ignore_string = ignore_rules.map { |x| "--ignore #{x}" }.join(' ')
62
61
 
63
62
  # make sure we have the container locally
64
63
  PuppetDockerTools::Utilities.pull("#{hadolint_container}:latest")
65
- container = Docker::Container.create('Cmd' => ['/bin/sh', '-c', "hadolint #{ignore_string} - "], 'Image' => hadolint_container, 'OpenStdin' => true, 'StdinOnce' => true)
64
+ container = Docker::Container.create('Cmd' => ['/bin/sh', '-c', "#{PuppetDockerTools::Utilities.get_hadolint_command}"], 'Image' => hadolint_container, 'OpenStdin' => true, 'StdinOnce' => true)
66
65
  # This container.tap startes the container created above, and passes directory/Dockerfile to the container
67
66
  container.tap(&:start).attach(stdin: "#{directory}/#{dockerfile}")
68
67
  # Wait for the run to finish
@@ -73,6 +72,13 @@ class PuppetDockerTools
73
72
  end
74
73
  end
75
74
 
75
+ # Run hadolint Dockerfile linting using a local hadolint executable. Executable
76
+ # found based on your path.
77
+ def local_lint
78
+ output, status = Open3.capture2e(PuppetDockerTools::Utilities.get_hadolint_command("#{directory}/#{dockerfile}"))
79
+ fail output unless status == 0
80
+ end
81
+
76
82
  # Push an image to hub.docker.com
77
83
  #
78
84
  def push
@@ -126,6 +126,23 @@ class PuppetDockerTools
126
126
  end
127
127
  end
128
128
 
129
+ # Generate the hadolint command that should be run. Hadolint is a
130
+ # linter for dockerfiles that also validates inline bash with shellcheck.
131
+ # For more info, see the github repo (https://github.com/hadolint/hadolint)
132
+ #
133
+ # @param file Dockerfile to lint, defaults to stdin
134
+ def get_hadolint_command(file = '-')
135
+ ignore_rules = [
136
+ 'DL3008',
137
+ 'DL3018',
138
+ 'DL4000',
139
+ 'DL4001',
140
+ ]
141
+ ignore_string = ignore_rules.map { |x| "--ignore #{x}" }.join(' ')
142
+
143
+ "hadolint #{ignore_string} #{file}"
144
+ end
145
+
129
146
  # Get a value from a Dockerfile
130
147
  #
131
148
  # @param key The key to read from the Dockerfile, e.g. 'from'
@@ -5,10 +5,13 @@ require 'docker'
5
5
  describe PuppetDockerTools::Runner do
6
6
  def create_runner(directory:, repository:, namespace:, dockerfile:)
7
7
  allow(File).to receive(:exist?).with("#{directory}/#{dockerfile}").and_return(true)
8
+ allow(Dir).to receive(:chdir).with(directory).and_return('b0c5ead01b6cabdb3f01871bce699be165c3288f')
9
+ allow(Time).to receive(:now).and_return(Time.at(1528478293))
8
10
  PuppetDockerTools::Runner.new(directory: directory, repository: repository, namespace: namespace, dockerfile: dockerfile)
9
11
  end
10
12
 
11
13
  let(:runner) { create_runner(directory: '/tmp/test-image', repository: 'test', namespace: 'org.label-schema', dockerfile: 'Dockerfile') }
14
+ let(:buildargs) {{ 'vcs_ref' => 'b0c5ead01b6cabdb3f01871bce699be165c3288f', 'build_date' => '2018-06-08T17:18:13Z' }.to_json}
12
15
 
13
16
  describe '#initialize' do
14
17
  it "should fail if the dockerfile doesn't exist" do
@@ -22,27 +25,27 @@ describe PuppetDockerTools::Runner do
22
25
 
23
26
  it 'builds a latest and version tag if version is found' do
24
27
  expect(PuppetDockerTools::Utilities).to receive(:get_value_from_env).with('version', namespace: runner.namespace, directory: runner.directory, dockerfile: runner.dockerfile).and_return('1.2.3')
25
- expect(Docker::Image).to receive(:build_from_dir).with(runner.directory, { 't' => 'test/test-image:1.2.3', 'dockerfile' => runner.dockerfile }).and_return(image)
26
- expect(Docker::Image).to receive(:build_from_dir).with(runner.directory, { 't' => 'test/test-image:latest', 'dockerfile' => runner.dockerfile }).and_return(image)
28
+ expect(Docker::Image).to receive(:build_from_dir).with(runner.directory, { 't' => 'test/test-image:1.2.3', 'dockerfile' => runner.dockerfile, 'buildargs' => buildargs }).and_return(image)
29
+ expect(Docker::Image).to receive(:build_from_dir).with(runner.directory, { 't' => 'test/test-image:latest', 'dockerfile' => runner.dockerfile, 'buildargs' => buildargs }).and_return(image)
27
30
  runner.build
28
31
  end
29
32
 
30
33
  it 'builds just a latest tag if no version is found' do
31
34
  expect(PuppetDockerTools::Utilities).to receive(:get_value_from_env).with('version', namespace: runner.namespace, directory: runner.directory, dockerfile: runner.dockerfile).and_return(nil)
32
- expect(Docker::Image).to receive(:build_from_dir).with(runner.directory, { 't' => 'test/test-image:latest', 'dockerfile' => runner.dockerfile }).and_return(image)
35
+ expect(Docker::Image).to receive(:build_from_dir).with(runner.directory, { 't' => 'test/test-image:latest', 'dockerfile' => runner.dockerfile, 'buildargs' => buildargs }).and_return(image)
33
36
  runner.build
34
37
  end
35
38
 
36
39
  it 'ignores the cache when that parameter is set' do
37
40
  expect(PuppetDockerTools::Utilities).to receive(:get_value_from_env).with('version', namespace: runner.namespace, directory: runner.directory, dockerfile: runner.dockerfile).and_return(nil)
38
- expect(Docker::Image).to receive(:build_from_dir).with(runner.directory, { 't' => 'test/test-image:latest', 'nocache' => true, 'dockerfile' => runner.dockerfile }).and_return(image)
41
+ expect(Docker::Image).to receive(:build_from_dir).with(runner.directory, { 't' => 'test/test-image:latest', 'nocache' => true, 'dockerfile' => runner.dockerfile, 'buildargs' => buildargs }).and_return(image)
39
42
  runner.build(no_cache: true)
40
43
  end
41
44
 
42
45
  it 'uses a custom dockerfile if passed' do
43
46
  allow(File).to receive(:exist?).with('/tmp/test-image/Dockerfile.test').and_return(true)
44
47
  expect(PuppetDockerTools::Utilities).to receive(:get_value_from_env).with('version', namespace: 'org.label-schema', directory: '/tmp/test-image', dockerfile: 'Dockerfile.test').and_return(nil)
45
- expect(Docker::Image).to receive(:build_from_dir).with('/tmp/test-image', { 't' => 'test/test-image:latest', 'dockerfile' => 'Dockerfile.test' }).and_return(image)
48
+ expect(Docker::Image).to receive(:build_from_dir).with('/tmp/test-image', { 't' => 'test/test-image:latest', 'dockerfile' => 'Dockerfile.test', 'buildargs' => buildargs }).and_return(image)
46
49
  local_runner = create_runner(directory: '/tmp/test-image', repository: 'test', namespace: 'org.label-schema', dockerfile: 'Dockerfile.test')
47
50
  local_runner.build
48
51
  end
@@ -86,6 +89,13 @@ describe PuppetDockerTools::Runner do
86
89
  end
87
90
  end
88
91
 
92
+ describe '#local_lint' do
93
+ it "should fail with logs if linting fails" do
94
+ allow(Open3).to receive(:capture2e).with(PuppetDockerTools::Utilities.get_hadolint_command('/tmp/test-image/Dockerfile')).and_return('container logs', 1)
95
+ expect { runner.local_lint }.to raise_error(RuntimeError, /container logs/)
96
+ end
97
+ end
98
+
89
99
  describe '#push' do
90
100
  it 'should fail if no version is set' do
91
101
  expect(PuppetDockerTools::Utilities).to receive(:get_value_from_label).and_return(nil)
@@ -195,4 +195,13 @@ HERE
195
195
  end
196
196
  end
197
197
 
198
+ describe '#get_hadolint_command' do
199
+ it 'generates a commmand with a dockerfile' do
200
+ expect(PuppetDockerTools::Utilities.get_hadolint_command('test/Dockerfile')).to eq('hadolint --ignore DL3008 --ignore DL3018 --ignore DL4000 --ignore DL4001 test/Dockerfile')
201
+ end
202
+
203
+ it 'defaults to generating a command that reads from stdin' do
204
+ expect(PuppetDockerTools::Utilities.get_hadolint_command).to eq('hadolint --ignore DL3008 --ignore DL3018 --ignore DL4000 --ignore DL4001 -')
205
+ end
206
+ end
198
207
  end
@@ -0,0 +1,11 @@
1
+ shared_examples "a running container" do |command, exit_status|
2
+ it "should run #{command} with exit status #{exit_status}" do
3
+ container = Docker::Container.create('Image' => @image.id, 'Cmd' => command)
4
+ container.start
5
+ container.wait
6
+ exit_status = container.json['State']['ExitCode']
7
+ expect(exit_status).to eq(exit_status)
8
+ container.kill
9
+ container.delete(force: true)
10
+ end
11
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puppet_docker_tools
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
  - Puppet, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-24 00:00:00.000000000 Z
11
+ date: 2018-06-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: docker-api
@@ -87,6 +87,7 @@ files:
87
87
  - spec/support/context/with_docker_container.rb
88
88
  - spec/support/context/with_docker_container_dummy_cmd.rb
89
89
  - spec/support/context/with_docker_image.rb
90
+ - spec/support/examples/running_container.rb
90
91
  homepage: https://github.com/puppetlabs/puppet_docker_tools
91
92
  licenses:
92
93
  - Apache-2.0