vagrant-ssh-config-manager 0.8.3 → 1.0.0.alpha
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 +4 -4
- data/.bundle/config +1 -1
- data/.gitignore +2 -1
- data/.rspec +2 -0
- data/.rubocop.yml +62 -0
- data/Gemfile +11 -9
- data/README.md +2 -2
- data/Rakefile +10 -8
- data/TESTING.md +82 -0
- data/lib/vagrant/ssh/config/manager.rb +5 -0
- data/lib/vagrant_ssh_config_manager/action/destroy.rb +82 -0
- data/lib/vagrant_ssh_config_manager/action/halt.rb +66 -0
- data/lib/vagrant_ssh_config_manager/action/provision.rb +81 -0
- data/lib/vagrant_ssh_config_manager/action/reload.rb +105 -0
- data/lib/vagrant_ssh_config_manager/action/up.rb +98 -0
- data/lib/{vagrant-ssh-config-manager → vagrant_ssh_config_manager}/config.rb +45 -49
- data/lib/{vagrant-ssh-config-manager → vagrant_ssh_config_manager}/file_locker.rb +35 -37
- data/lib/{vagrant-ssh-config-manager → vagrant_ssh_config_manager}/file_manager.rb +90 -80
- data/lib/{vagrant-ssh-config-manager → vagrant_ssh_config_manager}/include_manager.rb +54 -53
- data/lib/{vagrant-ssh-config-manager → vagrant_ssh_config_manager}/plugin.rb +15 -13
- data/lib/vagrant_ssh_config_manager/ssh_config_manager.rb +1152 -0
- data/lib/{vagrant-ssh-config-manager → vagrant_ssh_config_manager}/ssh_info_extractor.rb +129 -141
- data/lib/vagrant_ssh_config_manager/version.rb +7 -0
- data/lib/{vagrant-ssh-config-manager.rb → vagrant_ssh_config_manager.rb} +15 -12
- data/test-all.sh +11 -0
- data/test-integration.sh +4 -0
- data/test-unit.sh +4 -0
- data/vagrant-ssh-config-manager.gemspec +25 -21
- metadata +28 -18
- data/lib/vagrant-ssh-config-manager/action/destroy.rb +0 -84
- data/lib/vagrant-ssh-config-manager/action/halt.rb +0 -68
- data/lib/vagrant-ssh-config-manager/action/provision.rb +0 -82
- data/lib/vagrant-ssh-config-manager/action/reload.rb +0 -106
- data/lib/vagrant-ssh-config-manager/action/up.rb +0 -99
- data/lib/vagrant-ssh-config-manager/ssh_config_manager.rb +0 -2150
- data/lib/vagrant-ssh-config-manager/version.rb +0 -5
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'fileutils'
|
2
4
|
require 'digest'
|
3
5
|
require 'tempfile'
|
@@ -9,7 +11,7 @@ module VagrantPlugins
|
|
9
11
|
# Initialize FileManager with configuration
|
10
12
|
def initialize(config)
|
11
13
|
@config = config
|
12
|
-
@logger = Log4r::Logger.new(
|
14
|
+
@logger = Log4r::Logger.new('vagrant::plugins::sshconfigmanager::filemanager')
|
13
15
|
end
|
14
16
|
|
15
17
|
# Generate unique filename for VM SSH config
|
@@ -20,10 +22,14 @@ module VagrantPlugins
|
|
20
22
|
"#{project_hash}-#{vm_name}.conf"
|
21
23
|
end
|
22
24
|
|
23
|
-
#
|
24
|
-
def
|
25
|
-
|
26
|
-
|
25
|
+
# Generate full file path for a machine's SSH config under ssh_config_dir
|
26
|
+
def generate_file_path(machine)
|
27
|
+
File.join(@config.ssh_config_dir, generate_filename(machine))
|
28
|
+
end
|
29
|
+
|
30
|
+
# Return full path for a machine's SSH config file
|
31
|
+
def file_path(machine)
|
32
|
+
generate_file_path(machine)
|
27
33
|
end
|
28
34
|
|
29
35
|
# Generate SSH config content for a VM
|
@@ -32,28 +38,28 @@ module VagrantPlugins
|
|
32
38
|
return nil unless ssh_info
|
33
39
|
|
34
40
|
content = []
|
35
|
-
content <<
|
41
|
+
content << '# Managed by vagrant-ssh-config-manager plugin'
|
36
42
|
content << "# Project: #{File.basename(machine.env.root_path)}"
|
37
43
|
content << "# VM: #{machine.name}"
|
38
44
|
content << "# Generated: #{Time.now.strftime('%Y-%m-%d %H:%M:%S')}"
|
39
|
-
content <<
|
40
|
-
|
45
|
+
content << ''
|
46
|
+
|
41
47
|
host_name = generate_host_name(machine)
|
42
48
|
content << "Host #{host_name}"
|
43
49
|
content << " HostName #{ssh_info[:host]}"
|
44
50
|
content << " Port #{ssh_info[:port]}"
|
45
51
|
content << " User #{ssh_info[:username]}"
|
46
|
-
|
47
|
-
if ssh_info[:private_key_path]
|
52
|
+
|
53
|
+
if ssh_info[:private_key_path]&.first
|
48
54
|
content << " IdentityFile #{ssh_info[:private_key_path].first}"
|
49
|
-
content <<
|
55
|
+
content << ' IdentitiesOnly yes'
|
50
56
|
end
|
51
|
-
|
52
|
-
content <<
|
53
|
-
content <<
|
54
|
-
content <<
|
55
|
-
content <<
|
56
|
-
content <<
|
57
|
+
|
58
|
+
content << ' UserKnownHostsFile /dev/null'
|
59
|
+
content << ' StrictHostKeyChecking no'
|
60
|
+
content << ' PasswordAuthentication no'
|
61
|
+
content << ' LogLevel FATAL'
|
62
|
+
content << ''
|
57
63
|
|
58
64
|
content.join("\n")
|
59
65
|
end
|
@@ -62,20 +68,20 @@ module VagrantPlugins
|
|
62
68
|
def write_ssh_config_file(machine)
|
63
69
|
return false unless @config.enabled
|
64
70
|
|
65
|
-
file_path =
|
71
|
+
file_path = file_path(machine)
|
66
72
|
content = generate_ssh_config_content(machine)
|
67
73
|
return false unless content
|
68
74
|
|
69
75
|
begin
|
70
76
|
# Ensure directory exists
|
71
|
-
FileUtils.mkdir_p(File.dirname(file_path), mode:
|
72
|
-
|
77
|
+
FileUtils.mkdir_p(File.dirname(file_path), mode: 0o700)
|
78
|
+
|
73
79
|
# Use atomic write with temporary file
|
74
80
|
write_file_atomically(file_path, content)
|
75
|
-
|
81
|
+
|
76
82
|
@logger.info("SSH config file created: #{file_path}")
|
77
83
|
true
|
78
|
-
rescue => e
|
84
|
+
rescue StandardError => e
|
79
85
|
@logger.error("Failed to write SSH config file #{file_path}: #{e.message}")
|
80
86
|
false
|
81
87
|
end
|
@@ -83,13 +89,13 @@ module VagrantPlugins
|
|
83
89
|
|
84
90
|
# Remove SSH config file for VM
|
85
91
|
def remove_ssh_config_file(machine)
|
86
|
-
file_path =
|
87
|
-
|
92
|
+
file_path = file_path(machine)
|
93
|
+
|
88
94
|
begin
|
89
95
|
if File.exist?(file_path)
|
90
96
|
File.delete(file_path)
|
91
97
|
@logger.info("SSH config file removed: #{file_path}")
|
92
|
-
|
98
|
+
|
93
99
|
# Clean up empty directory if configured
|
94
100
|
cleanup_empty_directory if @config.cleanup_empty_dir
|
95
101
|
true
|
@@ -97,7 +103,7 @@ module VagrantPlugins
|
|
97
103
|
@logger.debug("SSH config file does not exist: #{file_path}")
|
98
104
|
false
|
99
105
|
end
|
100
|
-
rescue => e
|
106
|
+
rescue StandardError => e
|
101
107
|
@logger.error("Failed to remove SSH config file #{file_path}: #{e.message}")
|
102
108
|
false
|
103
109
|
end
|
@@ -105,46 +111,49 @@ module VagrantPlugins
|
|
105
111
|
|
106
112
|
# Check if SSH config file exists for VM
|
107
113
|
def ssh_config_file_exists?(machine)
|
108
|
-
File.exist?(
|
114
|
+
File.exist?(file_path(machine))
|
109
115
|
end
|
110
116
|
|
111
117
|
# Validate SSH config file content
|
112
|
-
|
118
|
+
# Returns true if the content contains required SSH config elements
|
119
|
+
def validate_ssh_config_content?(content)
|
113
120
|
return false if content.nil? || content.empty?
|
114
|
-
|
121
|
+
|
115
122
|
# Basic validation - check for required SSH config elements
|
116
|
-
content.include?(
|
123
|
+
content.include?('Host ') && content.include?('HostName ') && content.include?('Port ')
|
117
124
|
end
|
118
125
|
|
126
|
+
alias validate_ssh_config_content validate_ssh_config_content?
|
127
|
+
|
119
128
|
# Detect and clean up orphaned SSH config files
|
120
129
|
def cleanup_orphaned_files
|
121
130
|
return unless Dir.exist?(@config.ssh_config_dir)
|
122
131
|
|
123
132
|
orphaned_files = []
|
124
|
-
config_files = Dir.glob(File.join(@config.ssh_config_dir,
|
133
|
+
config_files = Dir.glob(File.join(@config.ssh_config_dir, '*.conf'))
|
125
134
|
|
126
135
|
config_files.each do |file_path|
|
127
|
-
filename = File.basename(file_path,
|
128
|
-
|
136
|
+
filename = File.basename(file_path, '.conf')
|
137
|
+
|
129
138
|
# Parse filename to extract project hash and VM name
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
139
|
+
next unless filename.match(/^([a-f0-9]{8})-(.+)$/)
|
140
|
+
|
141
|
+
project_hash = ::Regexp.last_match(1)
|
142
|
+
vm_name = ::Regexp.last_match(2)
|
143
|
+
|
144
|
+
# Check if this looks like an orphaned file
|
145
|
+
# (This is a basic heuristic - in practice, you might want more sophisticated detection)
|
146
|
+
file_age = Time.now - File.mtime(file_path)
|
147
|
+
|
148
|
+
# Consider files older than 30 days as potentially orphaned
|
149
|
+
next unless file_age > (30 * 24 * 60 * 60) # 30 days in seconds
|
150
|
+
|
151
|
+
orphaned_files << {
|
152
|
+
path: file_path,
|
153
|
+
project_hash: project_hash,
|
154
|
+
vm_name: vm_name,
|
155
|
+
age_days: (file_age / (24 * 60 * 60)).round
|
156
|
+
}
|
148
157
|
end
|
149
158
|
|
150
159
|
# Log detected orphaned files
|
@@ -164,27 +173,28 @@ module VagrantPlugins
|
|
164
173
|
removed_count = 0
|
165
174
|
|
166
175
|
orphaned_files.each do |file_info|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
@logger.error("Failed to remove orphaned file #{file_info[:path]}: #{e.message}")
|
173
|
-
end
|
176
|
+
File.delete(file_info[:path])
|
177
|
+
@logger.info("Removed orphaned SSH config file: #{file_info[:path]}")
|
178
|
+
removed_count += 1
|
179
|
+
rescue StandardError => e
|
180
|
+
@logger.error("Failed to remove orphaned file #{file_info[:path]}: #{e.message}")
|
174
181
|
end
|
175
182
|
|
176
183
|
# Clean up empty directory if configured
|
177
|
-
cleanup_empty_directory if @config.cleanup_empty_dir && removed_count
|
184
|
+
cleanup_empty_directory if @config.cleanup_empty_dir && removed_count.positive?
|
178
185
|
|
179
186
|
removed_count
|
180
187
|
end
|
181
188
|
|
182
|
-
#
|
183
|
-
def
|
184
|
-
|
185
|
-
Dir.glob(File.join(@config.ssh_config_dir, "*.conf"))
|
189
|
+
# Return list of all config files
|
190
|
+
def all_config_files
|
191
|
+
Dir.glob(File.join(@config.ssh_config_dir, '*.conf'))
|
186
192
|
end
|
187
193
|
|
194
|
+
# Backward compatibility aliases
|
195
|
+
alias get_file_path file_path
|
196
|
+
alias get_all_config_files all_config_files
|
197
|
+
|
188
198
|
private
|
189
199
|
|
190
200
|
# Generate unique project hash from root path
|
@@ -208,10 +218,10 @@ module VagrantPlugins
|
|
208
218
|
begin
|
209
219
|
temp_file.write(content)
|
210
220
|
temp_file.close
|
211
|
-
|
221
|
+
|
212
222
|
# Set proper permissions before moving
|
213
|
-
File.chmod(
|
214
|
-
|
223
|
+
File.chmod(0o600, temp_file.path)
|
224
|
+
|
215
225
|
# Atomic move
|
216
226
|
FileUtils.mv(temp_file.path, file_path)
|
217
227
|
ensure
|
@@ -222,22 +232,22 @@ module VagrantPlugins
|
|
222
232
|
# Clean up empty directory if no config files remain
|
223
233
|
def cleanup_empty_directory
|
224
234
|
return unless Dir.exist?(@config.ssh_config_dir)
|
225
|
-
|
235
|
+
|
226
236
|
entries = Dir.entries(@config.ssh_config_dir) - %w[. ..]
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
Dir.rmdir(@config.ssh_config_dir)
|
237
|
-
@logger.info("Removed empty SSH config directory: #{@config.ssh_config_dir}")
|
238
|
-
rescue => e
|
239
|
-
@logger.error("Failed to remove empty directory #{@config.ssh_config_dir}: #{e.message}")
|
237
|
+
return unless entries.empty?
|
238
|
+
|
239
|
+
begin
|
240
|
+
# Remove Include directive before removing directory
|
241
|
+
if @config.manage_includes
|
242
|
+
require_relative 'include_manager'
|
243
|
+
include_manager = IncludeManager.new(@config)
|
244
|
+
include_manager.remove_include_directive
|
240
245
|
end
|
246
|
+
|
247
|
+
Dir.rmdir(@config.ssh_config_dir)
|
248
|
+
@logger.info("Removed empty SSH config directory: #{@config.ssh_config_dir}")
|
249
|
+
rescue StandardError => e
|
250
|
+
@logger.error("Failed to remove empty directory #{@config.ssh_config_dir}: #{e.message}")
|
241
251
|
end
|
242
252
|
end
|
243
253
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'fileutils'
|
2
4
|
require 'tempfile'
|
3
5
|
require 'log4r'
|
@@ -5,24 +7,24 @@ require 'log4r'
|
|
5
7
|
module VagrantPlugins
|
6
8
|
module SshConfigManager
|
7
9
|
class IncludeManager
|
8
|
-
PLUGIN_MARKER_START =
|
9
|
-
PLUGIN_MARKER_END =
|
10
|
+
PLUGIN_MARKER_START = '# BEGIN vagrant-ssh-config-manager'
|
11
|
+
PLUGIN_MARKER_END = '# END vagrant-ssh-config-manager'
|
10
12
|
|
11
13
|
# Initialize IncludeManager with configuration
|
12
14
|
def initialize(config)
|
13
15
|
@config = config
|
14
|
-
@logger = Log4r::Logger.new(
|
16
|
+
@logger = Log4r::Logger.new('vagrant::plugins::sshconfigmanager::includemanager')
|
15
17
|
end
|
16
18
|
|
17
19
|
# Get the SSH config file path (always ~/.ssh/config)
|
18
20
|
def ssh_config_file
|
19
|
-
@ssh_config_file ||= File.expand_path(
|
21
|
+
@ssh_config_file ||= File.expand_path('~/.ssh/config')
|
20
22
|
end
|
21
23
|
|
22
24
|
# Check if Include directive exists in main SSH config
|
23
25
|
def include_directive_exists?
|
24
26
|
return false unless File.exist?(ssh_config_file)
|
25
|
-
|
27
|
+
|
26
28
|
content = File.read(ssh_config_file)
|
27
29
|
include_pattern = /^Include\s+#{Regexp.escape(@config.ssh_config_dir)}/
|
28
30
|
content.match?(include_pattern)
|
@@ -36,13 +38,13 @@ module VagrantPlugins
|
|
36
38
|
begin
|
37
39
|
# Create backup before modifying
|
38
40
|
create_backup
|
39
|
-
|
41
|
+
|
40
42
|
# Add Include directive at the beginning of file
|
41
43
|
add_include_to_config
|
42
|
-
|
44
|
+
|
43
45
|
@logger.info("Added Include directive for #{@config.ssh_config_dir} to ~/.ssh/config")
|
44
46
|
true
|
45
|
-
rescue => e
|
47
|
+
rescue StandardError => e
|
46
48
|
@logger.error("Failed to add Include directive: #{e.message}")
|
47
49
|
restore_backup
|
48
50
|
false
|
@@ -57,13 +59,13 @@ module VagrantPlugins
|
|
57
59
|
begin
|
58
60
|
# Create backup before modifying
|
59
61
|
create_backup
|
60
|
-
|
62
|
+
|
61
63
|
# Remove Include directive
|
62
64
|
remove_include_from_config
|
63
|
-
|
65
|
+
|
64
66
|
@logger.info("Removed Include directive for #{@config.ssh_config_dir} from ~/.ssh/config")
|
65
67
|
true
|
66
|
-
rescue => e
|
68
|
+
rescue StandardError => e
|
67
69
|
@logger.error("Failed to remove Include directive: #{e.message}")
|
68
70
|
restore_backup
|
69
71
|
false
|
@@ -74,7 +76,7 @@ module VagrantPlugins
|
|
74
76
|
def should_remove_include_directive?
|
75
77
|
return false unless @config.cleanup_empty_dir
|
76
78
|
return false unless Dir.exist?(@config.ssh_config_dir)
|
77
|
-
|
79
|
+
|
78
80
|
# Check if directory is empty (excluding . and ..)
|
79
81
|
entries = Dir.entries(@config.ssh_config_dir) - %w[. ..]
|
80
82
|
config_files = entries.select { |file| file.end_with?('.conf') }
|
@@ -87,7 +89,9 @@ module VagrantPlugins
|
|
87
89
|
|
88
90
|
if should_remove_include_directive?
|
89
91
|
remove_include_directive
|
90
|
-
elsif Dir.exist?(@config.ssh_config_dir) &&
|
92
|
+
elsif Dir.exist?(@config.ssh_config_dir) && Dir.entries(@config.ssh_config_dir).any? do |f|
|
93
|
+
File.file?(File.join(@config.ssh_config_dir, f)) && f.end_with?('.conf')
|
94
|
+
end
|
91
95
|
add_include_directive
|
92
96
|
end
|
93
97
|
end
|
@@ -95,10 +99,10 @@ module VagrantPlugins
|
|
95
99
|
# Parse SSH config file and find optimal location for Include
|
96
100
|
def find_include_location(content)
|
97
101
|
lines = content.lines
|
98
|
-
|
102
|
+
|
99
103
|
# Look for existing Include directives to place ours with them
|
100
104
|
include_line_index = lines.find_index { |line| line.strip.start_with?('Include ') }
|
101
|
-
|
105
|
+
|
102
106
|
if include_line_index
|
103
107
|
# Place before other Include directives
|
104
108
|
include_line_index
|
@@ -106,11 +110,9 @@ module VagrantPlugins
|
|
106
110
|
# Place at the beginning of file, after any initial comments
|
107
111
|
comment_end = 0
|
108
112
|
lines.each_with_index do |line, index|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
break
|
113
|
-
end
|
113
|
+
break unless line.strip.empty? || line.strip.start_with?('#')
|
114
|
+
|
115
|
+
comment_end = index + 1
|
114
116
|
end
|
115
117
|
comment_end
|
116
118
|
end
|
@@ -119,24 +121,25 @@ module VagrantPlugins
|
|
119
121
|
# Check if main SSH config file is write-protected
|
120
122
|
def main_config_writable?
|
121
123
|
return false unless File.exist?(ssh_config_file)
|
124
|
+
|
122
125
|
File.writable?(ssh_config_file)
|
123
126
|
end
|
124
127
|
|
125
128
|
# Handle edge case: empty main config file
|
126
129
|
def handle_empty_main_config
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
130
|
+
return if File.exist?(ssh_config_file)
|
131
|
+
|
132
|
+
# Create empty SSH config file with proper permissions
|
133
|
+
FileUtils.mkdir_p(File.dirname(ssh_config_file), mode: 0o700)
|
134
|
+
File.write(ssh_config_file, '')
|
135
|
+
File.chmod(0o600, ssh_config_file)
|
136
|
+
@logger.info("Created empty SSH config file: #{ssh_config_file}")
|
134
137
|
end
|
135
138
|
|
136
139
|
# Validate SSH config file format
|
137
140
|
def validate_main_config
|
138
141
|
return true unless File.exist?(ssh_config_file)
|
139
|
-
|
142
|
+
|
140
143
|
begin
|
141
144
|
content = File.read(ssh_config_file)
|
142
145
|
# Basic validation - check for severely malformed config
|
@@ -144,14 +147,14 @@ module VagrantPlugins
|
|
144
147
|
lines.each_with_index do |line, index|
|
145
148
|
stripped = line.strip
|
146
149
|
next if stripped.empty? || stripped.start_with?('#')
|
147
|
-
|
150
|
+
|
148
151
|
# Check for basic SSH config format issues
|
149
|
-
if stripped.include?("\t") && stripped.start_with?(
|
152
|
+
if stripped.include?("\t") && stripped.start_with?('Host ')
|
150
153
|
@logger.warn("Potential SSH config format issue at line #{index + 1}: tabs in Host directive")
|
151
154
|
end
|
152
155
|
end
|
153
156
|
true
|
154
|
-
rescue => e
|
157
|
+
rescue StandardError => e
|
155
158
|
@logger.error("SSH config validation failed: #{e.message}")
|
156
159
|
false
|
157
160
|
end
|
@@ -168,23 +171,23 @@ module VagrantPlugins
|
|
168
171
|
|
169
172
|
# Restore backup of main SSH config file
|
170
173
|
def restore_backup
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
174
|
+
return unless @backup_path && File.exist?(@backup_path)
|
175
|
+
|
176
|
+
FileUtils.cp(@backup_path, ssh_config_file)
|
177
|
+
File.delete(@backup_path)
|
178
|
+
@logger.info('Restored SSH config from backup')
|
176
179
|
end
|
177
180
|
|
178
181
|
# Add Include directive to SSH config
|
179
182
|
def add_include_to_config
|
180
183
|
handle_empty_main_config
|
181
|
-
|
182
|
-
content = File.exist?(ssh_config_file) ? File.read(ssh_config_file) :
|
184
|
+
|
185
|
+
content = File.exist?(ssh_config_file) ? File.read(ssh_config_file) : ''
|
183
186
|
lines = content.lines
|
184
|
-
|
187
|
+
|
185
188
|
# Find optimal location for Include
|
186
189
|
insert_index = find_include_location(content)
|
187
|
-
|
190
|
+
|
188
191
|
# Create Include directive with plugin markers
|
189
192
|
include_lines = [
|
190
193
|
"#{PLUGIN_MARKER_START}\n",
|
@@ -192,10 +195,10 @@ module VagrantPlugins
|
|
192
195
|
"#{PLUGIN_MARKER_END}\n",
|
193
196
|
"\n"
|
194
197
|
]
|
195
|
-
|
198
|
+
|
196
199
|
# Insert Include directive
|
197
200
|
lines.insert(insert_index, *include_lines)
|
198
|
-
|
201
|
+
|
199
202
|
# Write back to file atomically
|
200
203
|
write_config_atomically(lines.join)
|
201
204
|
end
|
@@ -203,29 +206,27 @@ module VagrantPlugins
|
|
203
206
|
# Remove Include directive from SSH config
|
204
207
|
def remove_include_from_config
|
205
208
|
return unless File.exist?(ssh_config_file)
|
206
|
-
|
209
|
+
|
207
210
|
content = File.read(ssh_config_file)
|
208
211
|
lines = content.lines
|
209
|
-
|
212
|
+
|
210
213
|
# Find and remove plugin-managed Include directive
|
211
214
|
start_index = lines.find_index { |line| line.strip == PLUGIN_MARKER_START.strip }
|
212
215
|
end_index = lines.find_index { |line| line.strip == PLUGIN_MARKER_END.strip }
|
213
|
-
|
216
|
+
|
214
217
|
if start_index && end_index && end_index > start_index
|
215
218
|
# Remove lines between markers (inclusive)
|
216
219
|
lines.slice!(start_index..end_index)
|
217
|
-
|
220
|
+
|
218
221
|
# Remove trailing empty line if it exists
|
219
|
-
if lines[start_index] && lines[start_index].strip.empty?
|
220
|
-
lines.delete_at(start_index)
|
221
|
-
end
|
222
|
+
lines.delete_at(start_index) if lines[start_index] && lines[start_index].strip.empty?
|
222
223
|
else
|
223
224
|
# Fallback: remove any Include directive for our directory
|
224
225
|
lines.reject! do |line|
|
225
226
|
line.strip.match?(/^Include\s+#{Regexp.escape(@config.ssh_config_dir)}/)
|
226
227
|
end
|
227
228
|
end
|
228
|
-
|
229
|
+
|
229
230
|
# Write back to file atomically
|
230
231
|
write_config_atomically(lines.join)
|
231
232
|
end
|
@@ -236,10 +237,10 @@ module VagrantPlugins
|
|
236
237
|
begin
|
237
238
|
temp_file.write(content)
|
238
239
|
temp_file.close
|
239
|
-
|
240
|
+
|
240
241
|
# Set proper permissions before moving
|
241
|
-
File.chmod(
|
242
|
-
|
242
|
+
File.chmod(0o600, temp_file.path)
|
243
|
+
|
243
244
|
# Atomic move
|
244
245
|
FileUtils.mv(temp_file.path, ssh_config_file)
|
245
246
|
ensure
|
@@ -1,54 +1,56 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'vagrant'
|
2
4
|
|
3
5
|
module VagrantPlugins
|
4
6
|
module SshConfigManager
|
5
|
-
class Plugin < Vagrant.plugin(
|
6
|
-
name
|
7
|
+
class Plugin < Vagrant.plugin('2')
|
8
|
+
name 'SSH Config Manager'
|
7
9
|
description <<-DESC
|
8
|
-
This plugin automatically manages SSH configurations by leveraging Vagrant's
|
9
|
-
internal SSH knowledge. It creates and maintains SSH config entries when VMs
|
10
|
+
This plugin automatically manages SSH configurations by leveraging Vagrant's#{' '}
|
11
|
+
internal SSH knowledge. It creates and maintains SSH config entries when VMs#{' '}
|
10
12
|
are started and cleans them up when VMs are destroyed.
|
11
13
|
DESC
|
12
14
|
|
13
15
|
# Register the configuration class
|
14
16
|
config :sshconfigmanager do
|
15
|
-
require
|
17
|
+
require 'vagrant_ssh_config_manager/config'
|
16
18
|
Config
|
17
19
|
end
|
18
20
|
|
19
21
|
# Hook into various Vagrant actions
|
20
22
|
action_hook(:ssh_config_manager, :machine_action_up) do |hook|
|
21
|
-
require
|
23
|
+
require 'vagrant_ssh_config_manager/action/up'
|
22
24
|
hook.after(Vagrant::Action::Builtin::WaitForCommunicator, Action::Up)
|
23
25
|
end
|
24
26
|
|
25
27
|
action_hook(:ssh_config_manager, :machine_action_destroy) do |hook|
|
26
|
-
require
|
28
|
+
require 'vagrant_ssh_config_manager/action/destroy'
|
27
29
|
hook.before(Vagrant::Action::Builtin::DestroyConfirm, Action::Destroy)
|
28
30
|
end
|
29
31
|
|
30
32
|
action_hook(:ssh_config_manager, :machine_action_reload) do |hook|
|
31
|
-
require
|
33
|
+
require 'vagrant_ssh_config_manager/action/reload'
|
32
34
|
hook.after(Vagrant::Action::Builtin::WaitForCommunicator, Action::Reload)
|
33
35
|
end
|
34
36
|
|
35
37
|
action_hook(:ssh_config_manager, :machine_action_halt) do |hook|
|
36
|
-
require
|
38
|
+
require 'vagrant_ssh_config_manager/action/halt'
|
37
39
|
hook.before(Vagrant::Action::Builtin::GracefulHalt, Action::Halt)
|
38
40
|
end
|
39
41
|
|
40
42
|
action_hook(:ssh_config_manager, :machine_action_suspend) do |hook|
|
41
|
-
require
|
43
|
+
require 'vagrant_ssh_config_manager/action/halt'
|
42
44
|
hook.before(Vagrant::Action::Builtin::Suspend, Action::Halt)
|
43
45
|
end
|
44
46
|
|
45
47
|
action_hook(:ssh_config_manager, :machine_action_resume) do |hook|
|
46
|
-
require
|
48
|
+
require 'vagrant_ssh_config_manager/action/up'
|
47
49
|
hook.after(Vagrant::Action::Builtin::Resume, Action::Up)
|
48
50
|
end
|
49
51
|
|
50
52
|
action_hook(:ssh_config_manager, :machine_action_provision) do |hook|
|
51
|
-
require
|
53
|
+
require 'vagrant_ssh_config_manager/action/provision'
|
52
54
|
hook.after(Vagrant::Action::Builtin::Provision, Action::Provision)
|
53
55
|
end
|
54
56
|
end
|