docker-template 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +30 -4
  3. data/LICENSE +1 -1
  4. data/README.md +79 -14
  5. data/Rakefile +115 -38
  6. data/bin/docker-template +24 -10
  7. data/comp/bin +9 -0
  8. data/comp/list +83 -0
  9. data/comp/list.pak +0 -0
  10. data/lib/docker/template.rb +47 -61
  11. data/lib/docker/template/builder.rb +302 -0
  12. data/lib/docker/template/cache.rb +71 -0
  13. data/lib/docker/template/cli.rb +125 -0
  14. data/lib/docker/template/error.rb +120 -11
  15. data/lib/docker/template/logger.rb +128 -0
  16. data/lib/docker/template/metadata.rb +566 -103
  17. data/lib/docker/template/normal.rb +46 -0
  18. data/lib/docker/template/notify.rb +44 -0
  19. data/lib/docker/template/parser.rb +48 -38
  20. data/lib/docker/template/repo.rb +131 -97
  21. data/lib/docker/template/rootfs.rb +51 -41
  22. data/lib/docker/template/scratch.rb +96 -66
  23. data/lib/docker/template/version.rb +4 -2
  24. data/lib/erb/context.rb +29 -0
  25. data/shas.yml +11 -0
  26. data/templates/rootfs.erb +5 -0
  27. data/templates/rootfs/alpine.erb +71 -0
  28. data/templates/rootfs/ubuntu.erb +76 -0
  29. data/{lib/docker/template/templates → templates}/scratch.erb +0 -1
  30. metadata +64 -50
  31. data/lib/docker/template/alias.rb +0 -28
  32. data/lib/docker/template/ansi.rb +0 -85
  33. data/lib/docker/template/auth.rb +0 -25
  34. data/lib/docker/template/common.rb +0 -130
  35. data/lib/docker/template/config.rb +0 -80
  36. data/lib/docker/template/error/bad_exit_status.rb +0 -17
  37. data/lib/docker/template/error/bad_repo_name.rb +0 -15
  38. data/lib/docker/template/error/invalid_repo_type.rb +0 -16
  39. data/lib/docker/template/error/invalid_targz_file.rb +0 -15
  40. data/lib/docker/template/error/no_rootfs_copy_dir.rb +0 -15
  41. data/lib/docker/template/error/no_rootfs_mkimg.rb +0 -15
  42. data/lib/docker/template/error/no_setup_context_found.rb +0 -15
  43. data/lib/docker/template/error/not_implemented.rb +0 -15
  44. data/lib/docker/template/error/repo_not_found.rb +0 -16
  45. data/lib/docker/template/interface.rb +0 -118
  46. data/lib/docker/template/patches.rb +0 -9
  47. data/lib/docker/template/patches/array.rb +0 -11
  48. data/lib/docker/template/patches/hash.rb +0 -71
  49. data/lib/docker/template/patches/object.rb +0 -9
  50. data/lib/docker/template/patches/pathname.rb +0 -46
  51. data/lib/docker/template/patches/string.rb +0 -9
  52. data/lib/docker/template/routable.rb +0 -28
  53. data/lib/docker/template/simple.rb +0 -49
  54. data/lib/docker/template/stream.rb +0 -63
  55. data/lib/docker/template/templates/rootfs.erb +0 -8
  56. data/lib/docker/template/util.rb +0 -54
  57. data/lib/docker/template/util/copy.rb +0 -77
  58. data/lib/docker/template/util/data.rb +0 -26
@@ -1,22 +1,15 @@
1
+ # ----------------------------------------------------------------------------
1
2
  # Frozen-string-literal: true
2
- # Copyright: 2015 Jordon Bedwell - Apache v2.0 License
3
+ # Copyright: 2015 - 2016 Jordon Bedwell - Apache v2.0 License
3
4
  # Encoding: utf-8
5
+ # ----------------------------------------------------------------------------
4
6
 
5
7
  module Docker
