From 4f43446eefd1502917050b89de26f0ba2bed1bb5 Mon Sep 17 00:00:00 2001 From: deflax Date: Fri, 27 Oct 2017 18:17:01 +0300 Subject: [PATCH] phyidgen function --- grid.py | 33 +++++++++-- plugin.py | 145 ++++++++++++++++++++++++++++------------------- requirements.txt | 1 - 3 files changed, 114 insertions(+), 65 deletions(-) diff --git a/grid.py b/grid.py index 38c6800..129570c 100644 --- a/grid.py +++ b/grid.py @@ -8,7 +8,6 @@ import json import re import datetime import random -import netaddr import os #import local packages @@ -33,7 +32,7 @@ def read(data): dbf = open(dbfile, 'r') data = json.load(dbf) dbf.close() - logger.info('{}> --> {}'.format(dbfile, data)) + logger.info('grid> --> {}'.format(dbfile)) return data except Exception as e: logger.critical('{}> '.format(e)) @@ -47,7 +46,7 @@ def create(json): dbf = open(dbfile, 'w') json.dump(data, dbf) dbf.close() - logger.info('grid> {} --> {}'.format(data, dbfile)) + logger.info('grid> <-- {}'.format(data)) return data except Exception as e: logger.critical('grid> {}'.format(e)) @@ -61,6 +60,29 @@ def delete(unit_type, unit_id): os.remove(dbfile) return None +def phyidgen(slave_name, unit_type): + """ scans all current db files and generate new id within a range between 1000 and 9999, and avoid any duplicates """ + full_list = list(range(1000,10000)) + exclude_list = [] + directory = 'db/' + for dbfile in os.listdir(directory): + filename = os.fsdecode(dbfile) + if filename.startswith(str(unit_type)): + db_fullpath = os.path.join(directory, filename) + dbf = open(db_fullpath, 'r') + data = json.load(dbf) + if data['slave'] == str(slave_name): + exclude_list.append(data['phyid']) + dbf.close() + valid_list = list(set(full_list) - set(exclude_list)) + if len(valid_list) > 1: + choice = random.choice(valid_list) + logger.info('grid> physical id generated: {}'.format(choice)) + return choice + else: + logger.critical('grid> no free physical ids!') + return none + def analyze_happiness(region_id): """ analyzes grid data for the reuqested region and returns proposed slave_id, based on a "happiness" factor. happiness means alive and free :) """ @@ -148,7 +170,7 @@ def generate_ipv4(region_name, how_many=1): ip_range_min = ioconfig.parser.get(str(region_name), 'ipv4_min') ip_range_max = ioconfig.parser.get(str(region_name), 'ipv4_max') - region_ipset = netaddr.IPSet(netaddr.IPRange(ip_range_min, ip_range_max)) + #region_ipset = netaddr.IPSet(netaddr.IPRange(ip_range_min, ip_range_max)) region_ips = [] for ip in region_ipset: region_ips.append(ip) @@ -331,9 +353,8 @@ def sync(cached=True): if __name__ == '__main__': - print(sync()) #print(query_happiness(0)) #print(generate_ipv4(0,3)) #print(generate_vmid()) - print(queryvm(147344)) + print(phyidgen('warrior', 'kvm')) diff --git a/plugin.py b/plugin.py index 7acd00f..a5c3c34 100644 --- a/plugin.py +++ b/plugin.py @@ -1,7 +1,6 @@ #. -*- coding: utf-8 - # required proxmox permissions: PVEAdmin # -# afx 2015-2017 # site from proxmoxer import ProxmoxAPI @@ -32,29 +31,31 @@ def auth(slave_name): def create(json): """ create an unit. returns JSON with data """ try: - region_id = ioconfig.parser.get(str(json['region']), 'regionid') - region_fullname = ioconfig.parser.get(str(json['region']), 'fullname') + region_name = json['region'] + region_id = ioconfig.parser.get(region_name, 'regionid') + region_fullname = ioconfig.parser.get(region_name, 'fullname') except: ioconfig.logger.error('grid> region not found') return None - vm_name_utf8 = json['hostname'] - vm_name = unidecode(vm_name_utf8) + try: - vm_pass = json['rootpass'] - except: - vm_pass = '!%%^)@&&(K3B' - #slave_name = str(grid.query_happiness(region_id, weight)) #TODO: provide weight parameters here and calculate route - #slave_name = 'lexx' - slave_name = 'warrior' - - unit_id = int(time.time() * 10000 * 10000) - phy_id = grid.phyidgen(json['type']) + slave_name = json['slave'] + except Exception as e: + ioconfig.logger.warning('grid> slave not predefined. I will query for a capable one.') + #slave_name = str(grid.query_happiness(region_id, weight)) + #slave_name = 'lexx' + slave_name = 'warrior' + ioconfig.logger.info('grid> slave [{}] selected'.format(slave_name)) proxobject = auth(slave_name) real_slave_name = proxobject.cluster.status.get()[0]['name'] - description = vm_name + ' (' + str(unit_id) + '-' + str(phy_id) + ')\n' + 'owned by ' + json['clientemail'] + ' (' + json['clientid'] + ')\n' - - if json['type'] == 'deploy': - #create partition + + unit_id = int(time.time() * 10000 * 10000) #currently unit_id is just a timestamp + phy_id = grid.phyidgen(slave_name, json['type']) + description = ' (' + str(unit_id) + ' - ' + str(phy_id) + ')\n' + 'owned by ' + json['clientemail'] + ' (' + json['clientid'] + ')\n' + + if json['type'] == 'kvm': + vm_name_utf8 = json['hostname'] + vm_name = unidecode(vm_name_utf8) image_name = 'vm-' + str(phy_id) + '-disk-1' try: local_storage = proxobject.nodes(real_slave_name).storage('lvm') @@ -62,69 +63,95 @@ def create(json): ioconfig.logger.info('%s[%s]> allocated %s as %s' % (json['clientemail'], slave_name, json['hdd'], image_name)) except: ioconfig.logger.info('%s[%s]> unable to allocate %s' % (json['clientemail'], slave_name, image_name)) - response = { 'status':'FAIL' } + response = { 'status':'vol_alloc_failed' } return response - - create_result = proxobject.nodes(real_slave_name).qemu.post(vmid=int(phy_id), - name=vm_name, - onboot=1, - sockets=1, - cores=json['cpu'], - memory=json['mem'], - scsihw='virtio-scsi-pci', - scsi0='file=lvm:' + image_name + ',discard=on', - description=description) + try: + create_result = proxobject.nodes(real_slave_name).qemu.post(vmid=int(phy_id), + name=vm_name, + onboot=1, + sockets=1, + cores=json['cpu'], + memory=json['mem'], + scsihw='virtio-scsi-pci', + scsi0='file=lvm:' + image_name + ',discard=on', + description=description) + except: + return { 'status': 'kvm_create_failed' } data = { 'unit_id': int(unit_id), 'type': 'kvm', 'clientid': json['clientid'], 'clientemail': json['clientemail'], 'hostname': vm_name, - 'region': region_fullname, + 'region': region_name, 'slave': slave_name, - 'phyid': phy_id + 'phyid': phy_id, + 'net0if': json['net0if'] } - response = { 'status': 'deploy_created', 'unit_id': unit_id, 'hostname': vm_name, 'password': vm_pass, 'slave': real_slave_name } + grid.create(data) + response = { 'status': 'kvm_created', 'unit_id': unit_id, 'hostname': vm_name, 'region': region_name, 'slave': real_slave_name } - if json['type'] == 'router': - create_result = proxobject.nodes(real_slave_name).lxc.post(vmid=int(phy_id), - hostname=vm_name, - onboot=1, - unprivileged=1, - password=vm_pass, - cores=json['cpu'], - memory=json['mem'], - net0='name=eth0,bridge=' + json['bridge_id'] + ',gw=' + json['region_gw'] + ',hwaddr=' + json['macaddr'] + ',ip=' + json['ipv4addr'] + '/' + json['region_netmask'], - ostemplate='backup:vztmpl/debian-9.0-standard_9.0-2_amd64.tar.gz', - rootfs='volume=lvm:' + image_name, - swap=32, - description=description) + if json['type'] == 'lxc': + vm_name_utf8 = json['hostname'] + vm_name = unidecode(vm_name_utf8) + image_name = 'vm-' + str(phy_id) + '-disk-1' + try: + local_storage = proxobject.nodes(real_slave_name).storage('lvm') + storage_create_result = local_storage.content.post(vmid=phy_id, filename=image_name, size=json['hdd'] + 'G') + ioconfig.logger.info('%s[%s]> allocated %s as %s' % (json['clientemail'], slave_name, json['hdd'], image_name)) + except: + ioconfig.logger.info('%s[%s]> unable to allocate %s' % (json['clientemail'], slave_name, image_name)) + response = { 'status':'vol_alloc_failed' } + return response + try: + vm_pass = json['rootpass'] + except: + vm_pass = '!%%^)@&&(K3B' + try: + create_result = proxobject.nodes(real_slave_name).lxc.post(vmid=int(phy_id), + hostname=vm_name, + onboot=1, + unprivileged=1, + password=vm_pass, + cores=json['cpu'], + memory=json['mem'], + net0='name=eth0,bridge=' + json['net0if'] + ',gw=' + json['region_gw'] + ',hwaddr=' + json['macaddr'] + ',ip=' + json['ipv4addr'] + '/' + json['region_netmask'], + ostemplate='backup:vztmpl/debian-9.0-standard_9.0-2_amd64.tar.gz', + rootfs='volume=lvm:' + image_name, + swap=32, + description=description) + except: + return { 'status': 'lxc_create_failed' } data = { 'unit_id': int(unit_id), 'type': 'lxc', 'clientid': json['clientid'], 'clientemail': json['clientemail'], 'hostname': vm_name, - 'region': region_fullname, + 'region': region_name, 'slave': slave_name, - 'phyid': phy_id + 'phyid': phy_id, + 'net0if': json['net0if'] } - response = { 'status': 'router_created', 'unit_id': unit_id, 'hostname': vm_name, 'password': vm_pass, 'slave': real_slave_name } + grid.create(data) + response = { 'status': 'lxc_created', 'unit_id': unit_id, 'hostname': vm_name, 'region': region_name, 'slave': real_slave_name } - - if json['type'] == 'bridge': + if json['type'] == 'br': + try: + create_result = proxobject.nodes(real_slave_name).network.post(iface='vmbr' + int(phy_id), + type='bridge', + autostart=1) + except: + return { 'status': 'br_create_failed' } data = { 'unit_id': int(unit_id), - 'type': 'vmbr', + 'type': 'br', 'clientid': json['clientid'], 'clientemail': json['clientemail'], - 'region': region_fullname, + 'region': region_name, 'slave': slave_name, 'phyid': phy_id } - #TODO: CREATE BRIDGE - response = { 'status': 'bridge_created', 'unit_id': unit_id, 'hostname': vm_name, 'password': vm_pass, 'slave': real_slave_name } + grid.create(data) + response = { 'status': 'bridge_created', 'unit_id': unit_id, 'region': region_name, 'slave': real_slave_name, 'phyid': phy_id } - time.sleep(7) #wait few seconds for the slave to prepare the machine for initial run - - grid.create(data) return response def remove(json): @@ -144,7 +171,9 @@ def remove(json): def query(json): """ return the db info of an unit """ - return grid.query(json) + query = grid.query(json) + query['status'] = 'query_success' + return query def status(json): """ returns the status of an unit """ diff --git a/requirements.txt b/requirements.txt index 1618cd9..3f6c558 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,6 @@ uwsgi pyOpenSSL requests falcon -netaddr proxmoxer proxmox-deploy websockify