dapp 0.24.12 → 0.25.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6cd3ff0c4bceec9cdd276f5fe5ad81ebf540ff88
4
- data.tar.gz: 0757dc0b74af4c3acebfe2143c236e1fb0470f2b
3
+ metadata.gz: 9feef0467f4a300a3890d8c35fca220590a9fd19
4
+ data.tar.gz: eb7cb2377a0dd260976a6bbfd08c51cf50e4c4bf
5
5
  SHA512:
6
- metadata.gz: d3cf61182dba6fdd9c610b5de68fa379c0c58dfc859936751c4744852fe7961ebff2a5d61c1ea9362fe244fd45de04e2e09becada2b5c64aa6efae9477c3681f
7
- data.tar.gz: f0e10a6ff4126492b75cc7806bc9cb5c4667cf47a6f7b608e4906ab4b92dd25e40fd6cda72449955c98e4ab289cec7455ecc79a31cc024b26686eb24ca34ddbd
6
+ metadata.gz: 0050bb050988788005d6af8dd2432ca5b3e9b02dd6f5fbd3203deab1adc36253f0d460ab31bac8c3ba17229a21c00ba1c6c180202496ff76a3e030cb665b360c
7
+ data.tar.gz: 19cc26da6da554416efa0969d0ccc88e061578cbd8b4147cf6af785eba4169555d7f10ec73fb85ee2a729c12d2795e793e1f6b86bb36d1900ec9154e7b94c23d
data/bin/dapp CHANGED
@@ -28,10 +28,6 @@ begin
28
28
  $stderr.puts "\033[1m\033[90mStacktrace dumped to #{filename}\033[0m"
29
29
  end
30
30
 
31
- if Dapp::CLI.dapp_object
32
- Dapp::CLI.dapp_object.sentry_exception(e)
33
- end
34
-
35
31
  raise
36
32
  end
37
33
  rescue Dapp::Error::Shellout => e
data/lib/dapp.rb CHANGED
@@ -26,8 +26,6 @@ require 'zlib'
26
26
  require 'slugify'
27
27
  require 'base64'
28
28
  require 'io/console'
29
- require 'sentry-raven'
30
- require 'toml-rb'
31
29
 
32
30
  require 'dapp/version'
33
31
  require 'dapp/core_ext/hash'
@@ -38,7 +36,6 @@ require 'dapp/helper/sha256'
38
36
  require 'dapp/helper/net_status'
39
37
  require 'dapp/helper/tar'
40
38
  require 'dapp/helper/yaml'
41
- require 'dapp/helper/url'
42
39
  require 'dapp/prctl'
43
40
  require 'dapp/error/mod/user'
44
41
  require 'dapp/error/base'
@@ -59,7 +56,6 @@ require 'dapp/config/directive/base'
59
56
  require 'dapp/config/config'
60
57
  require 'dapp/dapp/lock'
61
58
  require 'dapp/dapp/ssh_agent'
62
- require 'dapp/dapp/sentry'
63
59
  require 'dapp/dapp/git_artifact'
64
60
  require 'dapp/dapp/dappfile'
65
61
  require 'dapp/dapp/chef'
data/lib/dapp/cli.rb CHANGED
@@ -5,7 +5,7 @@ module Dapp
5
5
  extend Helper::Cli
6
6
  include Helper::Trivia
7
7
 
8
- SUBCOMMANDS = ['dimg', 'kube', 'update', 'slug'].freeze
8
+ SUBCOMMANDS = ['dimg', 'deployment', 'kube', 'update', 'slug'].freeze
9
9
 
10
10
  banner <<BANNER.freeze
11
11
  Usage: dapp subcommand [subcommand options]
@@ -13,6 +13,7 @@ Usage: dapp subcommand [subcommand options]
13
13
  Available subcommands: (for details, dapp SUB-COMMAND --help)
14
14
 
15
15
  dapp dimg
16
+ dapp deployment
16
17
  dapp kube
17
18
  dapp update
18
19
  dapp slug STRING
@@ -37,10 +38,6 @@ BANNER
37
38
  show_options: true,
38
39
  exit: 0
39
40
 
40
- class << self
41
- attr_accessor :dapp_object
42
- end
43
-
44
41
  def initialize(*args)
45
42
  super(*args)
46
43
 
@@ -58,8 +58,6 @@ module Dapp
58
58
 
59
59
  def run_dapp_command(run_method, options: {}, log_running_time: true, try_host_docker_login: false)
60
60
  dapp = ::Dapp::Dapp.new(options: options)
61
- ::Dapp::CLI.dapp_object = dapp
62
- dapp.sentry_message("Manual usage: `#{options[:dapp_command]}` command") unless ENV['CI']
63
61
 
64
62
  log_dapp_running_time(dapp, ignore: !log_running_time) do
65
63
  begin
@@ -76,10 +74,6 @@ module Dapp
76
74
  end
77
75
  end
78
76
 
