diff --git a/ovhtool.py b/ovhtool.py index f70700b..fcdb4cb 100644 --- a/ovhtool.py +++ b/ovhtool.py @@ -11,9 +11,10 @@ import logging logger = logging.getLogger(__name__) logging.basicConfig(level=logging.DEBUG) +import os +import re import ovh -import json -from collections import namedtuple +import netaddr from docopt import docopt try: @@ -35,6 +36,30 @@ class OVHIP(object): def __repr__(self): return ''.format(self) +def parse_ovhrc(fd): + config = {} + + for l in fd: + if l.strip().startswith('#'): + continue + try: + key, value = re.match('(.*)="(.*)"', l).groups() + config[key] = value + except: + logging.debug('Invalid config line: %r', l, exc_info=True) + + return config + +def server_detect(client): + ovhrc_path = os.path.expanduser('~/.ovhrc') + + if os.path.exists(ovhrc_path): + with open(ovhrc_path) as fd: + ovhrc = parse_ovhrc(fd) + return ovhrc['SERVERNAME'] + + return client.get('/dedicated/server')[0] + def list_ips(server=None, client=None): domains = {} @@ -51,13 +76,16 @@ def list_ips(server=None, client=None): domains[mac.lower()] = domain client = client or ovh.Client() + if not server: - server = client.get('/dedicated/server')[0] + server = server_detect(client) - ips = client.get('/ip?routedTo.serviceName=%s&type=failover' % server) + ips = {} + + for net in client.get('/ip?routedTo.serviceName=%s&type=failover' % server): + for addr in netaddr.IPNetwork(net): + ips[str(addr)] = OVHIP(str(addr), None, None) - # TODO: IP ranges - ips = {v.split('/')[0]: OVHIP(v.split('/')[0], None, None) for v in ips} macs = client.get('/dedicated/server/%s/virtualMac' % server) for mac in macs: diff --git a/vm.py b/vm.py index 8faaff0..984a666 100755 --- a/vm.py +++ b/vm.py @@ -4,6 +4,8 @@ usage: vm [--version] [--help] [...] Available commands are: create Create new VM from cloud image + ip:list List available OVH IPs + ip:sync Create missing vMACs for OVH IPs """ from __future__ import print_function @@ -225,8 +227,42 @@ Password: {0.password}'''.format(instance)) subprocess.call(['ping', '-c', '1', instance.ip]) +def cmd_iplist(args): + '''usage: vm ip:list + +List available OVH IPs +''' + ips = ovhtool.list_ips() + for _, ip in ips.items(): + hostname = ip.domain.name() if ip.domain else '' + print('%15s | %17s | %s' % (ip.ip, ip.mac, hostname)) + +def cmd_ipsync(args): + '''usage: vm ip:sync + +Create missing vMACs for available IPs +''' + client = ovh.Client() + server = ovhtool.server_detect(client) + ips = ovhtool.list_ips(client=client) + for ip in ips.values(): + if ip.mac is None: + try: + logger.info('Missing MAC for %s, creating', ip.ip) + resp = client.post('/dedicated/server/%s/virtualMac' % + (server,), + ipAddress=ip.ip, type='ovh', + virtualMachineName='vm') + logger.info('Result: %r', resp) + except: + logger.exception('Failed!') + + + commands = { 'create': cmd_create, + 'ip:list': cmd_iplist, + 'ip:sync': cmd_ipsync, } def main(gargv): @@ -252,9 +288,7 @@ if __name__ == '__main__': {'method': 'POST', 'path': '/dedicated/server/*/virtualMac'}, ]) - print('********\n\tNo valid OVH consumer_key, click this URL:\n\t' - '{0.validationUrl}\n\tand copy this consumer_key to ovh.conf: ' - '{0.consumerKey}\n********'.format(req), file=sys.stderr) + print(req, file=sys.stderr) exit(1) except CommandException as exc: