docker-template 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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 .