dapp 0.2.8 → 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 (49) hide show
  1. checksums.yaml +8 -8
  2. data/config/en/common.yml +3 -1
  3. data/config/en/net_status.yml +5 -2
  4. data/lib/dapp.rb +9 -6
  5. data/lib/dapp/application.rb +30 -5
  6. data/lib/dapp/application/logging.rb +2 -2
  7. data/lib/dapp/application/path.rb +10 -6
  8. data/lib/dapp/build/stage/base.rb +77 -9
  9. data/lib/dapp/build/stage/chef_cookbooks.rb +1 -1
  10. data/lib/dapp/build/stage/from.rb +2 -1
  11. data/lib/dapp/build/stage/infra_install.rb +1 -1
  12. data/lib/dapp/build/stage/source_1.rb +1 -1
  13. data/lib/dapp/build/stage/source_1_archive.rb +0 -4
  14. data/lib/dapp/build/stage/source_2.rb +1 -1
  15. data/lib/dapp/build/stage/source_3.rb +1 -1
  16. data/lib/dapp/build/stage/source_base.rb +3 -3
  17. data/lib/dapp/builder/chef.rb +160 -140
  18. data/lib/dapp/cli.rb +2 -1
  19. data/lib/dapp/cli/base.rb +1 -1
  20. data/lib/dapp/cli/build.rb +7 -7
  21. data/lib/dapp/cli/flush.rb +3 -3
  22. data/lib/dapp/cli/flush/{build_cache.rb → metadata.rb} +7 -7
  23. data/lib/dapp/cli/flush/{stage_cache.rb → stages.rb} +4 -4
  24. data/lib/dapp/cli/push.rb +3 -3
  25. data/lib/dapp/cli/run.rb +59 -0
  26. data/lib/dapp/config/application.rb +20 -2
  27. data/lib/dapp/config/artifact.rb +69 -0
  28. data/lib/dapp/config/chef.rb +27 -0
  29. data/lib/dapp/config/docker.rb +1 -1
  30. data/lib/dapp/config/git_artifact.rb +3 -29
  31. data/lib/dapp/config/shell.rb +20 -0
  32. data/lib/dapp/controller.rb +21 -22
  33. data/lib/dapp/exception/base.rb +1 -5
  34. data/lib/dapp/filelock.rb +1 -1
  35. data/lib/dapp/git_artifact.rb +2 -2
  36. data/lib/dapp/git_repo/base.rb +5 -5
  37. data/lib/dapp/git_repo/own.rb +6 -2
  38. data/lib/dapp/git_repo/remote.rb +5 -3
  39. data/lib/dapp/helper/cli.rb +7 -1
  40. data/lib/dapp/helper/log.rb +2 -2
  41. data/lib/dapp/helper/shellout.rb +1 -1
  42. data/lib/dapp/helper/trivia.rb +0 -4
  43. data/lib/dapp/image/arguments.rb +115 -0
  44. data/lib/dapp/image/docker.rb +76 -0
  45. data/lib/dapp/image/stage.rb +74 -0
  46. data/lib/dapp/version.rb +1 -1
  47. metadata +9 -6
  48. data/lib/dapp/docker_image.rb +0 -51
  49. data/lib/dapp/stage_image.rb +0 -160
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZTFkZDc3NDY0ZWRiMTEyMjM5ZjM5MmJhY2RkNmNlZWE2ZWUyYzFkNQ==
4
+ NTM1NTkwNWNjMzM0YTkzYTdlOGMzODY4MzE4ZGQ5YWZmNjI0YmU5Zg==
5
5
  data.tar.gz: !binary |-
6
- ZjI5NmE2ZTA0YTQwZjg1ZDc0MWI0MWE1ZDM2ZjcxMzAyNzAwNDhmZQ==
6
+ YjM5ODYyYzIzNDA3YjkyODFkYThjYjE2NTFhNDA4MGQxM2IyZGE2Mg==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- OGFiMDcwODlhYmVlZWMxMmM5YTI4OTAyOWIwNDViNjE5ODQxNzc4MzU4NDAz
10
- MjUwZjIyY2VhYTM5MzQ3MGEzYjExMDFkMjYwNTA4ZDRmOGIxYzhlMzRiMTQw
11
- NTgxYmI4NWU3MDM0NGNhZjVjOTdmZTJkNDU1YWMyZTE0ZDRlNzE=
9
+ OThjNmU0YmUyODZlODdkNzI2YjdiM2MyZDA4YmZkOWY2NTdmM2Y4MGJkYWM1
10
+ MTliMzkyMjcwMThiMGMzNTE2MGQyMGI0NGMyMTNlMDdkM2M5NDMzYjcxZTc0
11
+ YzM3YmMzZTkyNGYwZTM4YmJjMjY5YmFkN2U3YmVmMTgwODA5ZWY=
12
12
  data.tar.gz: !binary |-
13
- NjQyYTQzMzA1ZDMzOTY2N2EwODRlMzQyZDU4MjBiNDA4ZWRkOGZlOGU2NGIx
14
- MGM5ZTYzNjg2MjZiOWUzZDU0ZmI4NGNhNzJhZTAwOGE4MTZlN2VjODgyMzI3
15
- ZWMwMTQ4MDQ1MTM0NWI4M2I3MDYzYmQ0MDI0NDM0YjlkNDE2ZGE=
13
+ OWRiZGIzNzY0MTQzYzk3OTJlMDYxNDA4ZjI2OWEwZGQzNDQ2NTQ3NjQ4MGUx
14
+ N2Y4NTVmY2UyNTNhMGUzNmUwMTI1Zjg3ODJjZDhlYmIwZDIyZDgxZTFiZmRm
15
+ YWUwNGU0ZmY1MzJlNmU2ZDNhYmRmYTg1ZWFmODU1ZTYxMWFjZDQ=
@@ -5,10 +5,12 @@ en:
5
5
  info: "date: %{date}\nsize: %{size} MB"