79
- def run_method
80
- class_to_lowercase
81
- end
82
-
83
77
  def log_dapp_running_time(dapp, ignore: false)
84
78
  return yield if ignore
85
79
 
@@ -101,7 +95,7 @@ module Dapp
101
95
  self.class.print_error_with_help_and_die! self, "cannot use alias options --run-dir, --build-dir, --deploy-dir at the same time"
102
96
  end
103
97
 
104
- config.merge(build_dir: dirs.compact.first, dapp_command: run_method, **kwargs)
98
+ config.merge(build_dir: dirs.compact.first, **kwargs)
105
99
  end
106
100
  end
107
101
  end
data/lib/dapp/dapp.rb CHANGED
@@ -17,13 +17,10 @@ module Dapp
17
17
  include Logging::Paint
18
18
 
19
19
  include SshAgent
20
- include Sentry
21
-
22
20
  include Helper::Sha256
23
- extend Helper::Trivia
21
+ extend Helper::Trivia
24
22
  include Helper::Trivia
25
23
  include Helper::Tar
26
- include Helper::Url
27
24
 
28
25
  include Deps::Toolchain
29
26
  include Deps::Gitartifact
@@ -46,18 +43,6 @@ module Dapp
46
43
  self.class.options
47
44
  end
48
45
 
49
- def settings
50
- @settings ||= begin
51
- settings_path = File.join(self.class.home_dir, "settings.toml")
52
-
53
- if File.exists? settings_path
54
- TomlRB.load_file(settings_path)
55
- else
56
- {}
57
- end
58
- end
59
- end
60
-
61
46
  def name
62
47
  @name ||= begin
63
48
  n = begin
@@ -107,8 +92,8 @@ module Dapp
107
92
  self.class.tmp_base_dir
108
93
  end
109
94
 
110
- def build_dir
111
- @build_dir ||= begin
95
+ def build_path(*path)
96
+ @build_path ||= begin
112
97
  if option_build_dir
113
98
  Pathname.new(option_build_dir)
114
99
  else
@@ -116,10 +101,7 @@ module Dapp
116
101
  Pathname.new(dir)
117
102
  end.expand_path.tap(&:mkpath)
118
103
  end
119
- end
120
-
121
- def build_path(*path)
122
- make_path(build_dir, *path)
104
+ make_path(@build_path, *path)
123
105
  end
124
106
 
125
107
  def local_git_artifact_exclude_paths(&blk)
@@ -7,12 +7,6 @@ module Dapp
7
7
 
8
8
  def tags_by_scheme
9
9
  @tags_by_scheme_name ||= begin
10
- if simple_tags[:custom].any?
11
- if settings.fetch("sentry", {}).fetch("detect-push-tag-usage", false)
12
- sentry_message("--tag or --tag-slug usage detected", extra: {"slug_tags" => simple_tags})
13
- end
14
- end
15
-
16
10
  [simple_tags, branch_tags, commit_tags, build_tags, ci_tags].reduce({}) do |some_tags_by_scheme, tags_by_scheme|
17
11
  tags_by_scheme.in_depth_merge(some_tags_by_scheme)
18
12
  end.tap do |tags_by_scheme|
@@ -189,10 +189,8 @@ module Dapp
189
189
  commits[git_artifact] ||= begin
190
190
  if image.built?
191
191
  image.labels[dimg.dapp.dimgstage_g_a_commit_label(git_artifact.paramshash)]
192
- elsif g_a_stage? && !empty?
192
+ else
193
193
  git_artifact.latest_commit
194
- elsif prev_stage
195
- prev_stage.layer_commit(git_artifact)
196
194
  end
197
195
  end
198
196
  end
@@ -10,7 +10,7 @@ module Dapp
10
10
  image.add_volume "#{dimg.tmp_path('patches')}:#{dimg.container_tmp_path('patches')}:ro"
11
11
 
12
12
  dimg.git_artifacts.each do |git_artifact|
13
- image.add_service_change_label(dimg.dapp.dimgstage_g_a_commit_label(git_artifact.paramshash).to_sym => layer_commit(git_artifact))
13
+ image.add_service_change_label(dimg.dapp.dimgstage_g_a_commit_label(git_artifact.paramshash).to_sym => git_artifact.latest_commit)
14
14
  image.add_command git_artifact.send(apply_command_method, self)
15
15
  end
16
16
  end
@@ -28,9 +28,7 @@ module Dapp
28
28
  private
29
29
 
30
30
  def commit_list
31
- dimg.git_artifacts
32
- .select { |ga| ga.repo.commit_exists?(prev_stage.layer_commit(ga)) && ga.patch_any_changes?(self) }
33
- .map(&method(:layer_commit))
31
+ dimg.git_artifacts.map { |git_artifact| layer_commit(git_artifact) }
34
32
  end
35
33
 
36
34
  def git_artifacts_dev_patch_hashes
@@ -9,6 +9,10 @@ module Dapp::Dimg::CLI
9
9
  self.class.parse_options(self, argv)
