vagrant-eryph 0.1.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +79 -0
- data/lib/vagrant-eryph/actions/connect_eryph.rb +40 -0
- data/lib/vagrant-eryph/actions/create_catlet.rb +88 -0
- data/lib/vagrant-eryph/actions/destroy_catlet.rb +33 -0
- data/lib/vagrant-eryph/actions/is_created.rb +34 -0
- data/lib/vagrant-eryph/actions/is_stopped.rb +20 -0
- data/lib/vagrant-eryph/actions/message_already_created.rb +18 -0
- data/lib/vagrant-eryph/actions/message_not_created.rb +18 -0
- data/lib/vagrant-eryph/actions/message_will_not_destroy.rb +18 -0
- data/lib/vagrant-eryph/actions/prepare_cloud_init.rb +52 -0
- data/lib/vagrant-eryph/actions/read_ssh_info.rb +20 -0
- data/lib/vagrant-eryph/actions/read_state.rb +52 -0
- data/lib/vagrant-eryph/actions/start_catlet.rb +40 -0
- data/lib/vagrant-eryph/actions/stop_catlet.rb +40 -0
- data/lib/vagrant-eryph/actions.rb +210 -0
- data/lib/vagrant-eryph/command.rb +573 -0
- data/lib/vagrant-eryph/config.rb +553 -0
- data/lib/vagrant-eryph/errors.rb +61 -0
- data/lib/vagrant-eryph/helpers/cloud_init.rb +113 -0
- data/lib/vagrant-eryph/helpers/eryph_client.rb +413 -0
- data/lib/vagrant-eryph/plugin.rb +28 -0
- data/lib/vagrant-eryph/provider.rb +142 -0
- data/lib/vagrant-eryph/version.rb +7 -0
- data/lib/vagrant-eryph.rb +8 -0
- data/vagrant-eryph.gemspec +27 -0
- metadata +165 -0
@@ -0,0 +1,553 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module VagrantPlugins
|
6
|
+
module Eryph
|
7
|
+
class Config < Vagrant.plugin('2', :config)
|
8
|
+
# Eryph-specific configuration
|
9
|
+
attr_accessor :project
|
10
|
+
|
11
|
+
# Client configuration
|
12
|
+
attr_accessor :client_id
|
13
|
+
|
14
|
+
# SSL configuration
|
15
|
+
attr_accessor :ssl_verify
|
16
|
+
|
17
|
+
# Cloud-init and user setup configuration
|
18
|
+
attr_accessor :auto_config
|
19
|
+
|
20
|
+
# Hyper-V/VirtualBox compatible properties
|
21
|
+
attr_reader :cpus, :memory, :maxmemory, :vmname, :hostname
|
22
|
+
attr_reader :enable_virtualization_extensions, :enable_secure_boot
|
23
|
+
|
24
|
+
# Eryph top-level catlet properties
|
25
|
+
attr_reader :parent, :location, :environment, :store
|
26
|
+
|
27
|
+
# Complex structures (arrays/hashes)
|
28
|
+
attr_accessor :cpu_config, :memory_config, :drives, :networks
|
29
|
+
attr_accessor :catlet_name, :config_name, :auto_create_project, :configuration_name, :ssl_ca_file, :enable_winrm,
|
30
|
+
:vagrant_password, :ssh_key_injection, :fodder, :network_adapters, :capabilities, :variables
|
31
|
+
|
32
|
+
# Catlet configuration - direct hash structure
|
33
|
+
attr_accessor :catlet
|
34
|
+
|
35
|
+
def initialize
|
36
|
+
@project = UNSET_VALUE
|
37
|
+
@catlet_name = UNSET_VALUE
|
38
|
+
@config_name = UNSET_VALUE
|
39
|
+
@auto_create_project = UNSET_VALUE
|
40
|
+
|
41
|
+
@client_id = UNSET_VALUE
|
42
|
+
@configuration_name = UNSET_VALUE
|
43
|
+
|
44
|
+
@ssl_verify = UNSET_VALUE
|
45
|
+
@ssl_ca_file = UNSET_VALUE
|
46
|
+
|
47
|
+
@auto_config = UNSET_VALUE
|
48
|
+
@enable_winrm = UNSET_VALUE
|
49
|
+
@vagrant_password = UNSET_VALUE
|
50
|
+
@ssh_key_injection = UNSET_VALUE
|
51
|
+
@fodder = UNSET_VALUE
|
52
|
+
|
53
|
+
# Hyper-V/VirtualBox compatible properties
|
54
|
+
@cpus = UNSET_VALUE
|
55
|
+
@memory = UNSET_VALUE
|
56
|
+
@maxmemory = UNSET_VALUE
|
57
|
+
@vmname = UNSET_VALUE
|
58
|
+
@hostname = UNSET_VALUE
|
59
|
+
@enable_virtualization_extensions = UNSET_VALUE
|
60
|
+
@enable_secure_boot = UNSET_VALUE
|
61
|
+
|
62
|
+
# Eryph top-level properties
|
63
|
+
@parent = UNSET_VALUE
|
64
|
+
@location = UNSET_VALUE
|
65
|
+
@environment = UNSET_VALUE
|
66
|
+
@store = UNSET_VALUE
|
67
|
+
|
68
|
+
# Complex structures
|
69
|
+
@cpu_config = UNSET_VALUE
|
70
|
+
@memory_config = UNSET_VALUE
|
71
|
+
@drives = UNSET_VALUE
|
72
|
+
@networks = UNSET_VALUE
|
73
|
+
@network_adapters = UNSET_VALUE
|
74
|
+
@capabilities = UNSET_VALUE
|
75
|
+
@variables = UNSET_VALUE
|
76
|
+
|
77
|
+
# New catlet configuration
|
78
|
+
@catlet = UNSET_VALUE
|
79
|
+
|
80
|
+
# Gene references (separate from fodder)
|
81
|
+
@genes = UNSET_VALUE
|
82
|
+
end
|
83
|
+
|
84
|
+
def finalize!
|
85
|
+
@project = 'default' if @project == UNSET_VALUE
|
86
|
+
@catlet_name = nil if @catlet_name == UNSET_VALUE
|
87
|
+
@config_name = nil if @config_name == UNSET_VALUE
|
88
|
+
@auto_create_project = true if @auto_create_project == UNSET_VALUE
|
89
|
+
|
90
|
+
@client_id = nil if @client_id == UNSET_VALUE
|
91
|
+
@configuration_name = nil if @configuration_name == UNSET_VALUE
|
92
|
+
|
93
|
+
# SSL defaults - disable verification for localhost
|
94
|
+
@ssl_verify = determine_ssl_verify_default if @ssl_verify == UNSET_VALUE
|
95
|
+
@ssl_ca_file = nil if @ssl_ca_file == UNSET_VALUE
|
96
|
+
|
97
|
+
@auto_config = true if @auto_config == UNSET_VALUE
|
98
|
+
@enable_winrm = true if @enable_winrm == UNSET_VALUE
|
99
|
+
# Set auto password - will be resolved based on OS when machine context is available
|
100
|
+
@vagrant_password = :auto if @vagrant_password == UNSET_VALUE
|
101
|
+
@ssh_key_injection = :direct if @ssh_key_injection == UNSET_VALUE
|
102
|
+
@fodder = [] if @fodder == UNSET_VALUE
|
103
|
+
@genes = [] if @genes == UNSET_VALUE
|
104
|
+
|
105
|
+
# Hyper-V/VirtualBox compatible property defaults
|
106
|
+
@cpus = nil if @cpus == UNSET_VALUE
|
107
|
+
@memory = nil if @memory == UNSET_VALUE
|
108
|
+
@maxmemory = nil if @maxmemory == UNSET_VALUE
|
109
|
+
@vmname = nil if @vmname == UNSET_VALUE
|
110
|
+
@hostname = nil if @hostname == UNSET_VALUE
|
111
|
+
@enable_virtualization_extensions = nil if @enable_virtualization_extensions == UNSET_VALUE
|
112
|
+
@enable_secure_boot = nil if @enable_secure_boot == UNSET_VALUE
|
113
|
+
|
114
|
+
# Eryph property defaults
|
115
|
+
@parent = nil if @parent == UNSET_VALUE
|
116
|
+
@location = nil if @location == UNSET_VALUE
|
117
|
+
@environment = nil if @environment == UNSET_VALUE
|
118
|
+
@store = nil if @store == UNSET_VALUE
|
119
|
+
|
120
|
+
# Complex structure defaults
|
121
|
+
@cpu_config = nil if @cpu_config == UNSET_VALUE
|
122
|
+
@memory_config = nil if @memory_config == UNSET_VALUE
|
123
|
+
@drives = [] if @drives == UNSET_VALUE
|
124
|
+
@networks = [] if @networks == UNSET_VALUE
|
125
|
+
@network_adapters = [] if @network_adapters == UNSET_VALUE
|
126
|
+
@capabilities = [] if @capabilities == UNSET_VALUE
|
127
|
+
@variables = [] if @variables == UNSET_VALUE
|
128
|
+
|
129
|
+
# Initialize catlet configuration as empty hash if not set
|
130
|
+
@catlet = {} if @catlet == UNSET_VALUE
|
131
|
+
end
|
132
|
+
|
133
|
+
def validate(_machine)
|
134
|
+
errors = _detected_errors
|
135
|
+
|
136
|
+
# Validate required fields - check both catlet hash
|
137
|
+
catlet_hash = @catlet.is_a?(Hash) ? @catlet : {}
|
138
|
+
parent = catlet_hash[:parent] || catlet_hash['parent']
|
139
|
+
errors << 'parent is required (set in catlet hash)' unless parent
|
140
|
+
|
141
|
+
# Project is optional - defaults to 'default' if not specified
|
142
|
+
# No validation needed since we have a fallback
|
143
|
+
|
144
|
+
# Validate ssh_key_injection option
|
145
|
+
if @ssh_key_injection && !%i[direct variable].include?(@ssh_key_injection)
|
146
|
+
errors << 'ssh_key_injection must be :direct or :variable'
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
{ 'Eryph Provider' => errors }
|
151
|
+
end
|
152
|
+
|
153
|
+
# Helper method to determine SSL verification default
|
154
|
+
def determine_ssl_verify_default
|
155
|
+
# Default to false for localhost/development, true for remote endpoints
|
156
|
+
# This will be refined when we implement the client lookup logic
|
157
|
+
false
|
158
|
+
end
|
159
|
+
|
160
|
+
# Helper method to get the effective catlet name
|
161
|
+
def effective_catlet_name(machine)
|
162
|
+
@catlet_name || machine.config.vm.hostname || machine.name.to_s
|
163
|
+
end
|
164
|
+
|
165
|
+
# Helper method to build the effective catlet configuration
|
166
|
+
# Combines the new catlet hash with legacy individual properties for backward compatibility
|
167
|
+
def effective_catlet_configuration(machine)
|
168
|
+
# Start with the catlet hash configuration
|
169
|
+
config = @catlet.dup
|
170
|
+
|
171
|
+
# Add name and project (always required)
|
172
|
+
config[:name] = effective_catlet_name(machine)
|
173
|
+
config[:project] = @project
|
174
|
+
|
175
|
+
config
|
176
|
+
end
|
177
|
+
|
178
|
+
# Helper method to merge user fodder with auto-generated fodder
|
179
|
+
def merged_fodder(auto_generated_fodder = [])
|
180
|
+
return @fodder unless @auto_config
|
181
|
+
|
182
|
+
merged = auto_generated_fodder.dup
|
183
|
+
|
184
|
+
# Add gene fodder (convert from gene references), deduplicating by source
|
185
|
+
if @genes && @genes.any?
|
186
|
+
@genes.each do |gene_config|
|
187
|
+
# Skip duplicates based on source
|
188
|
+
unless merged.any? { |item| item[:source] == gene_config[:source] }
|
189
|
+
merged << gene_config
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# Add user-provided fodder, avoiding duplicates using composite keys
|
195
|
+
@fodder.each do |user_item|
|
196
|
+
# Build unique key based on source/name combination
|
197
|
+
user_key = if user_item[:source] && user_item[:name]
|
198
|
+
"#{user_item[:source]}:#{user_item[:name]}" # source + name
|
199
|
+
elsif user_item[:source]
|
200
|
+
user_item[:source] # source only
|
201
|
+
else
|
202
|
+
user_item[:name] # name only (local fodder)
|
203
|
+
end
|
204
|
+
|
205
|
+
# Find existing item with same key
|
206
|
+
existing_index = merged.find_index do |item|
|
207
|
+
existing_key = if item[:source] && item[:name]
|
208
|
+
"#{item[:source]}:#{item[:name]}"
|
209
|
+
elsif item[:source]
|
210
|
+
item[:source]
|
211
|
+
else
|
212
|
+
item[:name]
|
213
|
+
end
|
214
|
+
existing_key == user_key
|
215
|
+
end
|
216
|
+
|
217
|
+
if existing_index
|
218
|
+
# Replace existing item with user-provided one
|
219
|
+
merged[existing_index] = user_item
|
220
|
+
else
|
221
|
+
# Add new user item
|
222
|
+
merged << user_item
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
merged
|
227
|
+
end
|
228
|
+
|
229
|
+
# ============================================================
|
230
|
+
# HYPER-V/VIRTUALBOX COMPATIBLE PROPERTY SETTERS
|
231
|
+
# ============================================================
|
232
|
+
|
233
|
+
private
|
234
|
+
|
235
|
+
def ensure_catlet_hash!
|
236
|
+
@catlet = {} if @catlet == UNSET_VALUE || !@catlet.is_a?(Hash)
|
237
|
+
end
|
238
|
+
|
239
|
+
public
|
240
|
+
|
241
|
+
# CPU configuration
|
242
|
+
def cpus=(value)
|
243
|
+
@cpus = value
|
244
|
+
@catlet = {} if @catlet == UNSET_VALUE || !@catlet.is_a?(Hash)
|
245
|
+
@catlet[:cpu] ||= {}
|
246
|
+
@catlet[:cpu][:count] = value
|
247
|
+
end
|
248
|
+
|
249
|
+
# Memory configuration (startup memory)
|
250
|
+
def memory=(value)
|
251
|
+
@memory = value
|
252
|
+
@catlet = {} if @catlet == UNSET_VALUE || !@catlet.is_a?(Hash)
|
253
|
+
@catlet[:memory] ||= {}
|
254
|
+
@catlet[:memory][:startup] = value
|
255
|
+
end
|
256
|
+
|
257
|
+
# Maximum memory (enables dynamic memory)
|
258
|
+
def maxmemory=(value)
|
259
|
+
@maxmemory = value
|
260
|
+
ensure_catlet_hash!
|
261
|
+
@catlet[:memory] ||= {}
|
262
|
+
@catlet[:memory][:maximum] = value
|
263
|
+
|
264
|
+
# Auto-enable dynamic memory when maxmemory is set
|
265
|
+
@catlet[:capabilities] ||= []
|
266
|
+
@catlet[:capabilities].reject! { |c| c[:name] == 'dynamic_memory' }
|
267
|
+
@catlet[:capabilities] << { name: 'dynamic_memory' }
|
268
|
+
end
|
269
|
+
|
270
|
+
# VM name (maps to catlet name)
|
271
|
+
def vmname=(value)
|
272
|
+
@vmname = value
|
273
|
+
@catlet_name = value # For backward compatibility
|
274
|
+
ensure_catlet_hash!
|
275
|
+
@catlet[:name] = value
|
276
|
+
end
|
277
|
+
|
278
|
+
# Network hostname
|
279
|
+
def hostname=(value)
|
280
|
+
@hostname = value
|
281
|
+
ensure_catlet_hash!
|
282
|
+
@catlet[:hostname] = value
|
283
|
+
end
|
284
|
+
|
285
|
+
# Nested virtualization support
|
286
|
+
def enable_virtualization_extensions=(value)
|
287
|
+
@enable_virtualization_extensions = value
|
288
|
+
ensure_catlet_hash!
|
289
|
+
@catlet[:capabilities] ||= []
|
290
|
+
@catlet[:capabilities].reject! { |c| c[:name] == 'nested_virtualization' }
|
291
|
+
|
292
|
+
return unless value
|
293
|
+
|
294
|
+
@catlet[:capabilities] << { name: 'nested_virtualization' }
|
295
|
+
end
|
296
|
+
|
297
|
+
# Secure boot support
|
298
|
+
def enable_secure_boot=(value)
|
299
|
+
@enable_secure_boot = value
|
300
|
+
ensure_catlet_hash!
|
301
|
+
@catlet[:capabilities] ||= []
|
302
|
+
@catlet[:capabilities].reject! { |c| c[:name] == 'secure_boot' }
|
303
|
+
|
304
|
+
return unless value
|
305
|
+
|
306
|
+
@catlet[:capabilities] << { name: 'secure_boot' }
|
307
|
+
end
|
308
|
+
|
309
|
+
# ============================================================
|
310
|
+
# ERYPH TOP-LEVEL PROPERTY SETTERS
|
311
|
+
# ============================================================
|
312
|
+
|
313
|
+
def parent=(value)
|
314
|
+
@parent = value
|
315
|
+
ensure_catlet_hash!
|
316
|
+
@catlet[:parent] = value
|
317
|
+
end
|
318
|
+
|
319
|
+
def location=(value)
|
320
|
+
@location = value
|
321
|
+
ensure_catlet_hash!
|
322
|
+
@catlet[:location] = value
|
323
|
+
end
|
324
|
+
|
325
|
+
def environment=(value)
|
326
|
+
@environment = value
|
327
|
+
ensure_catlet_hash!
|
328
|
+
@catlet[:environment] = value
|
329
|
+
end
|
330
|
+
|
331
|
+
def store=(value)
|
332
|
+
@store = value
|
333
|
+
ensure_catlet_hash!
|
334
|
+
@catlet[:store] = value
|
335
|
+
end
|
336
|
+
|
337
|
+
# ============================================================
|
338
|
+
# DRIVE MANAGEMENT WITH UNIX NAMING
|
339
|
+
# ============================================================
|
340
|
+
|
341
|
+
DRIVE_TYPE_MAP = {
|
342
|
+
vhd: 'VHD',
|
343
|
+
shared_vhd: 'SharedVHD',
|
344
|
+
dvd: 'DVD',
|
345
|
+
vhd_set: 'VHDSet'
|
346
|
+
}.freeze
|
347
|
+
|
348
|
+
def add_drive(name, size: nil, type: :vhd, source: nil, **options)
|
349
|
+
drive_config = { name: name }
|
350
|
+
drive_config[:size] = size if size
|
351
|
+
|
352
|
+
# Convert symbol to proper API string
|
353
|
+
drive_config[:type] = DRIVE_TYPE_MAP[type] || type.to_s
|
354
|
+
drive_config[:source] = source if source
|
355
|
+
drive_config.merge!(options)
|
356
|
+
|
357
|
+
@drives = [] if @drives == UNSET_VALUE
|
358
|
+
@drives << drive_config
|
359
|
+
|
360
|
+
ensure_catlet_hash!
|
361
|
+
@catlet[:drives] ||= []
|
362
|
+
@catlet[:drives] << drive_config
|
363
|
+
end
|
364
|
+
|
365
|
+
# ============================================================
|
366
|
+
# CAPABILITIES MANAGEMENT
|
367
|
+
# ============================================================
|
368
|
+
|
369
|
+
def enable_capability(name, details: nil)
|
370
|
+
ensure_catlet_hash!
|
371
|
+
@catlet[:capabilities] ||= []
|
372
|
+
@catlet[:capabilities].reject! { |c| c[:name] == name.to_s }
|
373
|
+
cap_config = { name: name.to_s }
|
374
|
+
cap_config[:details] = details if details
|
375
|
+
@catlet[:capabilities] << cap_config
|
376
|
+
end
|
377
|
+
|
378
|
+
def disable_capability(name)
|
379
|
+
ensure_catlet_hash!
|
380
|
+
@catlet[:capabilities] ||= []
|
381
|
+
@catlet[:capabilities].reject! { |c| c[:name] == name.to_s }
|
382
|
+
end
|
383
|
+
|
384
|
+
# ============================================================
|
385
|
+
# GENE MANAGEMENT
|
386
|
+
# ============================================================
|
387
|
+
|
388
|
+
def add_fodder_gene(geneset, gene, fodder_name: nil, variables: nil, **options)
|
389
|
+
# Build proper gene fodder reference syntax: gene:geneset:gene
|
390
|
+
gene_source = "gene:#{geneset}:#{gene}"
|
391
|
+
|
392
|
+
# Create fodder item with gene source
|
393
|
+
fodder_config = {
|
394
|
+
source: gene_source
|
395
|
+
}
|
396
|
+
|
397
|
+
# Add name only if provided
|
398
|
+
fodder_config[:name] = fodder_name if fodder_name
|
399
|
+
|
400
|
+
# Add variables if specified - must be an array of variable objects per spec
|
401
|
+
fodder_config[:variables] = variables if variables&.any?
|
402
|
+
|
403
|
+
# Add any other options
|
404
|
+
fodder_config.merge!(options) if options.any?
|
405
|
+
|
406
|
+
# Add to genes array for later processing
|
407
|
+
@genes = [] if @genes == UNSET_VALUE
|
408
|
+
@genes << fodder_config
|
409
|
+
|
410
|
+
fodder_config
|
411
|
+
|
412
|
+
end
|
413
|
+
|
414
|
+
# ============================================================
|
415
|
+
# VARIABLE MANAGEMENT
|
416
|
+
# ============================================================
|
417
|
+
|
418
|
+
def set_variable(name, value)
|
419
|
+
@variables = [] if @variables == UNSET_VALUE
|
420
|
+
|
421
|
+
# Find existing variable or create new one
|
422
|
+
var = @variables.find { |v| v[:name] == name }
|
423
|
+
if var
|
424
|
+
# Update existing variable's value
|
425
|
+
var[:value] = value
|
426
|
+
else
|
427
|
+
# Create new variable with value (no type inference - must be declared separately)
|
428
|
+
@variables << {
|
429
|
+
name: name,
|
430
|
+
value: value
|
431
|
+
}
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
# ============================================================
|
436
|
+
# FODDER HELPERS
|
437
|
+
# ============================================================
|
438
|
+
|
439
|
+
def cloud_config(name, content = nil)
|
440
|
+
@fodder ||= []
|
441
|
+
|
442
|
+
if block_given?
|
443
|
+
# DSL-style configuration
|
444
|
+
config_data = {}
|
445
|
+
yield config_data
|
446
|
+
content = config_data
|
447
|
+
end
|
448
|
+
|
449
|
+
@fodder << {
|
450
|
+
name: name,
|
451
|
+
type: 'cloud-config',
|
452
|
+
content: content
|
453
|
+
}
|
454
|
+
end
|
455
|
+
|
456
|
+
def shell_script(name, content)
|
457
|
+
@fodder ||= []
|
458
|
+
@fodder << {
|
459
|
+
name: name,
|
460
|
+
type: 'shellscript',
|
461
|
+
content: content
|
462
|
+
}
|
463
|
+
end
|
464
|
+
|
465
|
+
# Helper method to extract Vagrant cloud-init configuration
|
466
|
+
# NOTE: We don't use Vagrant's cloud-init system - we generate our own fodder
|
467
|
+
def extract_vagrant_cloud_init_config(_machine)
|
468
|
+
# Always return empty - we handle cloud-init through our own fodder system
|
469
|
+
[]
|
470
|
+
end
|
471
|
+
|
472
|
+
private
|
473
|
+
|
474
|
+
# Convert Vagrant cloud-init configuration to Eryph fodder format
|
475
|
+
def convert_cloud_init_to_fodder(cloud_init_config, index = 0)
|
476
|
+
return nil unless cloud_init_config
|
477
|
+
return nil unless cloud_init_config.content_type
|
478
|
+
return nil if cloud_init_config.content_type == UNSET_VALUE
|
479
|
+
|
480
|
+
# Map Vagrant content types to Eryph fodder types
|
481
|
+
fodder_type = map_content_type_to_fodder_type(cloud_init_config.content_type)
|
482
|
+
return nil unless fodder_type
|
483
|
+
|
484
|
+
# Generate name based on type and index
|
485
|
+
name = "vagrant-cloud-init-#{fodder_type}"
|
486
|
+
name += "-#{index}" if index.positive?
|
487
|
+
|
488
|
+
# Extract content
|
489
|
+
content = extract_cloud_init_content(cloud_init_config)
|
490
|
+
return nil unless content
|
491
|
+
|
492
|
+
{
|
493
|
+
name: name,
|
494
|
+
type: fodder_type,
|
495
|
+
content: content
|
496
|
+
}
|
497
|
+
end
|
498
|
+
|
499
|
+
# Map Vagrant content types to Eryph fodder types
|
500
|
+
def map_content_type_to_fodder_type(content_type)
|
501
|
+
case content_type
|
502
|
+
when 'text/cloud-config'
|
503
|
+
'cloud-config'
|
504
|
+
when 'text/x-shellscript'
|
505
|
+
'shellscript'
|
506
|
+
when 'text/cloud-boothook'
|
507
|
+
'cloud-boothook'
|
508
|
+
when 'text/cloud-config-archive'
|
509
|
+
'cloud-config-archive'
|
510
|
+
when 'text/part-handler'
|
511
|
+
'part-handler'
|
512
|
+
when 'text/upstart-job'
|
513
|
+
'upstart-job'
|
514
|
+
else
|
515
|
+
nil # Unsupported content type
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
# Extract content from cloud-init configuration
|
520
|
+
def extract_cloud_init_content(cloud_init_config)
|
521
|
+
inline_content = cloud_init_config.inline
|
522
|
+
path_content = cloud_init_config.path
|
523
|
+
|
524
|
+
# Skip UNSET_VALUE properties
|
525
|
+
return nil if inline_content == UNSET_VALUE && path_content == UNSET_VALUE
|
526
|
+
|
527
|
+
if inline_content && inline_content != UNSET_VALUE
|
528
|
+
process_cloud_init_content(inline_content, cloud_init_config.content_type)
|
529
|
+
elsif path_content && path_content != UNSET_VALUE && File.exist?(path_content)
|
530
|
+
content = File.read(path_content)
|
531
|
+
process_cloud_init_content(content, cloud_init_config.content_type)
|
532
|
+
end
|
533
|
+
end
|
534
|
+
|
535
|
+
# Process cloud-init content based on content type
|
536
|
+
def process_cloud_init_content(content, content_type)
|
537
|
+
case content_type
|
538
|
+
when 'text/cloud-config'
|
539
|
+
# Parse YAML content into hash for cloud-config
|
540
|
+
begin
|
541
|
+
YAML.safe_load(content)
|
542
|
+
rescue StandardError
|
543
|
+
# If YAML parsing fails, return as string
|
544
|
+
content
|
545
|
+
end
|
546
|
+
else
|
547
|
+
# Return other content types as strings
|
548
|
+
content
|
549
|
+
end
|
550
|
+
end
|
551
|
+
end
|
552
|
+
end
|
553
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Eryph
|
5
|
+
module Errors
|
6
|
+
class EryphError < Vagrant::Errors::VagrantError
|
7
|
+
attr_reader :problem_details
|
8
|
+
|
9
|
+
def initialize(message = nil, problem_details = nil)
|
10
|
+
@problem_details = problem_details
|
11
|
+
super(message)
|
12
|
+
end
|
13
|
+
|
14
|
+
error_namespace('vagrant_eryph.errors')
|
15
|
+
|
16
|
+
def has_problem_details?
|
17
|
+
!@problem_details.nil?
|
18
|
+
end
|
19
|
+
|
20
|
+
def friendly_message
|
21
|
+
if has_problem_details? && @problem_details.respond_to?(:friendly_message)
|
22
|
+
@problem_details.friendly_message
|
23
|
+
else
|
24
|
+
super
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class APIConnectionError < EryphError
|
30
|
+
error_key(:api_connection_failed)
|
31
|
+
end
|
32
|
+
|
33
|
+
class CredentialsError < EryphError
|
34
|
+
error_key(:credentials_not_found)
|
35
|
+
end
|
36
|
+
|
37
|
+
class CatletNotFoundError < EryphError
|
38
|
+
error_key(:catlet_not_found)
|
39
|
+
end
|
40
|
+
|
41
|
+
class OperationFailedError < EryphError
|
42
|
+
error_key(:operation_failed)
|
43
|
+
end
|
44
|
+
|
45
|
+
class ConfigurationError < EryphError
|
46
|
+
error_key(:configuration_error)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Helper method to convert API errors to our enhanced errors
|
50
|
+
def self.from_api_error(api_error, error_class = EryphError)
|
51
|
+
if api_error.is_a?(::Eryph::Compute::ProblemDetailsError)
|
52
|
+
error_class.new(api_error.friendly_message, api_error)
|
53
|
+
elsif api_error.respond_to?(:message)
|
54
|
+
error_class.new(api_error.message, api_error)
|
55
|
+
else
|
56
|
+
error_class.new(api_error.to_s, api_error)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|