Skip to content

Instantly share code, notes, and snippets.

@chirauki
Last active January 21, 2019 11:09
Show Gist options
  • Save chirauki/a8c9dc382a544d42816ca3daf8c9d364 to your computer and use it in GitHub Desktop.
Save chirauki/a8c9dc382a544d42816ca3daf8c9d364 to your computer and use it in GitHub Desktop.
Capture script
#!/usr/bin/env ruby
require 'csv'
require 'trollop'
require 'rubygems'
require 'abiquo-api'
opts = Trollop::options do
opt :endpoint, "API endpoint", :type => :string
opt :username, "API username", :type => :string, :default => "admin"
opt :password, "API password", :type => :string, :default => "xabiquo"
opt :mode , "Authmode", :type => :string, :default => "basic"
opt :key , "API key", :type => :string
opt :secret , "API secret", :type => :string
opt :tkey , "Token key" , :type => :string
opt :tsecret , "Token secret", :type => :string
opt :file , "CVS file", :type => :string
end
Trollop::die :file, "must be provided" unless opts[:file]
Trollop::die :file, "must exists" unless File.exist?(opts[:file]) if opts[:file]
$vms = []
$client = case opts[:mode]
when "oauth" then
AbiquoAPI.new(
:connection_options => { :ssl => { :verify => false } },
:abiquo_api_url => opts[:endpoint],
:abiquo_api_key => opts[:key],
:abiquo_api_secret => opts[:secret],
:abiquo_token_key => opts[:tkey],
:abiquo_token_secret => opts[:tsecret])
else
AbiquoAPI.new(
:abiquo_api_url => opts[:endpoint],
:abiquo_username => opts[:username],
:abiquo_password => opts[:password])
end
def find(enum, name)
return enum.select {|o| o.name == name}.first
end
def link(href, accept)
AbiquoAPI::Link.new(
:href => href,
:type => "application/vnd.abiquo.#{accept}+json",
:client => $client)
end
# Capture a NOT_MANAGED VM
#
# This mimics the UI behavior as it is in Abiquo 3.6
#
# enterprise : Enterprise name the VM will be captured for
# vdatacenter : Virtual datacenter name the VM will be captured in
# vappliance : Virtual appliance name the VM will be captured in. It will be created if it doesn't not exist
# vmachine : Virtual machine name as reported by the HV
# nics : Network interfaces configuration in the form [VLAN0,ADDR0,...,VLANn,ADDRn]
# : VLANx must be the name of an existing network
# : ADDRx will be created if it doesn't not exist
def capture(enterprise, vdatacenter, vappliance, vmachine, nics)
# Validate enterprise
ent = find($enterprises, enterprise)
ent or raise "Enterprise not found"
# Validate vdc
vdc = find(link("#{ent.url}/action/virtualdatacenters", "virtualdatacenters").get, vdatacenter)
vdc or raise "Virtual datacenter not found"
# Validate VM
# 1 Find the VM in the VM list
# 2 Get the flat VM object with all nics
# 3 Verify the VM is not already managed
vm = find($vms, vmachine)
vm or raise "VM not found"
vm = vm.link(:virtualmachine).get(:sync => true, :accept => "application/vnd.abiquo.virtualmachineflat+json")
vm or raise "VM could not be synchronyzed"
vm.type == "NOT_MANAGED" or raise "VM is already managed"
# Validate vapp
unless vapp = find(vdc.link(:virtualappliances).get, vappliance)
puts "- Creating virtual appliance"
vapp = $client.post(vdc.link(:virtualappliances), {:name => vappliance},
:accept => "application/vnd.abiquo.virtualappliance+json",
:content => "application/vnd.abiquo.virtualappliance+json")
end
vapp or raise "Virtual appliance could not be created"
# Get networks
# This depends on the enterprise and the DC the VM is running in
dc = vm.link(:location).get.id
vlans = vdc.link(:privatenetworks).get.to_a
vlans += link(ent.url + "/action/publicnetworks", "vlans").get(:datacenterId => dc).to_a
vlans += link(ent.url + "/action/externalnetworks", "vlans").get(:datacenterId => dc).to_a
# Assign networks to each NIC
vm.nics["collection"].each_index do |n|
# Validate NIC data
nic = vm.nics["collection"][n]
network, address = nics[0], nics[1]
network and address or raise "Missing information for NIC #{n}"
# Validate network
vlan = find(vlans, network)
vlan or raise "Network #{network} not found"
# Validate IP
unless ip = vlan.link(:ips).get.select { |i| i.ip == address }.first
puts "- Creating IP #{address} in #{vlan.name}"
ip = $client.post(vlan.link(:ips), {
:ip => address,
:available => true,
:ipv6 => false,
:numips => 1,
:quarantine => false},
:content => "application/vnd.abiquo.ipsbulkcreation+json")
end
ip or raise "IP #{address} could not be created"
# Add nic configuration to VM nic
nic["ip"] = address
nic["links"] = [{
:title => vlan.name,
:href => vlan.url,
:type => "application/vnd.abiquo.vlan+json",
:rel => "vlan"}]
# Next interface
nics.shift(2)
end
# Insert imported link
link = vm.link(:edit)
link.rel = "imported"
vm.links.push({:imported => vm.link(:edit)})
# Capture VM
#vm = $client.post(link(vapp.link(:virtualmachines).href, "virtualmachineflat"), vm)
vm = $client.post(vapp.link(:virtualmachines), vm.to_json, :content => 'application/vnd.abiquo.virtualmachineflat+json',
:accept => 'application/vnd.abiquo.virtualmachineflat+json')
vm or raise "Could not capture VM"
end
puts "Retrieving platform information"
begin
$enterprises = link("/api/admin/enterprises", "enterprises").get
link("/api/admin/datacenters", "datacenters").get.each do |d|
d.link(:racks).get.each do |r|
r.link(:machines).get.each do |m|
$vms += m.link(:virtualmachines).get(:sync => true).to_a
end
end
end
rescue => e
puts "Could not retrieve platform information"
exit -1
end
puts "Retrieved platform information"
puts ""
# enterprise,vdc,vapp,vm,nic0_vlan,nic0_ip...nicN_vlan,nicN_ip
CSV.foreach(opts[:file]) do |row|
# Ignore empty lines and comments
next if row.length < 6 or row[0].start_with? '#'
# Start capture
puts "Capturing " + row[0..3].join(",")
# Validate input
row.size > 5 or raise "Incomplete row"
capture(row[0],row[1],row[2], row[3], row[4..-1])
puts "Captured " + row[0..3].join(",")
puts ""
end
puts "Finished capturing VMs"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment