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=, #api_url_version, #ask, #clear_current_grid, #client, #cloud_auth?, #cloud_client, #config, #confirm, #confirm_command, #current_account, #current_grid, #current_grid=, #current_master, #current_master=, #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_current_account, #require_current_grid, #require_current_master, #require_token, #reset_client, #reset_cloud_client, #running_silent?, #running_verbose?, #settings, #settings_filename, #spinner, #sprint, #sputs, #stdin_input, #use_refresh_token, #vfakespinner, #vputs, #vspinner, #warning, #yes?
Methods included from Util
included, #longest_string_in_array, #safe_dig, #time_ago, 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
55
|
# 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 'yaml'
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 132
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
295
296
297
298
299
300
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 295
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
204
205
206
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 204
def from_file?
!from_registry? && !from_url?
end
|
#from_registry? ⇒ Boolean
196
197
198
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 196
def from_registry?
file =~ /\A[a-zA-Z0-9\_\.\-]+\/[a-zA-Z0-9\_\.\-]+(?::.*)?\z/ && !File.exist?(file)
end
|
#from_url? ⇒ Boolean
200
201
202
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 200
def from_url?
file =~ /\A(?:http|https|ftp):\/\//
end
|
#fully_interpolated_yaml ⇒ Object
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 81
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 63
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
163
164
165
166
167
168
169
170
171
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 163
def interpolate_liquid(content, vars)
Liquid::Template.error_mode = :strict
template = Liquid::Template.parse(content)
vars = Hash[vars.map {|key, value| [key, value.nil? ? LiquidNull.new : value]}]
template.render!(vars, strict_variables: true, strict_filters: true)
end
|
#load_from_url(url) ⇒ Object
57
58
59
60
61
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 57
def load_from_url(url)
require 'open-uri'
stream = open(url)
stream.read
end
|
#parse_services(service_name = nil) ⇒ Hash
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 229
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
213
214
215
216
217
218
219
220
221
222
223
224
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 213
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
270
271
272
273
274
275
276
277
278
279
280
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 270
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
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 251
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
157
158
159
160
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 157
def process_variables
variables.run
raise RuntimeError, "Variable validation failed: #{variables.errors.inspect}" unless variables.valid?
end
|
#process_volume(volume_config) ⇒ Object
282
283
284
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 282
def process_volume(volume_config)
volume_config
end
|
#raw_yaml ⇒ Object
100
101
102
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 100
def raw_yaml
@raw_yaml ||= ::YAML.safe_load(raw_content) || {}
end
|
#services ⇒ Hash
Returns - services from YAML file.
291
292
293
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 291
def services
@services ||= fully_interpolated_yaml['services'] || {}
end
|
#skip_validation? ⇒ Boolean
188
189
190
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 188
def skip_validation?
!!@skip_validation
end
|
#skip_variables? ⇒ Boolean
192
193
194
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 192
def skip_variables?
!!@skip_variables
end
|
#stack_name ⇒ Object
173
174
175
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 173
def stack_name
@stack_name ||= parse_stack_name(raw_yaml['stack'].to_s)[:stack]
end
|
#stack_version ⇒ Object
177
178
179
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 177
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.
182
183
184
185
186
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 182
def validate
result = validator.validate(fully_interpolated_yaml)
store_failures(result)
result
end
|
209
210
211
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 209
def validator
@validator ||= YAML::ValidatorV3.new
end
|
#variables ⇒ Opto::Group
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 105
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
286
287
288
|
# File 'lib/kontena/cli/stacks/yaml/reader.rb', line 286
def volumes
@volumes ||= fully_interpolated_yaml['volumes'] || {}
end
|