10
10
  run_dapp_command(run_method, options: cli_options(dimgs_patterns: cli_arguments))
11
11
  end
12
+
13
+ def run_method
14
+ class_to_lowercase
15
+ end
12
16
  end
13
17
  end
14
18
  end
@@ -22,6 +22,18 @@ BANNER
22
22
  :g_a_pre_setup_patch, :setup, :after_setup_artifact, :g_a_artifact_patch, :build_artifact
23
23
  ]
24
24
 
25
+ introspect_stage_proc = proc do |stages|
26
+ proc { |val| val.to_sym.tap { |v| in_validate!(v, stages) } }
27
+ end
28
+
29
+ introspect_before_proc = proc do |stages|
30
+ proc do |val|
31
+ val_sym = val.to_sym
32
+ introspect_stage_proc.call(stages[1..-1]).call(val_sym)
33
+ stages[stages.index(val_sym) - 1]
34
+ end
35
+ end
36
+
25
37
  option :tmp_dir_prefix,
26
38
  long: '--tmp-dir-prefix PREFIX',
27
39
  description: 'Tmp directory prefix (/tmp by default). Used for build process service directories.'
@@ -48,12 +60,22 @@ BANNER
48
60
  option :introspect_stage,
49
61
  long: '--introspect-stage STAGE',
50
62
  description: "Introspect one of the following stages (#{list_msg_format(introspected_stages)})",
51
- proc: proc { |val| val.to_sym.tap { |v| in_validate!(v, introspected_stages) } }
63
+ proc: introspect_stage_proc.call(introspected_stages)
64
+
65
+ option :introspect_before,
66
+ long: '--introspect-before STAGE',
67
+ description: "Introspect stage before one of the following stages (#{list_msg_format(introspected_stages[1..-1])})",
68
+ proc: introspect_before_proc.call(introspected_stages)
52
69
 
53
70
  option :introspect_artifact_stage,
54
71
  long: '--introspect-artifact-stage STAGE',
55
72
  description: "Introspect one of the following stages (#{list_msg_format(artifact_introspected_stages)})",
56
- proc: proc { |val| val.to_sym.tap { |v| in_validate!(v, artifact_introspected_stages) } }
73
+ proc: introspect_stage_proc.call(artifact_introspected_stages)
74
+
75
+ option :introspect_artifact_before,
76
+ long: '--introspect-artifact-before STAGE',
77
+ description: "Introspect stage before one of the following stages (#{list_msg_format(artifact_introspected_stages[1..-1])})",
78
+ proc: introspect_before_proc.call(artifact_introspected_stages)
57
79
 
58
80
  option :ssh_key,
59
81
  long: '--ssh-key SSH_KEY',
@@ -75,6 +97,13 @@ BANNER
75
97
  long: '--force-save-cache',
76
98
  boolean: true,
77
99
  default: false
100
+
101
+ def cli_options(**kwargs)
102
+ super.tap do |config|
103
+ config[:introspect_stage] ||= config[:introspect_before]
104
+ config[:introspect_artifact_stage] ||= config[:introspect_artifact_before]
105
+ end
106
+ end
78
107
  end
79
108
  end
80
109
  end
@@ -4,8 +4,6 @@ module Dapp
4
4
  module Directive
5
5
  class Dimg < Base
6
6
  module Validation
7
- include Helper::Trivia
8
-
9
7
  def validate!
10
8
  directives_validate!
11
9
  validate_scratch!
@@ -140,13 +138,29 @@ module Dapp
140
138
  end
141
139
 
142
140
  def validate_artifact!(verifiable_artifact, artifact)
143
- cases = []
144
- cases << verifiable_artifact[:include_paths].any? do |verifiable_path|
145
- !ignore_path?(verifiable_path, paths: artifact[:include_paths], exclude_paths: artifact[:exclude_paths])
141
+ verifiable_artifact[:include_paths].each do |verifiable_path|
142
+ potential_conflicts = artifact[:include_paths].select { |path| path.start_with?(verifiable_path) }
143
+ validate_artifact_path!(verifiable_artifact, potential_conflicts)
144
+ end
145
+
146
+ if verifiable_artifact[:include_paths].empty?
147
+ if artifact[:include_paths].empty? || verifiable_artifact[:exclude_paths].empty?
148
+ raise ::Dapp::Error::Config, code: :artifact_conflict
149
+ else
150
+ validate_artifact_path!(verifiable_artifact, artifact[:include_paths])
151
+ end
146
152
  end
147
- cases << (verifiable_artifact[:include_paths].empty? && artifact[:include_paths].empty?)
153
+ end
148
154
 
149
- raise ::Dapp::Error::Config, code: :artifact_conflict if cases.any?
155
+ def validate_artifact_path!(verifiable_artifact, potential_conflicts)
156
+ raise ::Dapp::Error::Config, code: :artifact_conflict unless begin
157
+ potential_conflicts.all? do |path|
158
+ loop do
159
+ break if verifiable_artifact[:exclude_paths].include?(path) || ((path = File.dirname(path)) == '.')
160
+ end
161
+ verifiable_artifact[:exclude_paths].include?(path)
162
+ end
163
+ end
150
164
  end
