Class: Kontena::Cli::Stacks::YAML::Reader
- Inherits:
-
Object
- Object
- Kontena::Cli::Stacks::YAML::Reader
show all
- Includes:
- Common, Util
- Defined in:
- lib/kontena/cli/stacks/yaml/reader.rb
Instance Attribute Summary collapse
Instance Method Summary
collapse
Methods included from Common
#access_token=, #add_master, #any_key_to_continue, #any_key_to_continue_with_timeout, #api_url, #api_url=, #clear_current_grid, #client, #cloud_auth?, #cloud_client, #config, #confirm, #confirm_command, #current_grid, #current_master_index, #display_account_login_info, #display_login_info, display_logo, #display_master_login_info, #error, exit_with_error, #kontena_account, #logger, #pastel, #print, #prompt, #puts, #require_api_url, #require_token, #reset_client, #reset_cloud_client, #running_quiet?, #running_silent?, #running_verbose?, #spin_if, #spinner, #sprint, #sputs, #stdin_input, #use_refresh_token, #vfakespinner, #vputs, #vspinner, #warning
Methods included from Util
included, #longest_string_in_array, #safe_dig, #seconds_to_human, symbolize_keys, symbolize_keys!, #time_ago, #time_until, which
Constructor Details
#initialize(file, skip_validation: false, skip_variables: false, variables: nil, values: nil, defaults: nil) ⇒ Reader
Returns a new instance of Reader.
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 27
def initialize(file, skip_validation: false, skip_variables: false, variables: nil, values: nil, defaults: nil)
require_relative 'service_extender'
require_relative 'validator_v3'
require_relative 'opto'
require 'liquid'
@file = file
if from_registry?
require 'shellwords'
@raw_content = Kontena::StacksCache.pull(file)
@registry = current_account.stacks_url
elsif from_url?
@raw_content = load_from_url(file)
@registry = 'file://'
else
@raw_content = File.read(File.expand_path(file))
@registry = 'file://'
end
@errors = []
@notifications = []
@skip_validation = skip_validation
@skip_variables = skip_variables
@variables = variables
@values = values
@defaults = defaults
end
|
Instance Attribute Details
#defaults ⇒ Object
Returns the value of attribute defaults.
25
26
27
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 25
def defaults
@defaults
end
|
#errors ⇒ Object
Returns the value of attribute errors.
25
26
27
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 25
def errors
@errors
end
|
#file ⇒ Object
Returns the value of attribute file.
25
26
27
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 25
def file
@file
end
|
#notifications ⇒ Object
Returns the value of attribute notifications.
25
26
27
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 25
def notifications
@notifications
end
|
#raw_content ⇒ Object
Returns the value of attribute raw_content.
25
26
27
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 25
def raw_content
@raw_content
end
|
#registry ⇒ Object
Returns the value of attribute registry.
25
26
27
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 25
def registry
@registry
end
|
#values ⇒ Object
Returns the value of attribute values.
25
26
27
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 25
def values
@values
end
|
Instance Method Details
#execute(service_name = nil) ⇒ Hash
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 131
def execute(service_name = nil)
process_variables unless skip_variables?
validate unless skip_validation?
result = {}
Dir.chdir(from_file? ? File.dirname(File.expand_path(file)) : Dir.pwd) do
result[:stack] = raw_yaml['stack']
result[:version] = self.stack_version
result[:name] = self.stack_name
result[:registry] = registry
result[:expose] = fully_interpolated_yaml['expose']
result[:errors] = errors unless skip_validation?
result[:notifications] = notifications
result[:services] = errors.count.zero? ? parse_services(service_name) : {}
unless skip_variables?
result[:variables] = variables.to_h(values_only: true).reject do |k,_|
k == 'GRID' || k == 'STACK' || variables.option(k).to.has_key?(:vault) || variables.option(k).from.has_key?(:vault)
end
end
result[:volumes] = errors.count.zero? ? parse_volumes : {}
end
result
end
|
#from_external_file(filename, service_name) ⇒ Object
294
295
296
297
298
299
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 294
def from_external_file(filename, service_name)
outcome = Reader.new(filename, skip_validation: skip_validation?, skip_variables: true, variables: variables, defaults: defaults, values: values).execute(service_name)
errors.concat outcome[:errors] unless errors.any? { |item| item.has_key?(filename) }
notifications.concat outcome[:notifications] unless notifications.any? { |item| item.has_key?(filename) }
outcome[:services]
end
|
#from_file? ⇒ Boolean
203
204
205
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 203
def from_file?
!from_registry? && !from_url?
end
|
#from_registry? ⇒ Boolean
195
196
197
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 195
def from_registry?
file =~ /\A[a-zA-Z0-9\_\.\-]+\/[a-zA-Z0-9\_\.\-]+(?::.*)?\z/ && !File.exist?(file)
end
|
#from_url? ⇒ Boolean
199
200
201
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 199
def from_url?
file =~ /\A(?:http|https|ftp):\/\//
end
|
#fully_interpolated_yaml ⇒ Object
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 80
def fully_interpolated_yaml
return @fully_interpolated_yaml if @fully_interpolated_yaml
vars = variables.to_h(values_only: true)
@fully_interpolated_yaml = ::YAML.safe_load(
replace_dollar_dollars(
interpolate(
interpolate_liquid(
raw_content,
vars
),
use_opto: true,
raise_on_unknown: true
)
)
) || {}
rescue Psych::SyntaxError => ex
raise ex, "Error while parsing #{file} : #{ex.message}"
end
|
#internals_interpolated_yaml ⇒ Object
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 62
def internals_interpolated_yaml
@internals_interpolated_yaml ||= ::YAML.safe_load(
replace_dollar_dollars(
interpolate(
raw_content,
use_opto: false,
substitutions: {
'GRID' => env['GRID'],
'STACK' => env['STACK']
},
warnings: false
)
)
) || {}
rescue Psych::SyntaxError => ex
raise ex, "Error while parsing #{file} : #{ex.message}"
end
|
#interpolate_liquid(content, vars) ⇒ Object
162
163
164
165
166
167
168
169
170
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 162
def interpolate_liquid(content, vars)
Liquid::Template.error_mode = :strict
template = Liquid::Template.parse(content)
vars = vars.map {|key, value| [key, value.nil? ? LiquidNull.new : value]}.to_h
template.render!(vars, strict_variables: true, strict_filters: true)
end
|
#load_from_url(url) ⇒ Object
56
57
58
59
60
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 56
def load_from_url(url)
require 'open-uri'
stream = open(url)
stream.read
end
|
#parse_services(service_name = nil) ⇒ Hash
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 228
def parse_services(service_name = nil)
if service_name.nil?
services.each do |name, config|
services[name] = process_config(config)
if process_hash?(config)
services[name].delete('only_if')
services[name].delete('skip_if')
else
services.delete(name)
end
end
services
else
raise ("Service '#{service_name}' not found in #{file}") unless services.has_key?(service_name)
process_config(services[service_name])
end
end
|
#parse_volumes ⇒ Object
212
213
214
215
216
217
218
219
220
221
222
223
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 212
def parse_volumes
volumes.each do |name, config|
if process_hash?(config)
volumes[name].delete('only_if')
volumes[name].delete('skip_if')
volumes[name] = process_volume(config)
else
volumes.delete(name)
end
end
volumes
end
|
#process_config(service_config) ⇒ Object
269
270
271
272
273
274
275
276
277
278
279
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 269
def process_config(service_config)
normalize_env_vars(service_config)
merge_env_vars(service_config)
expand_build_context(service_config)
normalize_build_args(service_config)
if service_config.has_key?('extends')
service_config = extend_config(service_config)
service_config.delete('extends')
end
service_config
end
|
#process_hash?(hash) ⇒ Boolean
If the supplied hash contains skip_if/only_if conditionals, process that conditional and return true/false
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 250
def process_hash?(hash)
return true unless hash['skip_if'] || hash['only_if']
return true if skip_variables? || variables.empty?
skip_lambdas = normalize_ifs(hash['skip_if'])
only_lambdas = normalize_ifs(hash['only_if'])
if skip_lambdas
return false if skip_lambdas.any? { |s| s.call }
end
if only_lambdas
return false unless only_lambdas.all? { |s| s.call }
end
true
end
|
#process_variables ⇒ Object
156
157
158
159
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 156
def process_variables
variables.run
raise RuntimeError, "Variable validation failed: #{variables.errors.inspect}" unless variables.valid?
end
|
#process_volume(volume_config) ⇒ Object
281
282
283
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 281
def process_volume(volume_config)
volume_config
end
|
#raw_yaml ⇒ Object
99
100
101
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 99
def raw_yaml
@raw_yaml ||= ::YAML.safe_load(raw_content) || {}
end
|
#services ⇒ Hash
Returns - services from YAML file.
290
291
292
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 290
def services
@services ||= fully_interpolated_yaml['services'] || {}
end
|
#skip_validation? ⇒ Boolean
187
188
189
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 187
def skip_validation?
!!@skip_validation
end
|
#skip_variables? ⇒ Boolean
191
192
193
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 191
def skip_variables?
!!@skip_variables
end
|
#stack_name ⇒ Object
172
173
174
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 172
def stack_name
@stack_name ||= parse_stack_name(raw_yaml['stack'].to_s)[:stack]
end
|
#stack_version ⇒ Object
176
177
178
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 176
def stack_version
@stack_version ||= raw_yaml['version'] || parse_stack_name(raw_yaml['stack'].to_s)[:version] || '0.0.1'
end
|
#validate ⇒ Array
Returns array of validation errors.
181
182
183
184
185
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 181
def validate
result = validator.validate(fully_interpolated_yaml)
store_failures(result)
result
end
|
208
209
210
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 208
def validator
@validator ||= YAML::ValidatorV3.new
end
|
#variables ⇒ Opto::Group
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 104
def variables
return @variables if @variables
@variables = ::Opto::Group.new(
(internals_interpolated_yaml['variables'] || {}).merge('STACK' => { type: :string, value: env['STACK']}, 'GRID' => {type: :string, value: env['GRID']}),
defaults: {
from: :env,
to: :env
}
)
if defaults
defaults.each do |key, val|
var = @variables.option(key)
var.default = val if var
end
end
if values
values.each do |key, val|
var = @variables.option(key)
var.set(val) if var
end
end
@variables
end
|
#volumes ⇒ Object
285
286
287
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 285
def volumes
@volumes ||= fully_interpolated_yaml['volumes'] || {}
end
|