Created
March 1, 2018 00:24
-
-
Save vholer/9e970de996a6f271b622359f41d3b1ae to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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