151
165
 
152
166
  def _associated_artifacts
@@ -3,13 +3,14 @@ module Dapp
3
3
  module Config
4
4
  module Directive
5
5
  class GitArtifactRemote < GitArtifactLocal
6
- include ::Dapp::Helper::Url
7
-
8
6
  attr_reader :_url, :_name, :_branch, :_commit
9
7
 
10
8
  def initialize(url, **kwargs, &blk)
11
9
  @_url = url
12
- @_name = git_url_to_name(url)
10
+
11
+ url_without_scheme = url.split("://", 2).last
12
+ url_without_creds = url_without_scheme.split(":", 2).last
13
+ @_name = url_without_creds.gsub(%r{.*?([^\/ ]+\/[^\/ ]+)\.git}, '\\1')
13
14
 
14
15
  super(**kwargs, &blk)
15
16
  end
@@ -189,8 +189,6 @@ module Dapp
189
189
  end
190
190
 
191
191
  def cleanup_tmp
192
- return unless tmp_dir_exists?
193
-
194
192
  # В tmp-директории могли остаться файлы, владельцами которых мы не являемся.
195
193
  # Такие файлы могут попасть туда при экспорте файлов артефакта.
196
194
  # Чтобы от них избавиться — запускаем docker-контейнер под root-пользователем
@@ -6,10 +6,6 @@ module Dapp
6
6
  dapp.path(*path).expand_path
7
7
  end
8
8
 
9
- def tmp_dir_exists?
10
- @tmp_path != nil
11
- end
12
-
13
9
  def tmp_path(*path)
14
10
  @tmp_path ||= Dir.mktmpdir('dapp-', dapp.tmp_base_dir)
15
11
  make_path(@tmp_path, *path).expand_path.tap { |p| p.parent.mkpath }
@@ -35,6 +35,7 @@ module Dapp
35
35
  end
36
36
 
37
37
  def image_delete(tag)
38
+ image_blobs(tag).each { |hash| blob_delete(hash.values.first) }
38
39
  api_request(repo_suffix, "/manifests/#{image_digest(tag)}",
39
40
  method: :delete,
40
41
  expects: [202, 404],
@@ -53,6 +54,10 @@ module Dapp
53
54
  headers: { Accept: 'application/vnd.docker.distribution.manifest.v2+json' }).headers['Docker-Content-Digest']
54
55
  end
55
56
 
57
+ def image_blobs(tag)
58
+ manifest_v1(tag)['fsLayers']
59
+ end
60
+
56
61
  def manifest_v1(tag)
57
62
  api_request(repo_suffix, "/manifests/#{tag}")
58
63
  end
@@ -62,6 +67,11 @@ module Dapp
62
67
  headers: { Accept: 'application/vnd.docker.distribution.manifest.v2+json' })
63
68
  end
64
69
 
70
+ def blob_delete(id)
71
+ api_request(repo_suffix, "/blobs/#{id}",
72
+ method: :delete, expects: [202, 404])
73
+ end
74
+
65
75
  def api_request(*uri, **options)
66
76
  JSON.load(raw_api_request(*uri, **options).body)
67
77
  end
@@ -121,7 +121,7 @@ module Dapp
121
121
  last_part_path = path_parts.shift
122
122
  test_path = [test_path, last_part_path].compact.join('/')
123
123
 
124
- non_match = !File.fnmatch(test_path, embedded_rel_path, File::FNM_PATHNAME|File::FNM_DOTMATCH)
124
+ non_match = !File.fnmatch(test_path, embedded_rel_path, File::FNM_PATHNAME)
125
125
  part_for_all = (last_part_path == '**')
126
126
 
127
127
  if non_match || part_for_all
@@ -104,12 +104,12 @@ module Dapp
104
104
 
105
105
  def patches(from, to, paths: [], exclude_paths: [], **kwargs)
106
106
  diff(from, to, **kwargs).patches.select do |patch|
107
- !ignore_patch?(patch, paths: paths, exclude_paths: exclude_paths)
107
+ ignore_patch?(patch, paths: paths, exclude_paths: exclude_paths)
108
108
  end
109
109
  end
110
110
 
111
111
  def ignore_patch?(patch, paths: [], exclude_paths: [])
112
- ignore_path?(patch.delta.new_file[:path], paths: paths, exclude_paths: exclude_paths)
112
+ !ignore_path?(patch.delta.new_file[:path], paths: paths, exclude_paths: exclude_paths)
113
113
  end
114
114
 
115
115
  def entries(commit, paths: [], exclude_paths: [])
@@ -227,6 +227,22 @@ module Dapp
227
227
  paths.empty? || paths.any? { |p| check_path?(path, p) || check_subpath?(path, p) }