6
8
  module Template
7
- class Rootfs < Common
8
- attr_reader :img
9
- def initialize(repo)
10
- @repo = repo
11
- end
12
-
13
- #
9
+ class Rootfs < Builder
10
+ extend Forwardable::Extended
14
11
 
15
- def rootfs?
16
- true
17
- end
18
-
19
- #
12
+ # ----------------------------------------------------------------------
20
13
 
21
14
  def data
22
15
  Template.get(:rootfs, {
@@ -24,50 +17,67 @@ module Docker
24
17
  })
25
18
  end
26
19
 
27
- # In a typical situation we do not remove the rootfs img and don't
28
- # recommend removing it as it's better cached by Docker, if you wish
29
- # to delete it we will. Now, here we only remove it if we get told
30
- # to exit, since we will be in the middle of a build and probably
31
- # not have tagged yet, unless we are downstream, we will remove
32
- # it so you have no broken images on your system.
20
+ # ----------------------------------------------------------------------
21
+
22
+ def builder_data
23
+ tpl = "rootfs/#{@repo.metadata.rootfs_template}"
24
+ erb = @repo.root.join("rootfs.erb")
25
+
26
+ Template.get(
27
+ erb.file?? erb : tpl, {
28
+ :metadata => @repo.metadata
29
+ }
30
+ )
31
+ end
32
+
33
+ # ----------------------------------------------------------------------
34
+ # During a simple copy you store all the data (including rootfs) data
35
+ # as a single unit, this helps us clean up data that is known to be for
36
+ # just the rootfs image and remove it so it doesn't impact.
37
+ # ----------------------------------------------------------------------
38
+
39
+ def simple_cleanup(dir)
40
+ file = dir.join("usr/local/bin/mkimg")
41
+
42
+ if file.exist?
43
+ then file.delete
44
+ end
45
+ end
46
+
47
+ # ----------------------------------------------------------------------
33
48
 
34
- def unlink(img: true)
35
- keep = @repo.metadata["keep_rootfs"]
36
- @img.delete "force" => true if img && @img && !keep
49
+ def teardown(img: true)
37
50
  @context.rmtree if @context && @context.directory?
38
- rescue Docker::Error::NotFoundError
39
- nil
51
+ @img.delete "force" => true if @img && img \
52
+ rescue nil
40
53
  end
41
54
 
42
- #
55
+ # ----------------------------------------------------------------------
43
56
 
44
57
  private
45
58
  def setup_context
46
59
  @context = @repo.tmpdir("rootfs")
47
- @context.join("Dockerfile").write(data)
48
60
  @copy = @context.join(@repo.metadata["copy_dir"])
49
- @copy.mkdir
61
+ @context.join("Dockerfile").write(data)
62
+
63
+ @copy.join("usr/local/bin").mkdir_p
64
+ @copy.join("usr/local/bin/mkimg").write(builder_data)
65
+ @copy.join("usr/local/bin/mkimg").chmod(0755)
50
66
  copy_rootfs
51
67
  end
52
68
 
53
- #
69
+ # ----------------------------------------------------------------------
54
70
 
55
71
  private
56
72
  def copy_rootfs
57
- dir = @repo.copy_dir("rootfs")
58
- Util::Copy.new(dir, @copy).directory
59
- rescue Errno::ENOENT => error_
60
- if error_.message !~ /\/(copy|rootfs)\Z/
61
- raise error_ else raise Error::NoRootfsCopyDir
62
- end
63
- end
73
+ dir = @repo.copy_dir(
74
+ "rootfs"
75
+ )
64
76
 
65
- #
66
-
67
- private
68
- def verify_context
69
- unless @copy.join("usr/local/bin/mkimg").file?
70
- raise Error::NoRootfsMkimg
77
+ if dir.exist?
78
+ @repo.copy_dir("rootfs").safe_copy(@copy, {
79
+ :root => Template.root
80
+ })
71
81
  end
72
82
  end
