Class: LxDev::Main

Inherits:
Object
  • Object
show all
Defined in:
lib/lxdev/main.rb

Constant Summary collapse

WHITELISTED_SUDO_COMMANDS =
["lxc", "redir", "kill"]
SHELLS =
["bash", "zsh", "sh", "csh", "tcsh", "ash"]
BOOT_TIMEOUT =
30
VERSION =
'0.1.8'

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config_file, state_file) ⇒ Main

Returns a new instance of Main.



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/lxdev/main.rb', line 14

def initialize(config_file, state_file)
  @state_file = format(".lxdev/%s", state_file)
  @uid    = System.exec("id -u").output.chomp
  @gid    = System.exec("id -g").output.chomp
  @config = YAML.load_file(config_file)
  @name   = @config['box']['name']
  @image  = @config['box']['image']
  @user   = @config['box']['user']
  @ports  = @config['box']['ports'] || {}
  Dir.mkdir('.lxdev') unless File.directory?('.lxdev')
  begin
    @state = YAML.load_file(@state_file)
  rescue
    @state = Hash.new
  end
rescue Errno::ENOENT
  puts "#{config_file} not found"
  exit 1
end

Class Method Details

.setup(config_file = 'lxdev.yml', state_file = 'state') ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/lxdev/main.rb', line 34

def self.setup(config_file = 'lxdev.yml', state_file = 'state')
  self.check_requirements
  unless lxd_initialized?
    puts "Please run 'lxd init' and configure LXD first"
    return false
  end
  lxdev = Main.new(config_file, state_file)
  unless lxdev.set_ssh_keys
    puts "No ssh keys detected. Make sure you have an ssh key, a running agent, and the key added to the agent, e.g. with ssh-add."
    return false
  end
  return lxdev
end

Instance Method Details

#destroyObject



122
123
124
125
# File 'lib/lxdev/main.rb', line 122

def destroy
  ensure_container_created
  System.exec("sudo lxc delete #{@name}")
end

#execute(command, interactive: false) ⇒ Object



138
139
140
141
142
143
144
145
146
147
# File 'lib/lxdev/main.rb', line 138

def execute(command, interactive: false)
  if interactive
    exec("sudo lxc exec #{@name} #{command}") # execution stops here and gives control to exec
  end
  IO.popen("sudo lxc exec #{@name} -- /bin/sh -c '#{command}'", err: [:child, :out]) do |cmd_output|
    cmd_output.each do |line|
      puts line
    end
  end
end

#haltObject



115
116
117
118
119
120
# File 'lib/lxdev/main.rb', line 115

def halt
  ensure_container_created
  System.exec("sudo lxc stop #{@name}")
  cleanup_forwarded_ports
  remove_state
end

#provisionObject



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/lxdev/main.rb', line 149

def provision
  ensure_container_created
  if get_container_status.first['status'] != 'Running'
    puts "#{@name} is not running!"
    exit 1
  end
  provisioning = @config['box']['provisioning']
  if provisioning.nil?
    puts "Nothing to do"
    return
  end
  if @config['box']['auto_snapshots']
    snapshot_name = "provision_#{Time.now.to_i}"
    snapshot(snapshot_name)
  end
  puts "Provisioning #{@name}..."
  STDOUT.sync = true
  provisioning.each do |cmd|
    execute cmd
  end
  STDOUT.sync = false
end

#restore(snapshot_name) ⇒ Object



177
178
179
180
181
# File 'lib/lxdev/main.rb', line 177

def restore(snapshot_name)
  puts "Restoring snapshot #{snapshot_name}"
  exitstatus = System.exec("sudo lxc restore #{@name} #{snapshot_name}").exitstatus
  exitstatus == 0
end

#revertObject



189
190
191
192
193
194
195
196
197
# File 'lib/lxdev/main.rb', line 189

def revert
  snapshot      = get_container_status.first['snapshots'].last
  snapshot_name = snapshot['name'].partition('/').last
  if restore(snapshot_name)
    puts "Reverted to snapshot #{snapshot_name}"
    puts "Deleting snapshot"
    rmsnapshot(snapshot_name)
  end
end

#rmsnapshot(snapshot_name) ⇒ Object



183
184
185
186
187
# File 'lib/lxdev/main.rb', line 183

def rmsnapshot(snapshot_name)
  puts "Deleting snapshot #{snapshot_name}"
  exitstatus = System.exec("sudo lxc delete #{@name}/#{snapshot_name}").exitstatus
  exitstatus == 0
end

#save_stateObject



48
49
50
# File 'lib/lxdev/main.rb', line 48

def save_state
  File.open(@state_file, 'w') {|f| f.write @state.to_yaml} unless @state.empty?
end

#set_ssh_keysObject



52
53
54
55
56
57
58
59
# File 'lib/lxdev/main.rb', line 52

def set_ssh_keys
  ssh_keys = System.exec("ssh-add -L").output
  if ssh_keys[0..3] == 'ssh-'
    @ssh_keys = ssh_keys
  else
    nil
  end
end

#snapshot(snapshot_name) ⇒ Object



172
173
174
175
# File 'lib/lxdev/main.rb', line 172

def snapshot(snapshot_name)
  puts "Creating snapshot #{snapshot_name}"
  System.exec("sudo lxc snapshot #{@name} #{snapshot_name}")
end

#ssh(args) ⇒ Object



127
128
129
130
131
132
133
134
135
136
# File 'lib/lxdev/main.rb', line 127

def ssh(args)
  ensure_container_created
  host = get_container_ip
  if host.nil?
    puts "#{@name} doesn't seem to be running."
    exit 1
  end
  ssh_command = "ssh -o StrictHostKeyChecking=no -t #{@user}@#{get_container_ip} #{args.empty? ? '' : "'#{args.join(' ')}'"}"
  exec ssh_command
end

#statusObject



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/lxdev/main.rb', line 61

def status
  ensure_container_created

  container_status = get_container_status
  folders          = container_status.first['devices'].map {|name, folders| [name, "#{folders['source']} => #{folders['path']}"] if folders['source']}.compact
  table            = Terminal::Table.new do |t|
    t.add_row ['Name', container_status.first['name']]
    t.add_row ['Status', container_status.first['status']]
    t.add_row ['IP', get_container_ip]
    t.add_row ['Image', @image]
    t.add_separator
    folders.each do |folder|
      t.add_row folder
    end
    t.add_separator
    @ports.each do |guest, host|
      t.add_row ['Forwarded port', "guest: #{guest} host: #{host}"]
    end
    if container_status.first['snapshots'].any?
      t.add_separator
      t.add_row ['Snapshots', '']
    end
    container_status.first['snapshots'].each do |snapshot|
      t.add_row [snapshot['name'].partition('/').last, snapshot['created_at']]
    end
  end
  puts table
end

#upObject



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/lxdev/main.rb', line 90

def up
  do_provision = false
  unless @state.empty?
    puts "Container state #{@state_file} exists, is it running? If not it might have stopped unexpectedly. Please remove the file before starting."
    exit 1
  end
  if get_container_status.empty?
    create_container
    do_provision = true
  else
    if get_container_status.first['status'] == 'Running'
      puts "#{@name} is already running!"
      exit 1
    else
      start_container
    end
  end
  puts "Waiting for boot..."
  wait_for_boot
  @state['status'] = 'running'
  puts "Forwarding ports..."
  forward_ports(@ports)
  provision if do_provision
end