fi
done
;;
+ renumber)
+ shift; shift;
+ curip="$1"
+ curgw="$2"
+ newip="$3"
+ newgw="$4"
+ xs_prefix="/local/domain/0/backend/vif"
+ domid=`xm domid $MACHINE`
+ renumbered=
+ for vif in `xenstore-list $xs_prefix/$domid`; do
+ ip=`xenstore-read $xs_prefix/$domid/$vif/ip`
+ if [ $ip == $curip ]; then
+ script=`xenstore-read $xs_prefix/$domid/$vif/script`
+ # If the domain is rebooted without a full shutdown, the
+ # invirt-database script doesn't run to fill in arguments for
+ # vif-invirtroute, so we need to rewrite it as if it had
+ # been booted with the IP parameters swapped.
+ script=`echo $script | sed -ne "s/\(.* netdev=[^ ]*\).*/\1 gateway=$newgw other_ip=$curip other_gateway=$curgw/p"`
+ # The sed above will only print something if we matched. If
+ # the content of the script key wasn't as we expected, don't
+ # mess with it.
+ if [ -n "$script" ]; then
+ xenstore-write $xs_prefix/$domid/$vif/script "$script"
+ echo "'$ORIGMACHINE' has been configured to renumber $curip to $newip if it is rebooted without being powered off."
+ renumbered=yes
+ fi
+ fi
+ done
+ if [ -n "$renumbered" ]; then
+ echo "XVM's DNS server has been updated with your new address information."
+ echo "You MUST reboot your VM immediately in order for it to respond properly"
+ echo "to the old and new addresses."
+ fi
+ ;;
*)
echo "ERROR: Invalid Command"
exit 34
"""
from subprocess import PIPE, Popen, call
+from invirt.database import connect, session, models
import sys
import yaml
machine_name = argv[1]
command = argv[2]
+ renumber = []
+ if command == 'renumber':
+ connect()
+ machine = models.Machine.query.filter_by(name=machine_name).one()
+ for n in machine.nics:
+ if n.other_action and n.other_action == 'renumber_dhcp':
+ renumber.append((n.ip, n.gateway, n.other_ip, n.other_gateway))
+ print "IP %s is set to be renumbered to %s the next time '%s' is powered on." % (n.ip, n.other_ip, machine_name)
+ # We have to switch this now; we can't simply change to the
+ # 'renumber' state, because that will only work if the machine
+ # is turned off fully and then turned back on. A reboot will
+ # only run vif-invirtroute, not invirt-database, so we need
+ # to edit the vif-invirtroute script parameters in xenstore
+ # if the machine is on. That's why we have just saved a
+ # tuple of parameters, which we will pass to a host-based
+ # remctl if the machine is actually on (further below in this
+ # script). As a consequence of us swapping this now, DNS
+ # will change when the user runs this remctl, so if the machine
+ # is on, they will need to reboot it promptly to begin
+ # responding to the new address. We don't know if it's on
+ # yet, or if we'll succeed in editing the script. The
+ # remctl from the host will warn them to reboot immediately
+ # if successful.
+ (n.ip, n.netmask, n.gateway,
+ n.other_ip, n.other_netmask, n.other_gateway, n.other_action) = (
+ n.other_ip, n.other_netmask, n.other_gateway,
+ n.ip, n.netmask, n.gateway, 'dnat')
+ session.add(n)
+ session.flush()
+ else:
+ print 'IP %s is not currently slated to be renumbered.' % (n.ip)
+ if not renumber:
+ print >>sys.stderr, "machine '%s' is not currently slated to be renumbered" % (machine_name)
+ return 1
p = Popen(['/usr/sbin/invirt-remote-proxy-web', 'listvms'], stdout=PIPE)
output = p.communicate()[0]
if p.returncode != 0:
vms = yaml.load(output, yaml.CSafeLoader)
if machine_name not in vms:
+ if renumber:
+ # It's okay for the machine not to be on with the 'renumber'
+ # remctl. There's a DB component of the work (completed above)
+ # and an adjustment to make to the machine if it happens to be on.
+ return 0
print >>sys.stderr, "machine '%s' is not on" % machine_name
return 1
host = vms[machine_name]['host']
+ if renumber:
+ # We need to pass parameters from the database that the remctl script
+ # on the host where the VM is running won't easily have access to, and
+ # we may need to do this for multiple NICs, so we'll do this in our
+ # own loop for the 'renumber' remctl, separate from the normal remote
+ # control code path.
+ for nicparams in renumber:
+ p = Popen(['remctl', host, 'remote', 'control'] + argv[1:] + list(nicparams),
+ stdout=PIPE, stderr=PIPE)
+ (out, err) = p.communicate()
+ if p.returncode == 1:
+ print >>sys.stderr, "machine '%s' is not on" % machine_name
+ return 1
+ sys.stderr.write(err)
+ sys.stdout.write(out)
+ return 0
+
p = Popen(['remctl', host, 'remote', 'control'] + argv[1:],
stdout=PIPE, stderr=PIPE)
(out, err) = p.communicate()