228
228
  end
229
229
  end
230
+
231
+ def ignore_path?(path, paths: [], exclude_paths: [])
232
+ ignore_path_base(path, exclude_paths: exclude_paths) do
233
+ paths.empty? ||
234
+ paths.any? do |p|
235
+ File.fnmatch?(p, path, File::FNM_PATHNAME) ||
236
+ File.fnmatch?(File.join(p, '**', '*'), path, File::FNM_PATHNAME)
237
+ end
238
+ end
239
+ end
240
+
241
+ def ignore_path_base(path, exclude_paths: [])
242
+ is_exclude_path = exclude_paths.any? { |p| check_path?(path, p) }
243
+ is_include_path = yield
244
+ is_exclude_path || !is_include_path
245
+ end
230
246
  end
231
247
  end
232
248
  end
@@ -48,9 +48,9 @@ module Dapp
48
48
  delta_new_file = patch.delta.new_file
49
49
  args = [delta_new_file[:path], paths: paths, exclude_paths: exclude_paths]
50
50
  if nested_git_repository_mode?(delta_new_file[:mode])
51
- ignore_directory?(*args)
51
+ !ignore_directory?(*args)
52
52
  else
53
- ignore_path?(*args)
53
+ !ignore_path?(*args)
54
54
  end
55
55
  end
56
56
 
@@ -28,28 +28,12 @@ module Dapp
28
28
  Pathname.new(File.join(base.to_s, *path.compact.map(&:to_s)))
29
29
  end
30
30
 
31
- def ignore_path?(path, paths: [], exclude_paths: [])
32
- ignore_path_base(path, exclude_paths: exclude_paths) do
33
- paths.empty? ||
34
- paths.any? do |p|
35
- File.fnmatch?(p, path, File::FNM_PATHNAME|File::FNM_DOTMATCH) ||
36
- File.fnmatch?(File.join(p, '**', '*'), path, File::FNM_PATHNAME|File::FNM_DOTMATCH)
37
- end
38
- end
39
- end
40
-
41
- def ignore_path_base(path, exclude_paths: [])
42
- is_exclude_path = exclude_paths.any? { |p| check_path?(path, p) }
43
- is_include_path = yield
44
- is_exclude_path || !is_include_path
45
- end
46
-
47
31
  def check_path?(path, format)
48
- path_checker(path) { |checking_path| File.fnmatch(format, checking_path, File::FNM_PATHNAME|File::FNM_DOTMATCH) }
32
+ path_checker(path) { |checking_path| File.fnmatch(format, checking_path, File::FNM_PATHNAME) }
49
33
  end
50
34
 
51
35
  def check_subpath?(path, format)
52
- path_checker(format) { |checking_path| File.fnmatch(checking_path, path, File::FNM_PATHNAME|File::FNM_DOTMATCH) }
36
+ path_checker(format) { |checking_path| File.fnmatch(checking_path, path, File::FNM_PATHNAME) }
53
37
  end
54
38
 
55
39
  def path_checker(path)
@@ -62,11 +62,53 @@ module Dapp
62
62
  end
63
63
  end
64
64
 
65
+ def kube_helm_auto_purge_trigger_file_path(release_name)
66
+ File.join(self.class.home_dir, "helm", release_name, "auto_purge_failed_release_on_next_deploy")
67
+ end
68
+
69
+ def kube_create_helm_auto_purge_trigger_file(release_name)
70
+ FileUtils.mkdir_p File.dirname(kube_helm_auto_purge_trigger_file_path(release_name))
71
+ FileUtils.touch kube_helm_auto_purge_trigger_file_path(release_name)
72
+ end
73
+
74
+ def kube_delete_helm_auto_purge_trigger_file(release_name)
75
+ if File.exists? kube_helm_auto_purge_trigger_file_path(release_name)
76
+ FileUtils.rm_rf kube_helm_auto_purge_trigger_file_path(release_name)
77
+ end
78
+ end
79
+
65
80
  def kube_run_deploy(release)
66
81
  log_process("Deploy release #{release.name}") do
67
- kube_flush_hooks_jobs(release)
82
+ helm_status_res = shellout("helm status #{release.name} --output json")
83
+ helm_status = {}
84
+ helm_status = JSON.load(helm_status_res.stdout) if helm_status_res.status.success?
85
+ release_exists = nil
86
+
87
+ if not helm_status_res.status.success?
88
+ # Helm release is not exists.
89
+ release_exists = false
90
+
91
+ # Create purge-trigger for the next run.
92
+ kube_create_helm_auto_purge_trigger_file(release.name)
93
+ elsif helm_status.fetch("info", {}).fetch("status", {}).fetch("code", nil) == 4
94
+ # Helm release is in FAILED state
95
+ release_exists = true
96
+
97
+ if File.exists? kube_helm_auto_purge_trigger_file_path(release.name)
98
+ log_process("Purge helm release #{release.name}") do
99
+ shellout!("helm delete --purge #{release.name}")
100
+ end
101
+
102
+ # Purge-trigger file remains to exist
103
+ release_exists = false
104
+ end
105
+ else
106
+ # Helm release is not in FAILED state
107
+ release_exists = true
108
+ kube_delete_helm_auto_purge_trigger_file(release.name)
109
+ end
68
110
 
69
- release_exists = shellout("helm status #{release.name}").status.success?
111
+ kube_flush_hooks_jobs(release)
70
112
 
71
113
  watch_hooks_by_type = release.jobs.values
72
114
  .reduce({}) do |res, job|
@@ -116,7 +158,6 @@ module Dapp
116
158
  # Поэтому перехватываем и просто отображаем произошедшую
117
159
  # ошибку для информации пользователю без завершения работы dapp.
118
160
  $stderr.puts(::Dapp::Dapp.paint_string(::Dapp::Helper::NetStatus.message(e), :warning))
119
- sentry_exception(e, extra: {"job-spec" => job.spec})
120
161
  end
121
162
 
122
163
  end # Thread
@@ -127,18 +168,31 @@ module Dapp
127
168
 
128
169
  deployment_managers.each(&:before_deploy)
129
170
 
130
- log_process("Run helm") do
171
+ log_process("#{release_exists ? "Upgrade" : "Install"} helm release #{release.name}") do
131
172
  watch_hooks_condition_mutex.synchronize do
132
173
  deploy_has_began = true
133
174
  # Фактически гарантируется лишь вывод сообщения log_process перед выводом из потока watch_thr
134
175
  watch_hooks_condition.signal
135
176
  end
136
177
 
137
- cmd_res = release.helm_upgrade!
178
+ cmd_res = if release_exists
179
+ release.upgrade_helm_release
180
+ else
181
+ release.install_helm_release
182
+ end
138
183
 
139
184
  if cmd_res.error?
185
+ if cmd_res.stderr.end_with? "has no deployed releases\n"
186
+ log_warning "[WARN] Helm release #{release.name} is in improper state: FAILED state and there was no successful releases yet"
187
+ log_warning "[WARN] Helm release #{release.name} will be removed with `helm delete --purge` on the next run of `dapp kube deploy`"
188
+
189
+ kube_create_helm_auto_purge_trigger_file(release.name)
190
+ end
191
+
140
192
  raise ::Dapp::Error::Command, code: :kube_helm_failed, data: {output: (cmd_res.stdout + cmd_res.stderr).strip}
141
193
  else
194
+ kube_delete_helm_auto_purge_trigger_file(release.name)
195
+
142
196
  watch_hooks_thr.join if !dry_run? && watch_hooks_thr && watch_hooks_thr.alive?
143
197
  log_info((cmd_res.stdout + cmd_res.stderr).strip)
144
198
  end
@@ -13,8 +13,8 @@ module Dapp
13
13
  template_relative_path_pattern = Pathname(File.expand_path(template_path_pattern)).subpath_of(path('.helm'))
14
14
  template_relative_path_pattern ||= template_path_pattern
15
15
 
16
- File.fnmatch?(template_relative_path_pattern, template_path_without_chart_name, File::FNM_PATHNAME|File::FNM_DOTMATCH) ||
17
- File.fnmatch?(template_relative_path_pattern, template_path, File::FNM_PATHNAME|File::FNM_DOTMATCH)
16
+ File.fnmatch?(template_relative_path_pattern, template_path_without_chart_name, File::FNM_PATHNAME) ||
17
+ File.fnmatch?(template_relative_path_pattern, template_path, File::FNM_PATHNAME)
18
18
  end
19
19
  end
20
20
  else
@@ -49,15 +49,29 @@ module Dapp
49
49
  end.to_h
50
50
  end
51
51
 
52
- def helm_upgrade!
53
- args = [
54
- name, chart_path, additional_values_options,
55
- set_options, upgrade_extra_options
56
- ].flatten
52
+ def install_helm_release
53
+ unless dapp.dry_run?
54
+ dapp.kubernetes.create_namespace!(namespace) unless dapp.kubernetes.namespace?(namespace)
55
+ end
56
+
57
+ cmd = dapp.shellout([
58
+ "helm install #{chart_path}",
59
+ "--name #{name}",
60
+ *helm_additional_values_options,
61
+ *helm_set_options,
62
+ *helm_common_options,
63
+ ].join(" "))
57
64
 
58
- dapp.kubernetes.create_namespace!(namespace) unless dapp.kubernetes.namespace?(namespace)
65
+ return cmd
66
+ end
59
67
 
60
- cmd = dapp.shellout "helm upgrade #{args.join(' ')}"
68
+ def upgrade_helm_release
69
+ cmd = dapp.shellout([
70
+ "helm upgrade #{name} #{chart_path}",
71
+ *helm_additional_values_options,
72
+ *helm_set_options,
73
+ *helm_common_options
74
+ ].join(" "))
61
75
 
62
76
  return cmd
