def add(request, net, args): # Normal Response Code: 202 # Error Response Codes: computeFault (400, 500), # serviceUnavailable (503), # unauthorized (401), # badRequest (400), # buildInProgress (409), # badMediaType(415), # itemNotFound (404), # overLimit (413) if net.state != 'ACTIVE': raise faults.BuildInProgress('Network not active yet') server_id = args.get('serverRef', None) if not server_id: raise faults.BadRequest('Malformed Request.') vm = get_vm(server_id, request.user_uniq, non_suspended=True) address = None if net.dhcp: # Get a free IP from the address pool. try: address = get_network_free_address(net) except EmptyPool: raise faults.OverLimit('Network is full') log.info("Connecting VM %s to Network %s(%s)", vm, net, address) backend.connect_to_network(vm, net, address) return HttpResponse(status=202)
def do_create_server(userid, name, password, flavor, image, metadata={}, personality=[], network=None, backend=None): # Fix flavor for archipelago disk_template, provider = util.get_flavor_provider(flavor) if provider: flavor.disk_template = disk_template flavor.disk_provider = provider flavor.disk_origin = image['checksum'] image['backend_id'] = 'null' else: flavor.disk_provider = None flavor.disk_origin = None try: if backend is None: # Allocate backend to host the server. backend_allocator = BackendAllocator() backend = backend_allocator.allocate(userid, flavor) if backend is None: log.error("No available backend for VM with flavor %s", flavor) raise faults.ServiceUnavailable("No available backends") if network is None: # Allocate IP from public network (network, address) = util.get_public_ip(backend) else: address = util.get_network_free_address(network) # We must save the VM instance now, so that it gets a valid # vm.backend_vm_id. vm = VirtualMachine.objects.create( name=name, backend=backend, userid=userid, imageid=image["id"], flavor=flavor, action="CREATE") log.info("Created entry in DB for VM '%s'", vm) # Create VM's public NIC. Do not wait notification form ganeti hooks to # create this NIC, because if the hooks never run (e.g. building error) # the VM's public IP address will never be released! nic = NetworkInterface.objects.create(machine=vm, network=network, index=0, ipv4=address, state="BUILDING") # Also we must create the VM metadata in the same transaction. for key, val in metadata.items(): VirtualMachineMetadata.objects.create( meta_key=key, meta_value=val, vm=vm) # Issue commission to Quotaholder and accept it since at the end of # this transaction the VirtualMachine object will be created in the DB. # Note: the following call does a commit! quotas.issue_and_accept_commission(vm) except: transaction.rollback() raise else: transaction.commit() try: vm = VirtualMachine.objects.select_for_update().get(id=vm.id) # dispatch server created signal needed to trigger the 'vmapi', which # enriches the vm object with the 'config_url' attribute which must be # passed to the Ganeti job. server_created.send(sender=vm, created_vm_params={ 'img_id': image['backend_id'], 'img_passwd': password, 'img_format': str(image['format']), 'img_personality': json.dumps(personality), 'img_properties': json.dumps(image['metadata']), }) jobID = create_instance(vm, nic, flavor, image) # At this point the job is enqueued in the Ganeti backend vm.backendopcode = "OP_INSTANCE_CREATE" vm.backendjobid = jobID vm.save() transaction.commit() log.info("User %s created VM %s, NIC %s, Backend %s, JobID %s", userid, vm, nic, backend, str(jobID)) except: # If an exception is raised, then the user will never get the VM id. # In order to delete it from DB and release it's resources, we # mock a successful OP_INSTANCE_REMOVE job. process_op_status(vm=vm, etime=datetime.datetime.now(), jobid=-0, opcode="OP_INSTANCE_REMOVE", status="success", logmsg="Reconciled eventd: VM creation failed.") raise return vm
def do_create_server(userid, name, password, flavor, image, metadata={}, personality=[], network=None, backend=None): # Fix flavor for archipelago disk_template, provider = util.get_flavor_provider(flavor) if provider: flavor.disk_template = disk_template flavor.disk_provider = provider flavor.disk_origin = image['checksum'] image['backend_id'] = 'null' else: flavor.disk_provider = None flavor.disk_origin = None try: if backend is None: # Allocate backend to host the server. backend_allocator = BackendAllocator() backend = backend_allocator.allocate(userid, flavor) if backend is None: log.error("No available backend for VM with flavor %s", flavor) raise faults.ServiceUnavailable("No available backends") if network is None: # Allocate IP from public network (network, address) = util.get_public_ip(backend) nic = {'ip': address, 'network': network.backend_id} else: address = util.get_network_free_address(network) # We must save the VM instance now, so that it gets a valid # vm.backend_vm_id. vm = VirtualMachine.objects.create(name=name, backend=backend, userid=userid, imageid=image["id"], flavor=flavor, action="CREATE") # Create VM's public NIC. Do not wait notification form ganeti hooks to # create this NIC, because if the hooks never run (e.g. building error) # the VM's public IP address will never be released! NetworkInterface.objects.create(machine=vm, network=network, index=0, ipv4=address, state="BUILDING") log.info("Created entry in DB for VM '%s'", vm) # dispatch server created signal server_created.send(sender=vm, created_vm_params={ 'img_id': image['backend_id'], 'img_passwd': password, 'img_format': str(image['format']), 'img_personality': json.dumps(personality), 'img_properties': json.dumps(image['metadata']), }) # Also we must create the VM metadata in the same transaction. for key, val in metadata.items(): VirtualMachineMetadata.objects.create(meta_key=key, meta_value=val, vm=vm) # Issue commission to Quotaholder and accept it since at the end of # this transaction the VirtualMachine object will be created in the DB. # Note: the following call does a commit! quotas.issue_and_accept_commission(vm) except: transaction.rollback() raise else: transaction.commit() try: jobID = create_instance(vm, nic, flavor, image) # At this point the job is enqueued in the Ganeti backend vm.backendjobid = jobID vm.save() transaction.commit() log.info("User %s created VM %s, NIC %s, Backend %s, JobID %s", userid, vm, nic, backend, str(jobID)) except GanetiApiError as e: log.exception("Can not communicate to backend %s: %s.", backend, e) # Failed while enqueuing OP_INSTANCE_CREATE to backend. Restore # already reserved quotas by issuing a negative commission vm.operstate = "ERROR" vm.backendlogmsg = "Can not communicate to backend." vm.deleted = True vm.save() quotas.issue_and_accept_commission(vm, delete=True) raise except: transaction.rollback() raise return vm