6
6
  commands: "commands:"
7
7
  process:
8
+ artifact_copy: "copying artifact '%{name}'"
8
9
  git_artifact_loading: 'loading git_artifact'
10
+ git_artifact_clone: "cloning remote git_artifact '%{name}'"
11
+ git_artifact_fetch: "fetching remote git_artifact '%{name}'"
9
12
  chefdk_loading: 'loading chefdk'
10
13
  berks_vendor: 'berks_vendor'
11
- git_artifact_fetch: "fetching remote git_artifact '%{name}'"
12
14
  status:
13
15
  process:
14
16
  pushing: '[PUSHING]'
@@ -5,6 +5,7 @@ en:
5
5
  shell_command_failed: ">>> START STREAM\n%{stream}\n>>> END STREAM"
6
6
  application:
7
7
  application_not_built: "Application hasn't been built yet!"
8
+ application_not_run: "Application run failed!"
8
9
  git_branch_without_name: "Application has specific revision that isn't associated with a branch name!"
9
10
  ci_environment_required: 'CI environment required (Travis or GitLab CI)!'
10
11
  build:
@@ -14,11 +15,13 @@ en:
14
15
  another_image_already_tagged: 'Image with other id already tagged!'
15
16
  built_id_not_defined: '`from.built_id` not defined!'
16
17
  controller:
17
- push_command_unexpected_apps: "Push command can process only one application!"
18
+ push_command_unexpected_apps_number: "Push command can process only one application!"
19
+ run_command_unexpected_apps_number: "Run command can process only one application!"
18
20
  no_such_app: "No such app: '%{patterns}' in '%{path}'!"
19
21
  dappfile_not_found: "Dappfile not found!"
20
22
  config:
21
23
  builder_type_conflict: 'Conflict between builder types!'
22
24
  builder_type_unsupported: "Defined unsupported builder type `%{type}`!"
23
25
  docker_from_not_defined: "Docker `from` not defined!"
24
- git_artifact_unexpected_attribute: "'%{type}' git artifact doesn't have attribute '%{attr}'!"
26
+ artifact_unexpected_attribute: "Artifact doesn't have attribute '%{attr}'!"
27
+ git_artifact_unexpected_attribute: "'%{type}' git artifact doesn't have attribute '%{attr}'!"
@@ -32,13 +32,15 @@ require 'dapp/cli/push'
32
32
  require 'dapp/cli/smartpush'
33
33
  require 'dapp/cli/list'
34
34
  require 'dapp/cli/flush'
35
- require 'dapp/cli/flush/stage_cache'
36
- require 'dapp/cli/flush/build_cache'
35
+ require 'dapp/cli/flush/stages'
36
+ require 'dapp/cli/flush/metadata'
37
+ require 'dapp/cli/run'
37
38
  require 'dapp/filelock'
38
39
  require 'dapp/config/application'
39
40
  require 'dapp/config/main'
40
41
  require 'dapp/config/chef'
41
42
  require 'dapp/config/shell'
43
+ require 'dapp/config/artifact'
42
44
  require 'dapp/config/git_artifact'
43
45
  require 'dapp/config/docker'
44
46
  require 'dapp/builder/base'
@@ -66,20 +68,21 @@ require 'dapp/application/logging'
66
68
  require 'dapp/application/path'
67
69
  require 'dapp/application/tags'
68
70
  require 'dapp/application'
69
- require 'dapp/docker_image'
70
- require 'dapp/stage_image'
71
+ require 'dapp/image/arguments'
72
+ require 'dapp/image/docker'
73
+ require 'dapp/image/stage'
71
74
  require 'dapp/git_repo/base'
72
75
  require 'dapp/git_repo/own'
73
76
  require 'dapp/git_repo/remote'
74
77
  require 'dapp/git_artifact'
75
- require 'dapp/exception/base'
76
- require 'dapp/exception/introspect_image'
77
78
  require 'dapp/error/base'
78
79
  require 'dapp/error/application'
79
80
  require 'dapp/error/build'
80
81
  require 'dapp/error/config'
81
82
  require 'dapp/error/controller'
82
83
  require 'dapp/error/shellout'
84
+ require 'dapp/exception/base'
85
+ require 'dapp/exception/introspect_image'
83
86
 
84
87
  # Dapp
85
88
  module Dapp
@@ -14,21 +14,28 @@ module Dapp
14
14
  attr_reader :config
15
15
  attr_reader :cli_options
16
16
  attr_reader :ignore_git_fetch
17
+ attr_reader :is_artifact
17
18
 
18
- def initialize(config:, cli_options:, ignore_git_fetch: false)
19
+ def initialize(config:, cli_options:, ignore_git_fetch: false, is_artifact: false)
19
20
  @config = config
20
21
  @cli_options = cli_options
21
22
 
22
- @build_path = cli_options[:build_dir] || home_path('build')
23
- @build_cache_path = cli_options[:build_cache_dir] || home_path('build_cache')
23
+ @tmp_path = Dir.mktmpdir(cli_options[:tmp_dir_prefix] || 'dapp-')
24
+ @metadata_path = cli_options[:metadata_dir] || home_path('.dapps-metadata')
24
25
 