63
77
  end
@@ -93,8 +107,8 @@ module Dapp
93
107
  "helm",
94
108
  "template",
95
109
  chart_path,
96
- additional_values_options,
97
- set_options(without_registry: true),
110
+ helm_additional_values_options,
111
+ helm_set_options(without_registry: true),
98
112
  ("--namespace #{namespace}" if namespace),
99
113
  ].compact.join(" ")
100
114
 
@@ -113,7 +127,7 @@ module Dapp
113
127
  end
114
128
  end
115
129
 
116
- def additional_values_options
130
+ def helm_additional_values_options
117
131
  [].tap do |options|
118
132
  options.concat(values.map { |p| "--values #{p}" })
119
133
  end
@@ -123,7 +137,7 @@ module Dapp
123
137
  @dimg_registry ||= dapp.dimg_registry(repo)
124
138
  end
125
139
 
126
- def set_options(without_registry: false)
140
+ def helm_set_options(without_registry: false)
127
141
  [].tap do |options|
128
142
  options.concat set.map {|opt| "--set #{opt}"}
129
143
 
@@ -132,21 +146,16 @@ module Dapp
132
146
  end
133
147
  end
134
148
 
135
- def upgrade_extra_options(dry_run: nil)
149
+ def helm_common_options(dry_run: nil)
136
150
  dry_run = dapp.dry_run? if dry_run.nil?
137
151
 
138
152
  [].tap do |options|
139
153
  options << "--namespace #{namespace}" if namespace
140
- options << '--install'
141
154
  options << '--dry-run' if dry_run
142
155
  options << '--debug' if dry_run
143
156
  options << "--timeout #{deploy_timeout}" if deploy_timeout
144
157
  end
145
158
  end
146
-
147
- class << self
148
-
149
- end # << self
150
159
  end # Helm::Release
151
160
  end # Kube
152
161
  end # Dapp
data/lib/dapp/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Dapp
2
- VERSION = "0.24.12"
3
- BUILD_CACHE_VERSION = 26.2
2
+ VERSION = "0.25.0"
3
+ BUILD_CACHE_VERSION = 26
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dapp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.24.12
4
+ version: 0.25.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitry Stolyarov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-16 00:00:00.000000000 Z
11
+ date: 2018-01-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mixlib-shellout
@@ -186,34 +186,6 @@ dependencies:
186
186
  - - ">="
187
187
  - !ruby/object:Gem::Version
188
188
  version: 1.0.6
189
- - !ruby/object:Gem::Dependency
190
- name: sentry-raven
191
- requirement: !ruby/object:Gem::Requirement
192
- requirements:
193
- - - "~>"
194
- - !ruby/object:Gem::Version
195
- version: 2.7.2
196
- type: :runtime
197
- prerelease: false
198
- version_requirements: !ruby/object:Gem::Requirement
199
- requirements:
200
- - - "~>"
201
- - !ruby/object:Gem::Version
202
- version: 2.7.2
203
- - !ruby/object:Gem::Dependency
204
- name: toml-rb
205
- requirement: !ruby/object:Gem::Requirement
206
- requirements:
207
- - - "~>"
208
- - !ruby/object:Gem::Version
209
- version: 1.1.1
210
- type: :runtime
211
- prerelease: false
212
- version_requirements: !ruby/object:Gem::Requirement
213
- requirements:
214
- - - "~>"
215
- - !ruby/object:Gem::Version
216
- version: 1.1.1
217
189
  - !ruby/object:Gem::Dependency
218
190
  name: bundler
219
191
  requirement: !ruby/object:Gem::Requirement
@@ -476,7 +448,6 @@ files:
476
448
  - lib/dapp/dapp/logging/paint.rb
477
449
  - lib/dapp/dapp/logging/process.rb
478
450
  - lib/dapp/dapp/option_tags.rb
479
- - lib/dapp/dapp/sentry.rb
480
451
  - lib/dapp/dapp/shellout/base.rb
481
452
  - lib/dapp/dapp/shellout/streaming.rb
482
453
  - lib/dapp/dapp/slug.rb
@@ -678,7 +649,6 @@ files:
678
649
  - lib/dapp/helper/sha256.rb
679
650
  - lib/dapp/helper/tar.rb
680
651
  - lib/dapp/helper/trivia.rb
681
- - lib/dapp/helper/url.rb
682
652
  - lib/dapp/helper/yaml.rb
683
653
  - lib/dapp/kube.rb
684
654
  - lib/dapp/kube/cli/cli.rb
