Skip to content

Instantly share code, notes, and snippets.

@jingkaihe
Last active October 15, 2017 22:11
Show Gist options
  • Save jingkaihe/e2cfb49fb238cdaa761497335d43b122 to your computer and use it in GitHub Desktop.
Save jingkaihe/e2cfb49fb238cdaa761497335d43b122 to your computer and use it in GitHub Desktop.
Poor boy's terraform ⚠️ only works on SmartOS. ATM only supports native container (SmartOS & LX brand) provisioning & bootstrapping. You can provision KVM, however you can't run cmd against it
#!/usr/bin/env ruby
require "pty"
require 'optparse'
$stdout.sync = true
$stderr.sync = true
class Hypervisor
attr_accessor :admin, :addr
def self.parse!(args)
new.tap do |hypervisor|
OptionParser.new do |opts|
opts.banner = "Usage: vm_sync [options] provision|destroy vm1 vm2 vm3..."
opts.on("-a", "--admin admin", "hypervisor admin running the command") do |admin|
hypervisor.admin = admin
end
opts.on("-h", "--addr addr", "hypervisor address to connect to") do |addr|
hypervisor.addr = addr
end
opts.on("-c", "--config config.yml", "hypervisor configuration") do |cf|
require "yaml"
YAML.load_file(cf).tap do |config|
hypervisor.admin = admin = config["admin"]
hypervisor.addr = config["addr"]
end
end
end.parse!(args)
end
end
def rpc_addr
"#{admin}@#{addr}"
end
def pty_spawn(*cmd, &block)
spawn_cmd = "ssh #{rpc_addr} #{cmd.join(" ")}"
process_line("Execute #{spawn_cmd.inspect}...", &block)
PTY.spawn(spawn_cmd) do |out, _in, _pid|
begin
while line = out.gets
process_line(line, &block)
end
rescue Errno::EIO
end
end
rescue PTY::ChildExited
process_line("#{spawn_cmd.inspect} finished", &block)
end
def run(*cmd)
`ssh #{rpc_addr} #{cmd.join(" ")}`
end
private
def process_line(line)
if block_given?
yield(line)
else
puts(line)
end
end
end
hypervisor = Hypervisor.parse!(ARGV)
class VM
attr_reader :name, :hypervisor
def initialize(name, hypervisor:)
@name = name
@hypervisor = hypervisor
end
def manifest
"#{name}.json"
end
def manifest_path
File.join File.dirname(__FILE__), manifest
end
def remote_path
"/tmp/#{manifest}"
end
def exist?
File.exist?(manifest_path)
end
def zlogin_exec(*cmd)
hypervisor.pty_spawn("zlogin", uuid, *cmd) do |line|
vmputs(line)
end
end
def provision
vmputs "provisioning..."
`scp #{manifest_path} #{hypervisor.rpc_addr}:#{remote_path}`
hypervisor.run("vmadm create -f #{remote_path}")
end
def provisioned?
uuid != ""
end
def uuid
hypervisor.run("vmadm list -Ho uuid alias=#{name}").chomp
end
def destroy
vmputs "Delete #{uuid}..."
hypervisor.run("vmadm delete #{uuid}")
end
def vmputs(line)
puts "[#{name}] #{line}"
end
end
class VMS
attr_reader :vms
def initialize(*names, hypervisor:)
@vms = names.map do |name|
VM.new(name, hypervisor: hypervisor)
end
end
def provision_each
parallel_each do |vm|
vm.provision unless vm.provisioned?
yield(vm) if block_given?
end
end
def destroy_all
parallel_each { |vm| vm.destroy }
end
def parallel_each
vms.each do |vm|
fork do
yield(vm)
end
end
Process.waitall
end
end
action = ARGV.shift
vm_names = ARGV
vms = VMS.new(*vm_names, hypervisor: hypervisor)
case action
when "provision"
vms.provision_each do |vm|
[
"apt-get -y update",
"DEBIAN_FRONTEND=noninteractive apt-get -y upgrade",
"apt-get -y install puppet",
].each do |cmd|
vm.zlogin_exec(cmd)
end
end
when "destroy"
vms.destroy_all
when "rpc"
hypervisor.pty_spawn(*ARGV)
else
$stderr.puts "Support provision|destroy|rpc"
exit 1
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment