Module: Dapp::Kube::Dapp::Command::Deploy

Included in:
Dapp
Defined in:
lib/dapp/kube/dapp/command/deploy.rb

Instance Method Summary collapse

Instance Method Details

#kube_chart_path(*path) ⇒ Object



210
211
212
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 210

def kube_chart_path(*path)
  self.path('.helm', *path).expand_path
end

#kube_chart_secret_path(*path) ⇒ Object



206
207
208
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 206

def kube_chart_secret_path(*path)
  kube_chart_path('secret', *path).expand_path
end

#kube_chart_secret_values_pathObject



202
203
204
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 202

def kube_chart_secret_values_path
  kube_chart_path('secret-values.yaml').expand_path
end

#kube_check_helm_chart!Object

Raises:



158
159
160
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 158

def kube_check_helm_chart!
  raise Error::Command, code: :project_helm_chart_not_found, data: { path: kube_chart_path } unless kube_chart_path.exist?
end

#kube_copy_chartObject



39
40
41
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 39

def kube_copy_chart
  FileUtils.cp_r("#{kube_chart_path}/.", kube_tmp_chart_path)
end

#kube_delete_job!(name) ⇒ Object



142
143
144
145
146
147
148
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 142

def kube_delete_job!(name)
  kubernetes.delete_job!(name)
  loop do
    break unless kubernetes.job?(name)
    sleep 1
  end
end

#kube_deployObject

Raises:



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 6

def kube_deploy
  raise Error::Command, code: :helm_directory_not_exist unless kube_chart_path.exist?
  kube_check_helm!
  kube_check_helm_chart!

  repo = option_repo
  image_version = options[:image_version]
  validate_repo_name!(repo)
  validate_tag_name!(image_version)

  begin
    kube_copy_chart
    kube_helm_decode_secrets
    kube_generate_helm_chart_tpl

    additional_values = [].tap do |options|
      options.concat((kube_values_paths + kube_tmp_chart_secret_values_paths).map { |p| "--values #{p}" })
    end

    set_options = [].tap do |options|
      options << "--set global.dapp.repo=#{repo}"
      options << "--set global.dapp.image_version=#{image_version}"
      options << "--set global.namespace=#{kube_namespace}"
      options.concat(self.options[:helm_set_options].map { |opt| "--set #{opt}" })
    end

    kube_flush_hooks_jobs(additional_values, set_options)
    kube_run_deploy(additional_values, set_options)
  ensure
    FileUtils.rm_rf(kube_tmp_chart_path)
  end
end

#kube_flush_hooks_jobs(additional_values, set_options) ⇒ Object



108
109
110
111
112
113
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 108

def kube_flush_hooks_jobs(additional_values, set_options)
  return if (config_jobs_names = kube_helm_hooks_jobs_to_delete(additional_values, set_options).keys).empty?
  config_jobs_names.select { |name| kube_job_list.include? name }.each do |name|
    log_process("Delete hooks job `#{name}` for release #{kube_release_name} ", short: true) { kube_delete_job!(name) }
  end
end

#kube_generate_helm_chart_tplObject



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 84

def kube_generate_helm_chart_tpl
  cont = <<-EOF
{{/* vim: set filetype=mustache: */}}

{{- define "dimg" -}}
{{- if (ge (len (index .)) 2) -}}
{{- $name := index . 0 -}}                                                                          
{{- $context := index . 1 -}}  
{{- printf "%s:%s-%s" $context.Values.global.dapp.repo $name $context.Values.global.dapp.image_version -}}
{{- else -}}
{{- $context := index . 0 -}}
{{- printf "%s:%s" $context.Values.global.dapp.repo $context.Values.global.dapp.image_version -}}
{{- end -}}                                                                               
{{- end -}}                                                                                         

{{- define "dapp_secret_file" -}}
{{- $relative_file_path := index . 0 -}}
{{- $context := index . 1 -}}
{{- $context.Files.Get (print "#{kube_tmp_chart_secret_path.subpath_of(kube_tmp_chart_path)}/" $relative_file_path) -}}
{{- end -}}
  EOF
  kube_tmp_chart_path('templates/_dapp_helpers.tpl').write(cont)
end

#kube_helm_decode_json(json) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 62

def kube_helm_decode_json(json)
  decode_value = proc do |value|
    case value
    when Array then value.map { |v| decode_value.call(v) }
    when Hash then kube_helm_decode_json(value)
    else
      secret.nil? ? '' : secret.extract(value)
    end
  end
  json.each { |k, v| json[k] = decode_value.call(v) }
end

#kube_helm_decode_secret_filesObject



74
75
76
77
78
79
80
81
82
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 74

def kube_helm_decode_secret_files
  return unless kube_chart_secret_path.directory?
  Dir.glob(kube_chart_secret_path.join('**/*')).each do |entry|
    next unless File.file?(entry)
    secret_relative_path = Pathname(entry).subpath_of(kube_chart_secret_path)
    secret_data = secret.extract(IO.binread(entry).chomp("\n"))
    File.open(kube_tmp_chart_secret_path(secret_relative_path), 'wb:ASCII-8BIT', 0400) {|f| f.write secret_data}
  end