@@ -1,112 +0,0 @@
1
- module Dapp
2
- class Dapp
3
- module Sentry
4
- def sentry_message(msg, **kwargs)
5
- return if not ensure_sentry_configured
6
- kwargs[:level] ||= "info"
7
- Raven.capture_message(msg, _make_sentry_params(**kwargs))
8
- end
9
-
10
- def sentry_exception(exception, **kwargs)
11
- return if not ensure_sentry_configured
12
- (kwargs[:tags] ||= {})['error-code'] = begin
13
- net_status = exception.net_status
14
- [net_status[:context], net_status[:code]].compact.join('_')
15
- end
16
- Raven.capture_exception(exception, _make_sentry_params(**kwargs))
17
- end
18
-
19
- def ensure_sentry_configured
20
- return false unless sentry_settings = settings["sentry"]
21
-
22
- unless @sentry_settings_configured
23
- Raven.configure do |config|
24
- logger = ::Logger.new(STDOUT)
25
- logger.level = ::Logger::WARN
26
-
27
- config.logger = logger
28
- config.dsn = sentry_settings["dsn"]
29
- end
30
-
31
- @sentry_settings_configured = true
32
- end
33
-
34
- return true
35
- end
36
-
37
- def _make_sentry_params(level: nil, tags: {}, extra: {}, user: {})
38
- {
39
- level: level,
40
- tags: _sentry_tags_context.merge(tags),
41
- extra: _sentry_extra_context.merge(extra),
42
- user: _sentry_user_context.merge(user),
43
- }
44
- end
45
-
46
- def _sentry_extra_context
47
- @_sentry_extra_context ||= {
48
- "pwd" => Dir.pwd,
49
- "dapp-dir" => self.work_dir,
50
- "options" => self.options,
51
- "env-options" => {
52
- "DAPP_FORCE_SAVE_CACHE" => ENV["DAPP_FORCE_SAVE_CACHE"],
53
- "DAPP_BIN_DAPPFILE_YML" => ENV["DAPP_BIN_DAPPFILE_YML"],
54
- "ANSIBLE_ARGS" => ENV["ANSIBLE_ARGS"],
55
- "DAPP_CHEF_DEBUG" => ENV["DAPP_CHEF_DEBUG"],
56
- },
57
- }.tap {|extra|
58
- extra["ci-env"] = {"CI" => ENV["CI"]}
59
- ENV.select {|k, v| k.start_with?("CI_")}.each do |k, v|
60
- extra["ci-env"][k] = v
61
- end
62
- }
63
- end
64
-
65
- def _sentry_tags_context
66
- name = options[:name] ||
67
- @_sentry_tags_context ||= {
68
- "dapp-short-version" => ::Dapp::VERSION.split(".")[0..1].join("."),
69
- "dapp-version" => ::Dapp::VERSION,
70
- "dapp-build-cache-version" => ::Dapp::BUILD_CACHE_VERSION,
71
- "dapp-command" => self.options[:dapp_command],
72
- }.tap {|tags|
73
- git_config_path = File.join(Dir.pwd, ".git/config")
74
-
75
- tags["dapp-name"] = options[:name]
76
-
77
- if File.exists? git_config_path
78
- cfg = IniFile.load(File.join(Dir.pwd, ".git/config"))
79
- remote_origin_cfg = cfg['remote "origin"']
80
- remote_origin_url = remote_origin_cfg["url"]
81
- if remote_origin_url
82
- tags["dapp-name"] ||= begin
83
- repo_name = remote_origin_url.split('/').last
84
- repo_name = repo_name[/.*(?=\.git)/] if repo_name.end_with? '.git'
85
- repo_name
86
- end
87
-
88
- tags["git-host"] = self.get_host_from_git_url(remote_origin_url)
89
-
90
- git_name = self.git_url_to_name(remote_origin_url)
91
-
92
- tags["git-group"] = git_name.partition("/")[0]
93
- tags["git-name"] = git_name
94
- end
95
- end
96
-
97
- tags["dapp-name"] ||= File.basename(Dir.pwd)
98
-
99
- begin
100
- ver = self.class.host_docker_minor_version
101
- tags["docker-minor-version"] = ver.to_s
102
- rescue ::Exception
103
- end
104
- }
105
- end
106
-
107
- def _sentry_user_context
108
- @_sentry_user_context ||= {}
109
- end
110
- end # Sentry
111
- end # Dapp
112
- end # Dapp
@@ -1,23 +0,0 @@
1
- module Dapp
2
- module Helper
3
- module Url
4
- def git_url_to_name(url)
5
- url_without_scheme = url.split("://", 2).last
6
- # This may be broken, because "@" should delimit creds, not a ":"
7
- url_without_creds = url_without_scheme.split(":", 2).last
8
- url_without_creds.gsub(%r{.*?([^\/ ]+\/[^\/ ]+)\.git}, '\\1')
9
- end
10
-
11
- def get_host_from_git_url(url)
12
- url_without_scheme = url.split("://", 2).last
13
- url_without_creds = url_without_scheme.split("@", 2).last
14
-
15
- # Split out part after ":" in this kind of url: github.com:flant/dapp.git
16
- url_part = url_without_creds.split(":", 2).first
17
-
18
- # Split out part after first "/": github.com/flant/dapp.git
19
- url_part.split("/", 2).first
20
- end
21
- end # Url
22
- end # Helper
23
- end # Dapp