On Github PotHix / presentation-rubyconf2013
a.k.a PotHix
on the past 3 years
for both technical and product sides
with a python example
vm_ref = session.VM.get_by_uuid(virtual_machine.uuid) vm_vbds_refs = session.VM.get_record(vm_ref)["VBDs"] disks = vm_vbds_refs.inject({}) do |disks, vm_vbd_ref| vm_vbd_record = session.VBD.get_record(vm_vbd_ref) if vm_vbd_record["type"] == "Disk" disks[vm_vbd_ref] = vm_vbd_record end disks
reference: Xenserver API documentation
# Get all disks for a VM disks = virtual_machine.vbds
But the XenAPI way is still valid
One pool, one firewall (providing NAT) and one DHCP server
XMPP, ActiveMQ (+ Stomp), Resque
require "consumers/resque/configuration" module Resque class Consumer class << self def queue(name) @queue = name end ...
app/consumers/resque/consumer.rb
require 'xmpp4r' module XMPP class Consumer class << self attr_reader :queue_name, :queued_process, :timeout_value def queue(name) @queue_name = "#{name}@localhost" end ...
app/consumers/xmpp/consumer.rb
# -*- coding: UTF-8 -*- Consumer = Resque::Consumer
app/consumers/consumer.rb
BTW
process :of => :install do must_be :machine_created transition :select_ips, :from => :machine_created, :to => :ips_selected transition :queue_dhcp_for_install, :from => :ips_selected, :to => :dhcp_synchronized ...
module InstallSteps def select_ips log_activity(:info, :id => id, :status => 'starting') create_ip(primary=true) unless primary_ip_pair log_activity(:info, :id => id, :status => 'done') end def queue_dhcp_for_install ... end
app/steps/install_steps.rb
A different app to handle these
isc-dhcp
# cpro0007 host 3ea808bd-5ef0-4227-a617-f5b0694e408c{ hardware ethernet 00:25:22:bd:d1:20; fixed-address 186.202.1.7; option host-name "cpro0007"; } # cpro0051 host 3ea808bd-5ef0-4227-a617-cf5b0694e408 { hardware ethernet 00:25:22:bd:d1:21; fixed-address 186.202.1.8; option host-name "cpro0051"; }
<% vms.each do |vm| %> # <%= vm.name %> host <%= vm.uuid %> { hardware ethernet <%= vm.mac %>; fixed-address <%= vm.private_ip.address %>; option host-name \"<%= vm.name %>\"; } <% end %>
# Prepare isc dhcp file echo -e "<%= dhcp_config %>" > /etc/dhcp/<%= Config[:dhcp_conf_file] %> # Restart DHCP sudo /etc/init.d/isc-dhcp-server restart
Net::SSH.start(@host, @user, ssh_options) do |ssh| ssh_result = ssh.open_channel do |channel| channel.request_pty do |chn, success| raise "Could not obtain pty from ssh" unless success chn[:out] = "" chn.exec command ...
default DROP
iptables -A <%= internal_address %>/32 \ -p <%= rule.filter_protocol %> \ -s <%= rule.filter_address %> \ -d <%= internal_address %> \ --dport <%= rule.filter_port %> \ -j ACCEPT
# Configuring NAT ... iptables -t nat -A PREROUTING -d <%= rule.external_address %> \ -j DNAT --to-destination <%= rule.internal_address %> iptables -t nat -A POSTROUTING -s <%= rule.internal_address %> \ -j SNAT --to-source <%= rule.external_address %> ...
Provided by Xen VNC Proxy (a.k.a XVP)
POOL XENSERVERPOOL1 DOMAIN "" MANAGER root proxy_password_encrypted_hash HOST 10.20.30.40 VM 7890 4344dc8f-1bdd-4b65-812a-a0dc9b27256e console1_encrypted_pass VM 7891 c5b2d28e-4c11-492f-9d09-33670876cb4a console2_encrypted_pass
# for hosts /bin/echo -e "proxy_password_here" | /usr/sbin/xvp -x # for each console /bin/echo -e "console_password_here" | /usr/sbin/xvp -e
def encrypt_vnc(password) key = [0xc1, 0x24, 0x08, 0x99, 0xc2, 0x26, 0x07, 0x05] des = OpenSSL::Cipher::Cipher.new("des-ecb") des.key = key.map(&:chr).join des.encrypt des.update(password).unpack('H*').first end
coisa linda!
VM already shipped by Xen
Specialized post install
def post_installers { :windows2003 => PostInstall::Windows, :windows2008 => PostInstall::Windows, :linux => PostInstall::Linux } end ... def post_install post_installers[code.to_sym].new end
centos5, centos6, ubuntu9.04, ubuntu9.10, ubuntu10.04, ubuntu10.10, debian5, debian6, windows2003, ...
linux + cpanel, linux + plesk, windows + plesk, ...
SSH and bash scripts
Winrm and powershell scripts
production ready
"all your pools are belong to us"
and their maintenance
not so well documented
def export(vm_uuid, options = {}) options = {:to => "/tmp/export_file"}.merge(options) file = File.open(options[:to], "wb") session_ref = self.key task_ref = self.task.create "export vm #{vm_uuid}", "export job" path = "/export?session_id=#{session_ref} ... " uri = URI.parse "http://#{master_address}#{path}" Net::HTTP.get_response(uri) do |res| res.read_body {|chunk| file.write chunk } end options[:to] ensure file.close rescue nil self.task.destroy(task_ref) rescue nil end
or...datasets!
avoiding package overflow
by improving the infrastructure
dedicated servers for firewall and dhcp
Queueing and consuming using RabbitMQ
KVM, VMware
# Old xenapi code session.VM.get_by_uuid(virtual_machine.uuid) # Simplestack pool.on_simplestack.guests.find(virtual_machine.uuid)
Using ruby simplestack client
driven by monitoring
require 'blather/client' DaemonKit::Application.running! message :chat?, :body do |m| begin if Weatherman::Message.should_process?(m) message = JSON.parse(m.body, :allow_nan => true)["results"] unless message["event"].nil? Weatherman::Message.process(message["event"]) end end rescue => e DaemonKit.logger.error "Invalid message #{m.body}" DaemonKit.logger.error e.backtrace end end
new features and support for all versions!
# -*- coding: UTF-8 -*- module Network module Manager extend self def for(pool) pool.network_version.constantize.new end end end
# -*- coding: UTF-8 -*- module Network class Ver1 def internal_vlan? true end def installation_ip(vm) vm.public_ip.address end end end
# -*- coding: UTF-8 -*- module Network class Ver2 def internal_vlan? false end def installation_ip(vm) vm.on_simplestack.ip end end end