Skip to content

Instantly share code, notes, and snippets.

@vholer
Created March 1, 2018 00:24
Show Gist options
  • Save vholer/9e970de996a6f271b622359f41d3b1ae to your computer and use it in GitHub Desktop.
Save vholer/9e970de996a6f271b622359f41d3b1ae to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
ONE_LOCATION=ENV["ONE_LOCATION"]
if !ONE_LOCATION
RUBY_LIB_LOCATION="/usr/lib/one/ruby"
VMDIR="/var/lib/one"
CONFIG_FILE="/var/lib/one/config"
else
RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby"
VMDIR=ONE_LOCATION+"/var"
CONFIG_FILE=ONE_LOCATION+"/var/config"
end
$: << RUBY_LIB_LOCATION
require 'getoptlong'
require 'opennebula'
include OpenNebula
################################################################################
# Options
################################################################################
mode = nil
wait = false
opts = GetoptLong.new(
['--update', '-u', GetoptLong::NO_ARGUMENT],
['--delete', '-d', GetoptLong::NO_ARGUMENT],
['--wait-running', '-w', GetoptLong::NO_ARGUMENT],
)
begin
opts.each do |opt, arg|
case opt
when '--update'
mode = :update
when '--delete'
mode = :delete
when '--wait-running'
wait = true
end
end
rescue Exception => e
STDERR.puts e.to_s
exit(-1)
end
VM_ID = ARGV[0]
if mode.nil? or VM_ID.nil?
STDERR.puts "Missing update mode or virtual machine ID"
exit(-1)
end
################################################################################
# Methods
################################################################################
def fetch(type, id, client)
object = type.new_with_id(id, client)
rc = object.info
if OpenNebula.is_error?(rc)
STDERR.puts rc.message
exit(-1)
end
object
end
def dyndns_update(mode, endpoint, user, token, hostname, ip=nil)
params = {
:system => 'dyndns',
:hostname => hostname
}
if mode == :update and ip
params[:myip] = ip
else
params[:offline] = 'yes'
end
uri = URI("#{endpoint}/nic/update")
uri.query = URI.encode_www_form(params)
req = Net::HTTP::Get.new(uri)
req.basic_auth user, token
res = Net::HTTP.start(uri.hostname, uri.port, :use_ssl => true) {|http|
http.request(req)
}
if res.is_a?(Net::HTTPSuccess)
res.body =~ /^(nochg|good)/
else
STDERR.puts "DynDNS failure: #{res.message}"
exit(-1)
end
end
def get_dyndns_vnet(vm, client)
vm.each('/VM/TEMPLATE/NIC') do |nic|
next unless nic['IP']
vnet = fetch(OpenNebula::VirtualNetwork, nic['NETWORK_ID'], client)
if vnet['/VNET/TEMPLATE/DYNDNS_DOMAIN'] &&
vnet['/VNET/TEMPLATE/DYNDNS_ENDPOINT']
then
return vnet, nic['IP']
end
end
if vm['/VM/USER_TEMPLATE/DYNDNS_NETWORK_ID']
vnet = fetch(OpenNebula::VirtualNetwork, vm['/VM/USER_TEMPLATE/DYNDNS_NETWORK_ID'], client)
if vnet['/VNET/TEMPLATE/DYNDNS_DOMAIN'] &&
vnet['/VNET/TEMPLATE/DYNDNS_ENDPOINT']
then
return vnet
end
end
nil
end
################################################################################
# Main
################################################################################
begin
client = Client.new()
rescue Exception => e
STDERR.puts e.to_s
exit(-1)
end
# Retrieve virtual machine
vm = fetch(OpenNebula::VirtualMachine, VM_ID, client)
if wait
10.times do
break if vm.lcm_state_str() == 'RUNNING'
sleep 2
rc = vm.info()
if OpenNebula.is_error?(rc)
STDERR.puts rc.message
exit(-1)
end
end
if vm.lcm_state_str() != 'RUNNING'
STDERR.puts "Timed out when waiting for RUNNING state"
exit(-1)
end
end
# Check if we have valid hostname to set
hostname = vm['/VM/USER_TEMPLATE/HOSTNAME']
if hostname.nil?
STDERR.puts "Nothing to do, missing template HOSTNAME"
exit
end
hostname.strip!
unless hostname =~ /\A[a-z0-9_-]+\z/i
STDERR.puts "Invalid HOSTNAME"
exit(-1)
end
# Get user token
user = fetch(OpenNebula::User, vm['UID'], client)
uname = user['/USER/NAME']
token = user['/USER/TEMPLATE/TOKEN_PASSWORD']
if token.nil?
STDERR.puts "Missing user's token"
exit(-1)
end
# Find first vnet with DynDNS configuration
vnet, ip = get_dyndns_vnet(vm, client)
if vnet
domain = vnet['/VNET/TEMPLATE/DYNDNS_DOMAIN']
endpoint = vnet['/VNET/TEMPLATE/DYNDNS_ENDPOINT']
fqdn = "#{hostname}.#{uname}.#{domain}"
res = dyndns_update(mode, endpoint, uname, token, fqdn, ip)
if res
if mode == :update and ip
# save netork ID for future use
vm.update("DYNDNS_NETWORK_ID=#{vnet['ID']}", true)
STDOUT.puts "Dynamic hostname '#{fqdn}' updated with #{ip}"
else
STDOUT.puts "Dynamic hostname '#{fqdn}' cleaned"
end
exit(0)
else
STDERR.puts "Dynamic hostname '#{fqdn}' update failed"
exit(-1)
end
end
puts "Nothing to update"
exit(0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment