dapp 0.2.8 → 0.3.0

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