25
26
  @last_stage = Build::Stage::Source5.new(self)
26
27
  @ignore_git_fetch = ignore_git_fetch
28
+ @is_artifact = is_artifact
27
29
  end
28
30
 
29
31
  def build!
30
- last_stage.build!
31
- last_stage.save_in_cache!
32
+ log_step(config._name)
33
+ with_log_indent do
34
+ last_stage.build!
35
+ last_stage.save_in_cache!
36
+ end
37
+ ensure
38
+ FileUtils.rm_rf(tmp_path)
32
39
  end
33
40
 
34
41
  def export!(repo)
@@ -46,10 +53,28 @@ module Dapp
46
53
  end
47
54
  end
48
55
 
56
+ def run(docker_options, command)
57
+ raise Error::Application, code: :application_not_built unless last_stage.image.tagged?
58
+ cmd = "docker run #{[docker_options, last_stage.image.name, command].flatten.compact.join(' ')}"
59
+ if dry_run?
60
+ log_info(cmd)
61
+ else
62
+ system(cmd) || raise(Error::Application, code: :application_not_run)
63
+ end
64
+ end
65
+
66
+ def signature
67
+ last_stage.send(:signature)
68
+ end
69
+
49
70
  def builder
50
71
  @builder ||= Builder.const_get(config._builder.capitalize).new(self)
51
72
  end
52
73
 
74
+ def meta_options
75
+ { cli_options: cli_options, ignore_git_fetch: ignore_git_fetch }
76
+ end
77
+
53
78
  protected
54
79
 
55
80
  attr_reader :last_stage
@@ -58,8 +58,8 @@ module Dapp
58
58
  end
59
59
  end
60
60
 
61
- def log_secondary_process(message, **kvargs, &blk)
62
- log_process(message, **kvargs.merge(style: { message: :secondary, success: :secondary }), &blk)
61
+ def log_secondary_process(message, **kwargs, &blk)
62
+ log_process(message, **kwargs.merge(style: { message: :secondary, success: :secondary }), &blk)
63
63
  end
64
64
 
65
65
  def log_process_verbose(message, process:, style: {}, &blk)
@@ -7,16 +7,20 @@ module Dapp
7
7
  make_path(config._home_path, *path).expand_path
8
8
  end
9
9
 
10
- def build_path(*path)
11
- make_path(@build_path, *path).expand_path.tap { |p| FileUtils.mkdir_p p.parent }
10
+ def tmp_path(*path)
11
+ make_path(@tmp_path, *path).expand_path.tap { |p| FileUtils.mkdir_p p.parent }
12
12
  end
13
13
 
14
- def build_cache_path(*path)
15
- make_path(@build_cache_path, *path).expand_path.tap { |p| FileUtils.mkdir_p p.parent }
14
+ def metadata_path(*path)
15
+ make_path(@metadata_path, home_path.basename, *path).expand_path.tap { |p| FileUtils.mkdir_p p.parent }
16
16
  end
17
17
 
18
- def container_build_path(*path)
19
- make_path('/.build', *path)
18
+ def container_dapp_path(*path)
19
+ make_path('/.dapp', *path)
20
+ end
21
+
22
+ def container_tmp_path(*path)
23
+ container_dapp_path('tmp', *path)
20
24
  end
21
25
 
22
26
  private
@@ -46,14 +46,16 @@ module Dapp
46
46
  end
47
47
 
48
48
  def signature
49
- hashsum prev_stage.signature
49
+ hashsum [prev_stage.signature, artifacts_signatures]
50
50
  end
51
51
 
52
52
  def image
53
53
  @image ||= begin
54
- StageImage.new(name: image_name, from: from_image).tap do |image|
55
- image.add_volume "#{application.build_path}:#{application.container_build_path}"
54
+ Image::Stage.new(name: image_name, from: from_image).tap do |image|
55
+ image.add_volume "#{application.tmp_path}:#{application.container_tmp_path}"
56
+ before_artifacts.each { |artifact| apply_artifact(artifact, image) }
56
57
  yield image if block_given?
58
+ after_artifacts.each { |artifact| apply_artifact(artifact, image) }
57
59
  end
58
60
  end
59
61
  end
@@ -73,7 +75,7 @@ module Dapp
73
75
  end
74
76
 
75
77
  def should_be_introspected?
76
- application.cli_options[:introspect_stage] == name && !application.dry_run?
78
+ application.cli_options[:introspect_stage] == name && !application.dry_run? && !application.is_artifact
77
79
  end
78
80
 
79
81
  def image_build!
@@ -94,14 +96,14 @@ module Dapp
94
96
  end
95
97
 
96
98
  def image_info
97
- date, bytesize = image.info
98
- _date, from_bytesize = from_image.info
99
- [date, (from_bytesize.to_i - bytesize.to_i).abs]
99
+ date, size = image.info
100
+ _date, from_size = from_image.info
101
+ [date, (from_size.to_f - size.to_f).abs]
100
102
  end
101
103
 
102
104
  def format_image_info
103
- date, bytesize = image_info
104
- application.t(code: 'image.info', data: { date: Time.parse(date).localtime, size: to_mb(bytesize.to_i) })
105
+ date, size = image_info
106
+ application.t(code: 'image.info', data: { date: Time.parse(date).localtime, size: size.to_f.round(2) })
105
107
  end
106
108
 
107
109
  # rubocop:disable Metrics/AbcSize
@@ -115,6 +117,72 @@ module Dapp
115
117
  end
116
118
  end if application.log? && application.log_verbose?
117
119
  end