73
83
  end
@@ -1,35 +1,49 @@
1
+ # ----------------------------------------------------------------------------
1
2
  # Frozen-string-literal: true
2
- # Copyright: 2015 Jordon Bedwell - Apache v2.0 License
3
+ # Copyright: 2015 - 2016 Jordon Bedwell - Apache v2.0 License
3
4
  # Encoding: utf-8
5
+ # ----------------------------------------------------------------------------
4
6
 
5
7
  module Docker
6
8
  module Template
7
- class Scratch < Common
8
- attr_reader :rootfs, :img, :repo
9
- def initialize(repo)
10
- @repo = repo
9
+ class Scratch < Builder
10
+ attr_reader :rootfs
11
+
12
+ # ----------------------------------------------------------------------
13
+
14
+ def initialize(*args)
15
+ super; @rootfs = Rootfs.new(
16
+ repo
17
+ )
11
18
  end
12
19
 
13
- #
20
+ # ----------------------------------------------------------------------
14
21
 
15
22
  def data
16
23
  Template.get(:scratch, {
17
- :maintainer => @repo.metadata["maintainer"],
18
- :entrypoint => @repo.metadata["entry"].fallback,
24
+ :entrypoint => @repo.metadata.entry,
25
+ :maintainer => @repo.metadata.maintainer,
19
26
  :tar_gz => @tar_gz.basename
20
27
  })
21
28
  end
22
29
 
23
- #
30
+ # ----------------------------------------------------------------------
31
+
32
+ def teardown(img: false)
33
+ @copy.rm_rf if @copy
34
+ @context.rm_rf if @context
35
+ @tar_gz.rm_rf if @tar_gz
24
36
 
25
- def unlink(img: false)
26
- @copy.rmtree if @copy && @copy.directory?
27
- @img.delete "force" => true if @img && img
28
- @context.rmtree if @context && @context.directory?
29
- @tar_gz.unlink if @tar_gz && @tar_gz.file?
37
+ if @img && img
38
+ then @img.delete({
39
+ "force" => true
40
+ })
41
+ end
42
+ rescue Docker::Error::NotFoundError
43
+ nil
30
44
  end
31
45
 
32
- #
46
+ # ----------------------------------------------------------------------
33
47
 
34
48
  private
35
49
  def setup_context
@@ -39,96 +53,112 @@ module Docker
39
53
  copy_dockerfile
40
54
  end
41
55
 
42
- #
56
+ # ----------------------------------------------------------------------
43
57
 
44
58
  private
45
- def build_rootfs
46
- @rootfs ||= begin
47
- self.class.rootfs_for(@repo)
48
- end
59
+ def copy_dockerfile
60
+ data = self.data % @tar_gz.basename
61
+ dockerfile = @context.join("Dockerfile")
62
+ dockerfile.write(data)
49
63
  end
50
64
 
51
- # Caches and builds the master rootfs for repos, this is cached
52
- # on the class because it could be used many times in a single build
53
- # so we make sure to keep it around so you don't have tons of
54
- # replication going about slowing down all of the builds.
65
+ # ----------------------------------------------------------------------
55
66
 
56
- def self.rootfs_for(repo)
57
- (@rootfs ||= {})[repo.name] ||= begin
58
- Rootfs.new(repo).tap(&:build)
67
+ def copy_cleanup
68
+ @rootfs.simple_cleanup(
69
+ @copy
70
+ )
71
+ end
72
+
73
+ # ----------------------------------------------------------------------
74
+
75
+ def verify_context
76
+ if @repo.buildable? && @tar_gz.zero?
77
+ raise Error::InvalidTargzFile, @tar_gz
59
78
  end
60
79
  end
61
80
 
62
- #
81
+ # ----------------------------------------------------------------------
63
82
 
64
83
  private
65
84
  def build_context
66
- build_rootfs
85
+ return unless @repo.buildable?
86
+ @rootfs.build
67
87
 