end

#kube_helm_decode_secret_valuesObject



55
56
57
58
59
60
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 55

def kube_helm_decode_secret_values
  kube_secret_values_paths.each_with_index do |secret_values_file, index|
    decoded_data = kube_helm_decode_json(YAML::load(secret_values_file.read))
    kube_tmp_chart_secret_values_paths[index].write(decoded_data.to_yaml)
  end
end

#kube_helm_decode_secretsObject



43
44
45
46
47
48
49
50
51
52
53
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 43

def kube_helm_decode_secrets
  if secret.nil?
    log_warning(desc: {
      code: :dapp_secret_key_not_found,
      data: {not_found_in: secret_key_not_found_in.join(', ')}
    }) if !kube_secret_values_paths.empty? || kube_chart_secret_path.directory?
  else
    kube_helm_decode_secret_files
  end
  kube_helm_decode_secret_values
end

#kube_helm_extra_options(dry_run: dry_run?) ) ⇒ Object



162
163
164
165
166
167
168
169
170
171
172
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 162

def kube_helm_extra_options(dry_run: dry_run?)
  [].tap do |options|
    options << "--namespace #{kube_namespace}"
    options << '--install'
    options << '--wait'
    options << '--timeout 1800'

    options << '--dry-run' if dry_run
    options << '--debug'   if dry_run || log_verbose?
  end
end

#kube_helm_hooks_jobs_to_delete(additional_values, set_options) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 115

def kube_helm_hooks_jobs_to_delete(additional_values, set_options)
  generator = proc do |text|
    text.split(/# Source.*|---/).reject {|c| c.strip.empty? }.map {|c| YAML::load(c) }.reduce({}) do |objects, c|
      objects[c['kind']] ||= {}
      objects[c['kind']][(c['metadata'] || {})['name']] = c
      objects
    end
  end

  args = [kube_release_name, kube_tmp_chart_path, additional_values, set_options, kube_helm_extra_options(dry_run: true)].flatten
  output = shellout!("helm upgrade #{args.join(' ')}").stdout

  manifest_start_index = output.lines.index("MANIFEST:\n") + 1
  hook_start_index     = output.lines.index("HOOKS:\n") + 1
  configs = generator.call(output.lines[hook_start_index..manifest_start_index-1].join)

  (configs['Job'] || {}).reject do |_, c|
    c['metadata'] ||= {}
    c['metadata']['annotations'] ||= {}
    c['metadata']['annotations']['helm.sh/resource-policy'] == 'keep'
  end
end

#kube_job_listObject



138
139
140
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 138

def kube_job_list
  kubernetes.job_list['items'].map { |i| i['metadata']['name'] }
end

#kube_run_deploy(additional_values, set_options) ⇒ Object



150
151
152
153
154
155
156
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 150

def kube_run_deploy(additional_values, set_options)
  log_process("Deploy release #{kube_release_name}") do
    args = [kube_release_name, kube_tmp_chart_path, additional_values, set_options, kube_helm_extra_options].flatten
    kubernetes.create_namespace!(kube_namespace) unless kubernetes.namespace?(kube_namespace)
    shellout! "helm upgrade #{args.join(' ')}", verbose: true
  end
end

#kube_secret_values_pathsObject



193
194
195
196
197
198
199
200
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 193

def kube_secret_values_paths
  @kube_chart_secret_values_files ||= [].tap do |files|
    files << kube_chart_secret_values_path if kube_chart_secret_values_path.file?
    files.concat(options[:helm_secret_values_options].map { |p| Pathname(p).expand_path }.each do |f|
      raise Error::Command, code: :secret_values_file_not_found, data: { path: f } unless f.file?
    end)
  end
end

#kube_tmp_chart_path(*path) ⇒ Object



178
179
180
181
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 178

def kube_tmp_chart_path(*path)
  @kube_tmp_path ||= Dir.mktmpdir('dapp-helm-chart-', tmp_base_dir)
  make_path(@kube_tmp_path, *path).expand_path.tap { |p| p.parent.mkpath }
end

#kube_tmp_chart_secret_path(*path) ⇒ Object



174
175
176
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 174

def kube_tmp_chart_secret_path(*path)
  kube_tmp_chart_path('decoded-secret', *path).tap { |p| p.parent.mkpath }
end

#kube_tmp_chart_secret_values_pathsObject



189
190
191
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 189

def kube_tmp_chart_secret_values_paths
  @kube_tmp_chart_secret_values_paths ||= kube_secret_values_paths.map { |f| kube_tmp_chart_path("#{SecureRandom.uuid}-#{f.basename}") }
end

#kube_values_pathsObject



183
184
185
186
187
# File 'lib/dapp/kube/dapp/command/deploy.rb', line 183

def kube_values_paths
  self.options[:helm_values_options].map { |p| Pathname(p).expand_path }.each do |f|
    raise Error::Command, code: :values_file_not_found, data: { path: f } unless f.file?
  end
end