120
+ # rubocop:enable Metrics/AbcSize
121
+
122
+ def before_artifacts
123
+ @before_artifacts ||= do_artifacts(application.config._artifact.select { |artifact| artifact._before == name })
124
+ end
125
+
126
+ def after_artifacts
127
+ @after_artifacts ||= do_artifacts(application.config._artifact.select { |artifact| artifact._after == name })
128
+ end
129
+
130
+ def do_artifacts(artifacts)
131
+ artifacts.map do |artifact|
132
+ {
133
+ name: artifact._config._name,
134
+ options: artifact._artifact_options,
135
+ app: Application.new(config: artifact._config, is_artifact: true, **application.meta_options).tap(&:build!)
136
+ }
137
+ end
138
+ end
139
+
140
+ def artifacts_signatures
141
+ (before_artifacts + after_artifacts).map { |artifact| hashsum [artifact[:app].signature, artifact[:options]] }
142
+ end
143
+
144
+ def apply_artifact(artifact, image)
145
+ return if application.dry_run?
146
+
147
+ artifact_name = artifact[:name]
148
+ app = artifact[:app]
149
+ cwd = artifact[:options][:cwd]
150
+ paths = artifact[:options][:paths]
151
+ owner = artifact[:options][:owner]
152
+ group = artifact[:options][:group]
153
+ where_to_add = artifact[:options][:where_to_add]
154
+
155
+ docker_options = ['--rm',
156
+ "--volume #{application.tmp_path('artifact', artifact_name)}:#{app.container_tmp_path(artifact_name)}",
157
+ '--entrypoint /bin/sh']
158
+ commands = safe_cp(where_to_add, app.container_tmp_path(artifact_name), Process.uid, Process.gid)
159
+ application.log_secondary_process(application.t(code: 'process.artifact_copy', data: { name: artifact_name }), short: true) do
160
+ app.run(docker_options, Array(application.shellout_pack(commands)))
161
+ end
162
+
163
+ commands = safe_cp(application.container_tmp_path('artifact', artifact_name), where_to_add, owner, group, cwd, paths)
164
+ image.add_commands commands
165
+ end
166
+
167
+ # rubocop:disable Metrics/ParameterLists
168
+ def safe_cp(from, to, owner, group, cwd = '', paths = [])
169
+ credentials = ''
170
+ credentials += "-o #{owner} " if owner
171
+ credentials += "-g #{group} " if group
172
+
173
+ commands = []
174
+ commands << ['install', credentials, '-d', to].join(' ')
175
+
176
+ copy_files = lambda do |from_, cwd_, path_ = ''|
177
+ "find #{File.join(from_, cwd_, path_)} -type f -exec bash -ec 'install -D #{credentials} {} " \
178
+ "#{File.join(to, "$(echo {} | sed -e \"s/#{File.join(from_, cwd_).gsub('/', '\\/')}//g\")")}' \\;"
179
+ end
180
+
181
+ commands.concat(paths.empty? ? Array(copy_files.call(from, cwd)) : paths.map { |path| copy_files.call(from, cwd, path) })
182
+ commands << "find #{to} -type d -exec bash -ec 'install -d #{credentials} {}' \\;"
183
+ commands.join(' && ')
184
+ end
185
+ # rubocop:enable Metrics/ParameterLists
118
186
  end # Base
119
187
  end # Stage
120
188
  end # Build
@@ -9,7 +9,7 @@ module Dapp
9
9
  end
10
10
 
11
11
  def signature
12
- hashsum [prev_stage.signature, *application.builder.chef_cookbooks_checksum]
12
+ hashsum [super, *application.builder.chef_cookbooks_checksum]
13
13
  end
14
14
 
15
15
  def image
@@ -5,6 +5,7 @@ module Dapp
5
5
  class From < Base
6
6
  def signature
7
7
  hashsum [from_image_name,
8
+ artifacts_signatures,
8
9
  application.config._docker._from_cache_version,
9
10
  Dapp::BUILD_CACHE_VERSION]
10
11
  end
@@ -28,7 +29,7 @@ module Dapp
28
29
  end
29
30
 
30
31
  def from_image
31
- @from_image ||= StageImage.new(name: from_image_name)
32
+ @from_image ||= Image::Stage.new(name: from_image_name)
32
33
  end
33
34
 
34
35
  def image_info
@@ -9,7 +9,7 @@ module Dapp
9
9
  end
10
10
 
11
11
  def signature
12
- hashsum [prev_stage.signature, *application.builder.infra_install_checksum]
12
+ hashsum [super, *application.builder.infra_install_checksum]
13
13
  end
14
14
 
15
15
  def image
@@ -15,7 +15,7 @@ module Dapp
15
15
  protected
16
16
 
17
17
  def dependencies_checksum