68
- output_given = false
69
88
  img = Container.create(create_args)
70
- img.start(start_args).attach do |type, str|
71
- type == :stdout ? $stdout.print(str) : $stderr.print(Ansi.red(str))
72
- output_given = true
73
- end
89
+ img.start(start_args).attach(logger_opts, &Logger.new.method(logger_type))
90
+ status = img.json["State"]["ExitCode"]
74
91
 
75
- # NOTE: Sometimes the instance exists too quickly for attach to even
76
- # work, through the remote API, so we need to detect those situations
77
- # and stream the logs after it's exited if we have given no output,
78
- # we want you to always get the output that was given.
79
-
80
- unless output_given
81
- img.streaming_logs "stdout" => true, "stderr" => true do |type, str|
82
- type == :stdout ? $stdout.print(str) : $stderr.print(Ansi.red(str))
83
- end
84
- end
85
-
86
- if (status = img.json["State"]["ExitCode"]) != 0
92
+ if status != 0
87
93
  raise Error::BadExitStatus, status
88
94
  end
89
95
  ensure
90
- img.tap(&:stop).delete("force" => true) if img
96
+ @rootfs.teardown
97
+
98
+ if img
99
+ then img.tap(&:stop).delete({
100
+ "force" => true
101
+ })
102
+ end
91
103
  end
92
104
 
93
- #
105
+ # ----------------------------------------------------------------------
94
106
 
95
- def verify_context
96
- unless @tar_gz.size > 0
97
- raise Error::InvalidTargzFile, @tar_gz
98
- end
107
+ private
108
+ def logger_type
109
+ @repo.metadata["tty"] ? :tty : :simple
99
110
  end
100
111
 
101
- #
112
+ # ----------------------------------------------------------------------
102
113
 
103
114
  private
104
- def copy_dockerfile
105
- data = self.data % @tar_gz.basename
106
- dockerfile = @context.join("Dockerfile")
107
- dockerfile.write(data)
115
+ def logger_opts
116
+ return {
117
+ :tty => @repo.metadata["tty"], :stdout => true, :stderr => true
118
+ }
108
119
  end
109
120
 
110
- #
121
+ # ----------------------------------------------------------------------
111
122
 
112
123
  private
113
124
  def create_args
114
- {
115
- "Env" => @repo.to_env_hash(tar_gz: @tar_gz, copy_dir: @copy).to_env_ary,
116
- "Name" => ["rootfs", @repo.name, @repo.tag, "image"].join("-"),
125
+ name = ["rootfs", @repo.name, @repo.tag, "image"].join("-")
126
+ env = @repo.to_env(:tar_gz => @tar_gz, :copy_dir => @copy)
127
+
128
+ return {
129
+ "Env" => env.to_a,
130
+ "Tty" => @repo.metadata["tty"],
117
131
  "Image" => @rootfs.img.id,
132
+ "Name" => name,
133
+
134
+ "HostConfig" => {
135
+ "Binds" => [
136
+ "#{@copy}:#{@copy}", "#{@tar_gz}:#{@tar_gz}"
137
+ ]
138
+ },
139
+
118
140
  "Volumes" => {
119
- @tar_gz.to_s => {}, @copy.to_s => {}
141
+ @copy.to_s => {
142
+ "source" => @copy.to_s,
143
+ "destination" => @copy.to_s
144
+ },
145
+
146
+ @tar_gz.to_s => {
147
+ "source" => @tar_gz.to_s,
148
+ "destination" => @tar_gz.to_s
149
+ }
120
150
  }
121
151
  }
122
152
  end
123
153
 
124
- #
154
+ # ----------------------------------------------------------------------
125
155
 
126
156
  private
127
157
  def start_args
128
158
  {
129
- "Binds" => [
130
- "#{@copy}:#{@copy}:ro", "#{@tar_gz}:#{@tar_gz}"
131
- ]
159
+ # "Binds" => [
160
+ # "#{@copy}:#{@copy}", "#{@tar_gz}:#{@tar_gz}"
161
+ # ]
132
162
  }
133
163
  end
134
164
  end
@@ -1,9 +1,11 @@
1
+ # ----------------------------------------------------------------------------
1
2
  # Frozen-string-literal: true
2
- # Copyright: 2015 Jordon Bedwell - Apache v2.0 License
3
+ # Copyright: 2015 - 2016 Jordon Bedwell - Apache v2.0 License
3
4
  # Encoding: utf-8
5
+ # ----------------------------------------------------------------------------
4
6
 
5
7
  module Docker
6
8
  module Template
7
- VERSION = "0.2.0"
9
+ VERSION = "0.3.0"
8
10
  end
9
11
  end
@@ -0,0 +1,29 @@
1
+ # ----------------------------------------------------------------------------
2
+ # Frozen-string-literal: true
3
+ # Copyright: 2015 - 2016 Jordon Bedwell - Apache v2.0 License
4
+ # Encoding: utf-8
5
+ # ----------------------------------------------------------------------------
6
+
7
+ require "erb"
8
+ class ERB
9
+ class Context
10
+
11
+ # ------------------------------------------------------------------------
12
+ # Wraps any data you wish to send to ERB limiting it's context access.
13
+ # ------------------------------------------------------------------------
14
+
15
+ def initialize(vars)
16
+ vars.each do |key, val|
17
+ instance_variable_set("@#{key}", val)
18
+ end
19
+ end
20
+
21
+ # ------------------------------------------------------------------------
22
+ # Returns the binding so that we can ship it off and give it to ERB.
23
+ # ------------------------------------------------------------------------
24
+
25
+ def _binding
26
+ return binding
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,11 @@
1
+ alpine:
2
+ apk_tools:
3
+ 3.3: { package: apk-tools-static-2.6.5-r1.apk, sha: 03162d70e6d42eea77624a8da76d69e665ca19aa834361c3652414f111884636 }
4
+ 3.2: { package: apk-tools-static-2.6.3-r0.apk, sha: ee5f42e06731c7447ce8fae99116a637f261e24f67826ca81dbe60ffbdb5c40e }
5
+
6
+ apk_keys:
7
+ 3.3: { package: alpine-keys-1.1-r0.apk, sha: bd1f365f1dbda97e02fceb86fe4ff7e220f31ecc9debfd2a0c43764b45d31d0e }
8
+ 3.2: { package: alpine-keys-1.1-r0.apk, sha: 26e9296d789fd4cae7392a067bed480b502d4302bcb7289d699af42c100622eb }
9
+
10
+ ubuntu:
11
+ signing_key_sha: ""
@@ -0,0 +1,5 @@
1
+ FROM <%= @rootfs_base_img %>
2
+ COPY copy /
3
+ ENTRYPOINT [ \
4
+ "/usr/local/bin/mkimg" \
5
+ ]
@@ -0,0 +1,71 @@
1
+ #!/bin/sh
2
+ [ "$DEBUG" ] && set -x
3
+ set -e
4
+
5
+ arch=$(uname -i)
6
+ rootfs=$(mktemp -d)
7
+ tmp=$(mktemp -d)
8
+
9
+ mirrors="\nhttp://dl-1.alpinelinux.org/alpine/v<%= @metadata.release %>/main"
10
+ mirrors=$mirrors"\nhttp://dl-2.alpinelinux.org/alpine/v<%= @metadata.release %>/main"
11
+ mirrors=$mirrors"\n@testing http://dl-3.alpinelinux.org/alpine/edge/testing"
12
+ mirrors=$mirrors"\n@testing http://dl-4.alpinelinux.org/alpine/edge/testing"
13
+ release_url="http://nl.alpinelinux.org/alpine/v<%= @metadata.release %>/main"
14
+ testing_url="http://nl.alpinelinux.org/alpine/edge/testing"
15
+
16
+ tar_ignore() {
17
+ sed -r "/tar: Ignoring unknown extended header/d"
18
+ }
19
+
20
+ apt-get update && apt-get install --no-install-recommends -y wget
21
+ <% sha1 = @metadata._shas[:alpine][:apk_keys ][@metadata.tag].sha %>
22
+ <% pkg1 = @metadata._shas[:alpine][:apk_keys ][@metadata.tag].package %>
23
+ <% pkg2 = @metadata._shas[:alpine][:apk_tools][@metadata.tag].package %>
24
+ <% sha2 = @metadata._shas[:alpine][:apk_tools][@metadata.tag].sha %>
25
+ for v in <%= sha1 %>:<%= pkg1 %> <%= sha2 %>:<%= pkg2 %>; do
26
+ sha=$(echo $v | awk -F: '{ print $1 }')
27
+ pkg=$(echo $v | awk -F: '{ print $2 }')
28
+ wget -nv -O $tmp/$pkg $release_url/$arch/$pkg
29
+ if [ "$(sha256sum $tmp/$pkg)" != "$sha $tmp/$pkg" ]; then
30
+ >&2 printf "%s sha error: %s" $pkg \
31
+ "$(sha256sum $tmp/$pkg)"
32
+ exit 1
33
+ fi
34
+ done
35
+
36
+ tar xzf $tmp/alpine-keys-*.apk -C $tmp etc/ 2>&1 | tar_ignore
37
+ tar xzf $tmp/apk-tools-static-*.apk -C $tmp sbin/apk.static 2>&1 | tar_ignore
38
+ $tmp/sbin/apk.static --keys-dir=$tmp/etc/apk/keys --initdb --root=$rootfs \
39
+ --repository=$release_url --update-cache add apk-tools busybox \
40
+ libc-utils alpine-baselayout alpine-keys musl
41
+
42
+ cd $tmp
43
+ $tmp/sbin/apk.static --keys-dir=$tmp/etc/apk/keys --root=$rootfs --repository=$release_url --update fetch alpine-base
44
+ tar xzf $tmp/alpine-base-*.apk -C $rootfs etc/ 2>&1 | tar_ignore
45
+ cd -> /dev/null
46
+
47
+ cp -R $COPY_DIR/* $rootfs 2> /dev/null || true
48
+ mkdir -p $rootfs/etc/startup1.d
49
+ mkdir -p $rootfs/etc/startup2.d
50
+ mkdir -p $rootfs/etc/startup3.d
51
+ mkdir -p $rootfs/etc/shutdown.d
52
+
53
+ cp /etc/hosts $rootfs/etc/hosts
54
+ cp /etc/resolv.conf $rootfs/etc/resolv.conf
55
+ printf "$mirrors" > $rootfs/etc/apk/repositories
56
+ <% if @metadata.pkgs? %>chroot $rootfs sh -ec "apk --update add <%= @metadata.pkgs %>"<% end %>
57
+ <% if @metadata.packages? %>chroot $rootfs sh -ec "apk --update add <%= @metadata.packages %>"<% end %>
58
+ <% if @metadata.package_cleanup? %>chroot $rootfs sh -ec "apk del <%= @metadata.package_cleanup %>"<% end %>
59
+ <% if @metadata.pkg_cleanup? %>chroot $rootfs sh -ec "apk del <%= @metadata.pkg_cleanup %>"<% end %>
60
+ chroot $rootfs sh -ec '{
61
+ mv /var/run/* /run 2> /dev/null || true
62
+ mv /var/lock /run 2> /dev/null || true
63
+ rm -rf /var/run /var/lock
64
+ ln -s /run/lock /var/lock
65
+ ln -s /run /var/run
66
+ }'
67
+
68
+ rm -rf $rootfs/etc/hosts
69
+ rm -rf $rootfs/etc/resolv.conf
70
+ docker-helper cleanup $rootfs
71
+ tar -zf $TAR_GZ --numeric-owner -C $rootfs -c .