18
- hashsum [prev_stage.signature,
18
+ hashsum [super,
19
19
  app_install_files_checksum,
20
20
  *application.builder.app_install_checksum]
21
21
  end
@@ -16,10 +16,6 @@ module Dapp
16
16
  next_stage
17
17
  end
18
18
 
19
- def container_archive_path(git_artifact)
20
- application.container_build_path git_artifact.filename '.tar.gz'
21
- end
22
-
23
19
  protected
24
20
 
25
21
  def apply_command_method
@@ -11,7 +11,7 @@ module Dapp
11
11
  protected
12
12
 
13
13
  def dependencies_checksum
14
- hashsum [prev_stage.signature,
14
+ hashsum [super,
15
15
  *application.builder.infra_setup_checksum]
16
16
  end
17
17
  end # Source2
@@ -11,7 +11,7 @@ module Dapp
11
11
  protected
12
12
 
13
13
  def dependencies_checksum
14
- hashsum [prev_stage.signature,
14
+ hashsum [super,
15
15
  app_setup_files_checksum,
16
16
  *application.builder.app_setup_checksum]
17
17
  end
@@ -29,7 +29,7 @@ module Dapp
29
29
  bash_commands = []
30
30
  volumes = []
31
31
  application.git_artifacts.each do |git_artifact|
32
- volumes << "#{git_artifact.repo.dir_path}:#{git_artifact.repo.container_build_dir_path}"
32
+ volumes << "#{git_artifact.repo.path}:#{git_artifact.repo.container_path}"
33
33
  bash_commands.concat(git_artifact.send(apply_command_method, self))
34
34
  end
35
35
 
@@ -43,7 +43,7 @@ module Dapp
43
43
  end
44
44
 
45
45
  def dependencies_checksum
46
- hashsum [prev_stage.signature]
46
+ hashsum [prev_stage.signature, artifacts_signatures]
47
47
  end
48
48
 
49
49
  def layer_commit(git_artifact)
@@ -94,7 +94,7 @@ module Dapp
94
94
  end
95
95
 
96
96
  def layer_commit_file_path(git_artifact)
97
- application.build_path git_artifact.filename ".#{name}.#{git_artifact.paramshash}.#{dependencies_checksum}.commit"
97
+ application.metadata_path git_artifact.filename ".#{name}.#{git_artifact.paramshash}.#{dependencies_checksum}.commit"
98
98
  end
99
99
 
100
100
  def dependency_files_checksum(regs)
@@ -2,34 +2,23 @@ module Dapp
2
2
  module Builder
3
3
  # Chef
4
4
  class Chef < Base
5
- LOCAL_COOKBOOK_PATTERNS = %w(
5
+ LOCAL_COOKBOOK_CHECKSUM_PATTERNS = %w(
6
6
  recipes/**/*
7
7
  files/**/*
8
8
  templates/**/*
9
9
  ).freeze
10
10
 
11
- STAGE_LOCAL_COOKBOOK_PATTERNS = %w(
12
- metadata.json
13
- recipes/%{stage}.rb
14
- recipes/*_%{stage}.rb
15
- files/default/%{stage}/*
16
- templates/default/%{stage}/*
17
- ).freeze
18
-
19
11
  DEFAULT_CHEFDK_IMAGE = 'dappdeps/chefdk:0.17.3-1'.freeze # TODO: config, DSL, DEFAULT_CHEFDK_IMAGE
20
12
 
21
13
  [:infra_install, :infra_setup, :app_install, :app_setup].each do |stage|
22
14
  define_method(:"#{stage}_checksum") { stage_cookbooks_checksum(stage) }
23
15
 
24
16
  define_method(:"#{stage}") do |image|
25
- install_stage_cookbooks(stage)
26
- install_chef_solo_stage_config(stage)
27
-
28
17
  unless stage_empty?(stage)
29
18
  image.add_volumes_from(chefdk_container)
30
19
  image.add_commands 'export PATH=/.dapp/deps/chefdk/bin:$PATH'
31
20
 
32
- image.add_volume "#{stage_build_path(stage)}:#{container_stage_build_path(stage)}"
21
+ image.add_volume "#{stage_tmp_path(stage)}:#{container_stage_tmp_path(stage)}"
33
22
  image.add_commands ['chef-solo',
34
23
  "-c #{container_stage_config_path(stage)}",
35
24
  "-o #{stage_cookbooks_runlist(stage).join(',')}"].join(' ')
@@ -42,9 +31,11 @@ module Dapp
42
31
  end
43
32
 
44
33
  def chef_cookbooks(image)
34
+ image.add_volume "#{cookbooks_vendor_path}:#{application.container_dapp_path('chef_vendored_cookbooks')}"
45
35
  image.add_commands(
46
- "mkdir -p /usr/share/dapp/chef_repo",
47
- "cp -a #{container_cookbooks_vendor_path} /usr/share/dapp/chef_repo/cookbooks"
36
+ 'mkdir -p /usr/share/dapp/chef_repo',
37
+ ["cp -a #{application.container_dapp_path('chef_vendored_cookbooks')} ",
38
+ '/usr/share/dapp/chef_repo/cookbooks'].join
48
39
  )
49
40
  end
50
41
 
@@ -74,76 +65,40 @@ module Dapp
74
65
  @cookbook_metadata ||= CookbookMetadata.new(cookbook_metadata_path)
75
66
  end
76
67
 
68
+
77
69
  def berksfile_lock_checksum
78
70
  application.hashsum berksfile_lock_path.read if berksfile_lock_path.exist?
79
71
  end
80
72
 
81
- # rubocop:disable Metrics/AbcSize
82
- def stage_cookbooks_runlist(stage)
83
- @stage_cookbooks_runlist ||= {}
84
- @stage_cookbooks_runlist[stage] ||= [].tap do |res|
85
- to_runlist_entrypoint = proc do |name, entrypoint|
86
- entrypoint_file = stage_cookbooks_path(stage, name, 'recipes', "#{entrypoint}.rb")
87
- next unless entrypoint_file.exist?
88
- "#{name}::#{entrypoint}"
89
- end
90
-
91
- res.concat(application.config._chef._modules.map do |name|
92
- to_runlist_entrypoint[name, stage]
93
- end.compact)
94
-
95
- project_main_entry = to_runlist_entrypoint[project_name, stage]
96
- res << project_main_entry if project_main_entry
97
-
98
- res.concat(application.config._app_runlist.map do |app_component|
99
- to_runlist_entrypoint[project_name, [app_component, stage].join('_')]
100
- end.compact)
101
- end
102
- end
103
- # rubocop:enable Metrics/AbcSize
104
-
105
- def local_cookbook_paths
106
- @local_cookbook_paths ||= berksfile.local_cookbooks
107
- .values
108
- .map { |cookbook| cookbook[:path] }
109
- .product(LOCAL_COOKBOOK_PATTERNS)
110
- .map { |cb, dir| Dir[cb.join(dir)] }
111
- .flatten
112
- .map(&Pathname.method(:new))
113
- end
114
-
115
- def stage_cookbooks_vendored_paths(stage, with_files: false)
116
- Dir[cookbooks_vendor_path('*')]
117
- .map do |cookbook_path|
118
- if ['mdapp-*', project_name].any? { |pattern| File.fnmatch(pattern, File.basename(cookbook_path)) }
119
- STAGE_LOCAL_COOKBOOK_PATTERNS.map do |pattern|
120
- Dir[File.join(cookbook_path, pattern % { stage: stage })]
121
- end
122
- elsif with_files
123
- Dir[File.join(cookbook_path, '**/*')]
124
- else
125
- cookbook_path
126
- end
127
- end
73
+ def local_cookbook_paths_for_checksum
74
+ @local_cookbook_paths_for_checksum ||= berksfile
75
+ .local_cookbooks
76
+ .values
77
+ .map { |cookbook| cookbook[:path] }
78
+ .product(LOCAL_COOKBOOK_CHECKSUM_PATTERNS)
79
+ .map { |cb, dir| Dir[cb.join(dir)] }
128
80
  .flatten
129
81
  .map(&Pathname.method(:new))
130
82
  end
131
83
 
84
+ def stage_cookbooks_paths_for_checksum(stage)
85
+ install_stage_cookbooks(stage)
86
+ Dir[stage_cookbooks_path(stage, '**/*')].map(&Pathname.method(:new))
87
+ end
88
+
132
89
  def stage_cookbooks_checksum_path(stage)
133
- application.build_cache_path("#{cookbooks_checksum}.#{stage}.checksum")
90
+ application.metadata_path("#{cookbooks_checksum}.#{stage}.checksum")
134
91
  end
135
92
 
136
93
  def stage_cookbooks_checksum(stage)
137
94
  if stage_cookbooks_checksum_path(stage).exist?
138
95
  stage_cookbooks_checksum_path(stage).read.strip
139
96
  else
140
- install_cookbooks
141
-
142
- if stage == :chef_cookbooks
143
- checksum = cookbooks_checksum
97
+ checksum = if stage == :chef_cookbooks
98
+ cookbooks_checksum
144
99
  else
145
- checksum = application.hashsum [
146
- _paths_checksum(stage_cookbooks_vendored_paths(stage, with_files: true)),
100
+ application.hashsum [
101
+ _paths_checksum(stage_cookbooks_paths_for_checksum(stage)),
147
102
  *application.config._chef._modules,
148
103
  stage == :infra_install ? chefdk_image : nil
149
104
  ].compact
@@ -157,11 +112,12 @@ module Dapp
157
112
  def cookbooks_checksum
158
113
  @cookbooks_checksum ||= application.hashsum [
159
114
  berksfile_lock_checksum,
160
- _paths_checksum(local_cookbook_paths),
115
+ _paths_checksum(local_cookbook_paths_for_checksum),
161
116
  *application.config._chef._modules
162
117
  ]
163
118
  end
164
119
 
120
+
165
121
  def chefdk_image
166
122
  DEFAULT_CHEFDK_IMAGE # TODO: config, DSL, DEFAULT_CHEFDK_IMAGE
167
123
  end
@@ -187,101 +143,165 @@ module Dapp
187
143
  end
188
144
  end
189
145
 
146
+
190
147
  # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
191
148
  def install_cookbooks
192
- @install_cookbooks ||= begin
193
- volumes_from = chefdk_container
194
- application.log_secondary_process(application.t(code: 'process.berks_vendor')) do
195
- ssh_auth_socket_path = nil
196
- ssh_auth_socket_path = Pathname.new(ENV['SSH_AUTH_SOCK']).expand_path if ENV['SSH_AUTH_SOCK'] && File.exist?(ENV['SSH_AUTH_SOCK'])
197
-
198
- vendor_commands = [
199
- 'mkdir -p ~/.ssh',
200
- 'echo "Host *" >> ~/.ssh/config',
201
- 'echo " StrictHostKeyChecking no" >> ~/.ssh/config',
202
- 'if [ ! -f Berksfile.lock ] ; then echo "Berksfile.lock not found" 1>&2 ; exit 1 ; fi',
203
- 'cp -a Berksfile.lock /tmp/Berksfile.lock.orig',
204
- '/.dapp/deps/chefdk/bin/berks vendor /tmp/vendored_cookbooks',
205
- 'export LOCKDIFF=$(diff -u0 Berksfile.lock /tmp/Berksfile.lock.orig)',
206
- ['if [ "$LOCKDIFF" != "" ] ; then ',
207
- 'cp -a /tmp/Berksfile.lock.orig Berksfile.lock ; ',
208
- 'echo -e "Bad Berksfile.lock\n$LOCKDIFF" 1>&2 ; exit 1 ; fi'].join,
209
- ["find /tmp/vendored_cookbooks -type f -exec bash -ec '",
210
- "install -D -o #{Process.uid} -g #{Process.gid} --mode $(stat -c %a {}) {} ",
211
- "#{cookbooks_vendor_path}/$(echo {} | sed -e \"s/\\/tmp\\/vendored_cookbooks\\///g\")' \\;"].join,
212
- "chown -R #{Process.uid}:#{Process.gid} #{berksfile_lock_path}",
213
- ]
214
-
215
- application.shellout!(
216
- ['docker run --rm',
217
- ("--volume #{ssh_auth_socket_path}:#{ssh_auth_socket_path}" if ssh_auth_socket_path),
218
- "--volume #{cookbooks_vendor_path.tap(&:mkpath)}:#{cookbooks_vendor_path}",
219
- *berksfile.local_cookbooks
220
- .values
221
- .map { |cookbook| "--volume #{cookbook[:path]}:#{cookbook[:path]}" },
222
- "--volumes-from #{volumes_from}",
223
- "--workdir #{berksfile_path.parent}",
224
- ("--env SSH_AUTH_SOCK=#{ssh_auth_socket_path}" if ssh_auth_socket_path),
225
- "dappdeps/berksdeps:0.1.0 #{application.shellout_pack(vendor_commands.join(' && '))}"].compact.join(' '),
226
- log_verbose: application.log_verbose?
227
- )
228
-
229
- true
230
- end
149
+ volumes_from = chefdk_container
150
+ application.log_secondary_process(application.t(code: 'process.berks_vendor')) do
151
+ ssh_auth_socket_path = nil
152
+ ssh_auth_socket_path = Pathname.new(ENV['SSH_AUTH_SOCK']).expand_path if ENV['SSH_AUTH_SOCK'] && File.exist?(ENV['SSH_AUTH_SOCK'])
153
+
154
+ vendor_commands = [
155
+ 'mkdir -p ~/.ssh',
156
+ 'echo "Host *" >> ~/.ssh/config',
157
+ 'echo " StrictHostKeyChecking no" >> ~/.ssh/config',
158
+ 'if [ ! -f Berksfile.lock ] ; then echo "Berksfile.lock not found" 1>&2 ; exit 1 ; fi',
159
+ 'cp -a Berksfile.lock /tmp/Berksfile.lock.orig',
160
+ '/.dapp/deps/chefdk/bin/berks vendor /tmp/vendored_cookbooks',
161
+ 'export LOCKDIFF=$(diff -u0 Berksfile.lock /tmp/Berksfile.lock.orig)',
162
+ ['if [ "$LOCKDIFF" != "" ] ; then ',
163
+ 'cp -a /tmp/Berksfile.lock.orig Berksfile.lock ; ',
164
+ 'echo -e "Bad Berksfile.lock\n$LOCKDIFF" 1>&2 ; exit 1 ; fi'].join,
165
+ ["find /tmp/vendored_cookbooks -type f -exec bash -ec '",
166
+ "install -D -o #{Process.uid} -g #{Process.gid} --mode $(stat -c %a {}) {} ",
167
+ "#{_cookbooks_vendor_path}/$(echo {} | sed -e \"s/\\/tmp\\/vendored_cookbooks\\///g\")' \\;"].join
168
+ ]
169
+
170
+ application.shellout!(
171
+ ['docker run --rm',
172
+ ("--volume #{ssh_auth_socket_path}:#{ssh_auth_socket_path}" if ssh_auth_socket_path),
173
+ "--volume #{_cookbooks_vendor_path.tap(&:mkpath)}:#{_cookbooks_vendor_path}",
174
+ *berksfile.local_cookbooks
175
+ .values
176
+ .map { |cookbook| "--volume #{cookbook[:path]}:#{cookbook[:path]}" },
177
+ "--volumes-from #{volumes_from}",
178
+ "--workdir #{berksfile_path.parent}",
179
+ ("--env SSH_AUTH_SOCK=#{ssh_auth_socket_path}" if ssh_auth_socket_path),
180
+ "dappdeps/berksdeps:0.1.0 bash #{application.shellout_pack(vendor_commands.join(' && '))}"].compact.join(' '),
181
+ log_verbose: application.log_verbose?
182
+ )
183
+
184
+ true
231
185
  end
232
186
  end
233
187
  # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
234
188
 
235
- def install_stage_cookbooks(stage)
236
- stage_cookbooks_path(stage).mkpath
237
- stage_cookbooks_vendored_paths(stage).each do |path|
238
- new_path = stage_cookbooks_path(stage, path.relative_path_from(cookbooks_vendor_path))
239
- new_path.parent.mkpath
240
- FileUtils.cp_r path, new_path
241
- end
189
+ def _cookbooks_vendor_path
190
+ application.metadata_path("cookbooks.#{cookbooks_checksum}")
242
191
  end
243
192
 
244
- def stage_empty?(stage)
245
- stage_cookbooks_runlist(stage).empty?
193
+ def cookbooks_vendor_path(*path)
194
+ _cookbooks_vendor_path.tap do |cookbooks_path|
195
+ install_cookbooks unless cookbooks_path.exist?
196
+ end.join(*path)
246
197
  end
247
198
 
248
- def install_chef_solo_stage_config(stage)
249
- stage_config_path(stage).write [
250
- "file_cache_path \"/var/cache/dapp/chef\"\n",
251
- "cookbook_path \"#{container_stage_cookbooks_path(stage)}\"\n"
252
- ].join
253
- end
254
199
 
255
- def cookbooks_vendor_path(*path)
256
- application.build_path('chef', 'vendored_cookbooks').join(*path)
257
- end
200
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
201
+ def install_stage_cookbooks(stage)
202
+ @install_stage_cookbooks ||= {}
203
+ @install_stage_cookbooks[stage] ||= true.tap do
204
+ common_paths = proc do |cookbook_path|
205
+ [['metadata.json', 'metadata.json'],
206
+ ["files/#{stage}", 'files/default'],
207
+ ["templates/#{stage}", 'templates/default']
208
+ ].select { |from, _| cookbook_path.join(from).exist? }
209
+ end
258
210
 
259
- def container_cookbooks_vendor_path(*path)
260
- application.container_build_path('chef', 'vendored_cookbooks').join(*path)
211
+ install_paths = Dir[cookbooks_vendor_path('*')]
212
+ .map(&Pathname.method(:new))
213
+ .map { |cookbook_path|
214
+ cookbook_name = File.basename cookbook_path
215
+ is_project = (cookbook_name == project_name)
216
+ is_mdapp = cookbook_name.start_with? 'mdapp-'
217
+ mdapp_enabled = is_mdapp && application.config._chef._modules.include?(cookbook_name)
218
+
219
+ paths = if is_project
220
+ recipe_paths = application.config._chef._recipes
221
+ .map { |recipe| ["recipes/#{stage}/#{recipe}.rb", "recipes/#{recipe}.rb"] }
222
+ .select { |from, _| cookbook_path.join(from).exist? }
223
+
224
+ (recipe_paths + common_paths[cookbook_path]) if recipe_paths.any?
225
+ elsif is_mdapp and mdapp_enabled
226
+ recipe_path = "recipes/#{stage}.rb"
227
+ if cookbook_path.join(recipe_path).exist?
228
+ [[recipe_path, recipe_path]] + common_paths[cookbook_path]
229
+ end
230
+ else
231
+ [['.', '.']]
232
+ end
233
+
234
+ [cookbook_path, paths] if paths and paths.any?
235
+ }
236
+ .compact
237
+
238
+ stage_cookbooks_path(stage).mkpath
239
+ install_paths.each do |cookbook_path, paths|
240
+ paths.each do |from, to|
241
+ from_path = cookbook_path.join(from)
242
+ to_path = stage_cookbooks_path(stage, cookbook_path.basename, to)
243
+ to_path.parent.mkpath
244
+ FileUtils.cp_r from_path, to_path
245
+ end
246
+ end
247
+ end
261
248
  end
249
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
250
+
251
+ # rubocop:disable Metrics/AbcSize
252
+ def stage_cookbooks_runlist(stage)
253
+ install_stage_cookbooks(stage)
254
+
255
+ @stage_cookbooks_runlist ||= {}
256
+ @stage_cookbooks_runlist[stage] ||= [].tap do |res|
257
+ to_runlist_entrypoint = proc do |cookbook, entrypoint|
258
+ entrypoint_file = stage_cookbooks_path(stage, cookbook, 'recipes', "#{entrypoint}.rb")
259
+ next unless entrypoint_file.exist?
260
+ "#{cookbook}::#{entrypoint}"
261
+ end
262
+
263
+ res.concat(application.config._chef._recipes.map do |recipe|
264
+ to_runlist_entrypoint[project_name, recipe]
265
+ end.flatten.compact)
262
266
 
263
- def stage_build_path(stage, *path)
264
- application.build_path(application.config._name, stage).join(*path)
267
+ res.concat(application.config._chef._modules.map do |mod|
268
+ to_runlist_entrypoint[mod, stage]
269
+ end.flatten.compact)
270
+ end
265
271
  end
272
+ # rubocop:enable Metrics/AbcSize
266
273
 
267
- def container_stage_build_path(_stage, *path)
268
- path.compact.map(&:to_s).inject(Pathname.new('/chef_build'), &:+)
274
+ def stage_empty?(stage)
275
+ stage_cookbooks_runlist(stage).empty?
269
276
  end
270
277
 
271
278
  def stage_cookbooks_path(stage, *path)
272
- stage_build_path(stage, 'cookbooks', *path)
279
+ stage_tmp_path(stage, 'cookbooks', *path)
273
280
  end
274
281
 
275
- def container_stage_cookbooks_path(stage, *path)
276
- container_stage_build_path(stage, 'cookbooks', *path)
277
- end
278
282
 
279
- def stage_config_path(stage, *path)
280
- stage_build_path(stage, 'config.rb', *path)
283
+ def install_chef_solo_stage_config(stage)
284
+ @install_chef_solo_stage_config ||= {}
285
+ @install_chef_solo_stage_config[stage] ||= true.tap do
286
+ stage_tmp_path(stage, 'config.rb').write [
287
+ "file_cache_path \"/var/cache/dapp/chef\"\n",
288
+ "cookbook_path \"#{container_stage_tmp_path(stage, 'cookbooks')}\"\n"
289
+ ].join
290
+ end
281
291
  end
282
292
 
283
293
  def container_stage_config_path(stage, *path)
284
- container_stage_build_path(stage, 'config.rb', *path)
294
+ install_chef_solo_stage_config(stage)
295
+ container_stage_tmp_path(stage, 'config.rb', *path)
296
+ end
297
+
298
+
299
+ def stage_tmp_path(stage, *path)
300
+ application.tmp_path(application.config._name, stage).join(*path)
301
+ end
302
+
303
+ def container_stage_tmp_path(_stage, *path)
304
+ path.compact.map(&:to_s).inject(Pathname.new('/chef_build'), &:+)
285
305
  end
286
306
 
287
307
  def _paths_checksum(paths)