Esempio n. 1
0
def reassign(vm, project, shared_to_project):
    commands.validate_server_action(vm, "REASSIGN")

    if vm.project == project:
        if vm.shared_to_project != shared_to_project:
            log.info("%s VM %s to project %s",
                     "Sharing" if shared_to_project else "Unsharing", vm,
                     project)
            vm.shared_to_project = shared_to_project
            vm.volumes.filter(index=0, deleted=False)\
                      .update(shared_to_project=shared_to_project)
            vm.save()
    else:
        action_fields = {"to_project": project, "from_project": vm.project}
        log.info("Reassigning VM %s from project %s to %s, shared: %s", vm,
                 vm.project, project, shared_to_project)
        if not (vm.backend.public
                or vm.backend.projects.filter(project=project).exists()):
            raise faults.BadRequest("Cannot reassign VM. Target project "
                                    "doesn't have access to the VM's backend.")
        vm.project = project
        vm.shared_to_project = shared_to_project
        vm.save()
        vm.volumes.filter(index=0, deleted=False).update(
            project=project, shared_to_project=shared_to_project)
        quotas.issue_and_accept_commission(vm,
                                           action="REASSIGN",
                                           action_fields=action_fields)
    return vm
Esempio n. 2
0
def reassign_volume(volume, project, shared_to_project):
    if volume.index == 0:
        raise faults.Conflict("Cannot reassign: %s is a system volume" %
                              volume.id)

    server = volume.machine
    if server is not None:
        commands.validate_server_action(server, "REASSIGN")

    if volume.project == project:
        if volume.shared_to_project != shared_to_project:
            log.info("%s volume %s to project %s",
                "Sharing" if shared_to_project else "Unsharing",
                volume, project)
            volume.shared_to_project = shared_to_project
            volume.save()
    else:
        action_fields = {"to_project": project, "from_project": volume.project}
        log.info("Reassigning volume %s from project %s to %s, shared: %s",
                volume, volume.project, project, shared_to_project)
        volume.project = project
        volume.shared_to_project = shared_to_project
        volume.save()
        quotas.issue_and_accept_commission(volume, action="REASSIGN",
                                           action_fields=action_fields)
    return volume
Esempio n. 3
0
def delete_floating_ip(floating_ip):
    if floating_ip.nic:
        # This is safe, you also need for_update to attach floating IP to
        # instance.
        server = floating_ip.nic.machine
        if server is None:
            msg = ("Floating IP '%s' is used by port '%s'" %
                   (floating_ip.id, floating_ip.nic_id))
        else:
            msg = ("Floating IP '%s' is used by server '%s'" %
                   (floating_ip.id, floating_ip.nic.machine_id))
        raise faults.Conflict(msg)

    # Lock network to prevent deadlock
    Network.objects.select_for_update().get(id=floating_ip.network_id)

    # Return the address of the floating IP back to pool
    floating_ip.release_address()
    # And mark the floating IP as deleted
    floating_ip.deleted = True
    floating_ip.save()
    # Release quota for floating IP
    quotas.issue_and_accept_commission(floating_ip, action="DESTROY")
    transaction.commit()
    # Delete the floating IP from DB
    log.info("Deleted floating IP '%s' of user '%s", floating_ip,
             floating_ip.userid)
    floating_ip.delete()
Esempio n. 4
0
File: ips.py Progetto: grnet/synnefo
def create_floating_ip(credentials, network_id=None, address=None,
                       project=None, shared_to_project=False,
                       atomic_context=None):
    userid = credentials.userid
    if network_id is None:
        floating_ip = allocate_public_ip(userid, floating_ip=True)
    else:
        network = util.get_network(network_id, credentials,
                                   for_update=True, non_deleted=True)
        if not network.floating_ip_pool:
            msg = ("Cannot allocate floating IP. Network %s is"
                   " not a floating IP pool.")
            raise faults.Conflict(msg % network.id)
        if network.action == "DESTROY":
            msg = "Cannot allocate floating IP. Network %s is being deleted."
            raise faults.Conflict(msg % network.id)

        # Allocate the floating IP
        floating_ip = allocate_ip(network, userid, address=address,
                                  floating_ip=True)

    if project is None:
        project = userid
    floating_ip.project = project
    floating_ip.shared_to_project=shared_to_project
    floating_ip.save()
    # Issue commission (quotas)
    quotas.issue_and_accept_commission(
        floating_ip, atomic_context=atomic_context)

    log.info("Created floating IP '%s' for user IP '%s'", floating_ip, userid)

    return floating_ip
Esempio n. 5
0
File: ips.py Progetto: grnet/synnefo
def reassign_floating_ip(
        floating_ip_id, project, shared_to_project, credentials,
        atomic_context=None):
    floating_ip = util.get_floating_ip_by_id(credentials,
                                             floating_ip_id,
                                             for_update=True)
    if not credentials.is_admin and credentials.userid != floating_ip.userid:
        raise faults.Forbidden("Action 'reassign' is allowed only to the owner"
                               " of the floating IP.")
    validate_ip_action(floating_ip, "REASSIGN", silent=False)
    if floating_ip.project == project:
        if floating_ip.shared_to_project != shared_to_project:
            log.info("%s floating_ip %s to project %s",
                "Sharing" if shared_to_project else "Unsharing",
                floating_ip, project)
            floating_ip.shared_to_project = shared_to_project
            floating_ip.save()
    else:
        action_fields = {"to_project": project,
                         "from_project": floating_ip.project}
        log.info("Reassigning floating_ip %s from project %s to %s, shared: %s",
                floating_ip, floating_ip.project, project, shared_to_project)
        floating_ip.project = project
        floating_ip.shared_to_project = shared_to_project
        floating_ip.save()

        quotas.issue_and_accept_commission(floating_ip, action="REASSIGN",
                                           action_fields=action_fields,
                                           atomic_context=atomic_context)
    return floating_ip
Esempio n. 6
0
def delete_floating_ip(floating_ip):
    if floating_ip.nic:
        # This is safe, you also need for_update to attach floating IP to
        # instance.
        server = floating_ip.nic.machine
        if server is None:
            msg = ("Floating IP '%s' is used by port '%s'" %
                   (floating_ip.id, floating_ip.nic_id))
        else:
            msg = ("Floating IP '%s' is used by server '%s'" %
                   (floating_ip.id, floating_ip.nic.machine_id))
        raise faults.Conflict(msg)

    # Lock network to prevent deadlock
    Network.objects.select_for_update().get(id=floating_ip.network_id)

    # Return the address of the floating IP back to pool
    floating_ip.release_address()
    # And mark the floating IP as deleted
    floating_ip.deleted = True
    floating_ip.save()
    # Release quota for floating IP
    quotas.issue_and_accept_commission(floating_ip, action="DESTROY")
    transaction.commit()
    # Delete the floating IP from DB
    log.info("Deleted floating IP '%s' of user '%s", floating_ip,
             floating_ip.userid)
    floating_ip.delete()
Esempio n. 7
0
def reassign_volume(volume, project, shared_to_project):
    if volume.index == 0:
        raise faults.Conflict("Cannot reassign: %s is a system volume" %
                              volume.id)

    server = volume.machine
    if server is not None:
        commands.validate_server_action(server, "REASSIGN")

    if volume.project == project:
        if volume.shared_to_project != shared_to_project:
            log.info("%s volume %s to project %s",
                "Sharing" if shared_to_project else "Unsharing",
                volume, project)
            volume.shared_to_project = shared_to_project
            volume.save()
    else:
        action_fields = {"to_project": project, "from_project": volume.project}
        log.info("Reassigning volume %s from project %s to %s, shared: %s",
                volume, volume.project, project, shared_to_project)
        volume.project = project
        volume.shared_to_project = shared_to_project
        volume.save()
        quotas.issue_and_accept_commission(volume, action="REASSIGN",
                                           action_fields=action_fields)
    return volume
Esempio n. 8
0
def reassign_volume(volume_id, project, shared_to_project, credentials,
                    atomic_context=None):
    volume = util.get_volume(credentials,
                             volume_id, for_update=True, non_deleted=True)

    if not credentials.is_admin and credentials.userid != volume.userid:
        raise faults.Forbidden("Action 'reassign' is allowed only to the owner"
                               " of the volume.")

    if volume.index == 0:
        raise faults.Conflict("Cannot reassign: %s is a system volume" %
                              volume.id)

    server = volume.machine
    if server is not None:
        commands.validate_server_action(server, "REASSIGN")

    if volume.project == project:
        if volume.shared_to_project != shared_to_project:
            log.info("%s volume %s to project %s",
                "Sharing" if shared_to_project else "Unsharing",
                volume, project)
            volume.shared_to_project = shared_to_project
            volume.save()
    else:
        action_fields = {"to_project": project, "from_project": volume.project}
        log.info("Reassigning volume %s from project %s to %s, shared: %s",
                volume, volume.project, project, shared_to_project)
        volume.project = project
        volume.shared_to_project = shared_to_project
        volume.save()
        quotas.issue_and_accept_commission(volume, action="REASSIGN",
                                           action_fields=action_fields,
                                           atomic_context=atomic_context)
    return volume
Esempio n. 9
0
def create_floating_ip(userid,
                       network=None,
                       address=None,
                       project=None,
                       shared_to_project=False):
    if network is None:
        floating_ip = allocate_public_ip(userid, floating_ip=True)
    else:
        if not network.floating_ip_pool:
            msg = ("Cannot allocate floating IP. Network %s is"
                   " not a floating IP pool.")
            raise faults.Conflict(msg % network.id)
        if network.action == "DESTROY":
            msg = "Cannot allocate floating IP. Network %s is being deleted."
            raise faults.Conflict(msg % network.id)

        # Allocate the floating IP
        floating_ip = allocate_ip(network,
                                  userid,
                                  address=address,
                                  floating_ip=True)

    if project is None:
        project = userid
    floating_ip.project = project
    floating_ip.shared_to_project = shared_to_project
    floating_ip.save()
    # Issue commission (quotas)
    quotas.issue_and_accept_commission(floating_ip)
    transaction.commit()

    log.info("Created floating IP '%s' for user IP '%s'", floating_ip, userid)

    return floating_ip
Esempio n. 10
0
def create_floating_ip(userid, network=None, address=None, project=None):
    if network is None:
        floating_ip = allocate_public_ip(userid, floating_ip=True)
    else:
        if not network.floating_ip_pool:
            msg = ("Cannot allocate floating IP. Network %s is"
                   " not a floating IP pool.")
            raise faults.Conflict(msg % network.id)
        if network.action == "DESTROY":
            msg = "Cannot allocate floating IP. Network %s is being deleted."
            raise faults.Conflict(msg % network.id)

        # Allocate the floating IP
        floating_ip = allocate_ip(network, userid, address=address,
                                  floating_ip=True)

    if project is None:
        project = userid
    floating_ip.project = project
    floating_ip.save()
    # Issue commission (quotas)
    quotas.issue_and_accept_commission(floating_ip)
    transaction.commit()

    log.info("Created floating IP '%s' for user IP '%s'", floating_ip, userid)

    return floating_ip
Esempio n. 11
0
def update_network_state(network):
    """Update the state of a Network based on BackendNetwork states.

    Update the state of a Network based on the operstate of the networks in the
    backends that network exists.

    The state of the network is:
    * ACTIVE: If it is 'ACTIVE' in at least one backend.
    * DELETED: If it is is 'DELETED' in all backends that have been created.

    This function also releases the resources (MAC prefix or Bridge) and the
    quotas for the network.

    """
    if network.deleted:
        # Network has already been deleted. Just assert that state is also
        # DELETED
        if not network.state == "DELETED":
            network.state = "DELETED"
            network.save()
        return

    backend_states = [s.operstate for s in network.backend_networks.all()]
    if not backend_states and network.action != "DESTROY":
        if network.state != "ACTIVE":
            network.state = "ACTIVE"
            network.save()
            return

    # Network is deleted when all BackendNetworks go to "DELETED" operstate
    deleted = reduce(lambda x, y: x == y and "DELETED", backend_states,
                     "DELETED")

    # Release the resources on the deletion of the Network
    if deleted:
        log.info("Network %r deleted. Releasing link %r mac_prefix %r",
                 network.id, network.mac_prefix, network.link)
        network.deleted = True
        network.state = "DELETED"
        if network.mac_prefix:
            if network.FLAVORS[network.flavor]["mac_prefix"] == "pool":
                release_resource(res_type="mac_prefix",
                                 value=network.mac_prefix)
        if network.link:
            if network.FLAVORS[network.flavor]["link"] == "pool":
                release_resource(res_type="bridge", value=network.link)

        # Issue commission
        if network.userid:
            quotas.issue_and_accept_commission(network, delete=True)
            # the above has already saved the object and committed;
            # a second save would override others' changes, since the
            # object is now unlocked
            return
        elif not network.public:
            log.warning("Network %s does not have an owner!", network.id)
    network.save()
Esempio n. 12
0
def reassign(network, project):
    action_fields = {"to_project": project, "from_project": network.project}
    log.info("Reassigning network %s from project %s to %s",
             network, network.project, project)
    network.project = project
    network.save()
    quotas.issue_and_accept_commission(network, action="REASSIGN",
                                       action_fields=action_fields)
    return network
Esempio n. 13
0
def reassign_floating_ip(floating_ip, project):
    action_fields = {"to_project": project,
                     "from_project": floating_ip.project}
    log.info("Reassigning floating IP %s from project %s to %s",
             floating_ip, floating_ip.project, project)
    floating_ip.project = project
    floating_ip.save()
    quotas.issue_and_accept_commission(floating_ip, action="REASSIGN",
                                       action_fields=action_fields)
Esempio n. 14
0
def process_op_status(vm, etime, jobid, opcode, status, logmsg, nics=None):
    """Process a job progress notification from the backend

    Process an incoming message from the backend (currently Ganeti).
    Job notifications with a terminating status (sucess, error, or canceled),
    also update the operating state of the VM.

    """
    # See #1492, #1031, #1111 why this line has been removed
    #if (opcode not in [x[0] for x in VirtualMachine.BACKEND_OPCODES] or
    if status not in [x[0] for x in BACKEND_STATUSES]:
        raise VirtualMachine.InvalidBackendMsgError(opcode, status)

    vm.backendjobid = jobid
    vm.backendjobstatus = status
    vm.backendopcode = opcode
    vm.backendlogmsg = logmsg

    # Update backendtime only for jobs that have been successfully completed,
    # since only these jobs update the state of the VM. Else a "race condition"
    # may occur when a successful job (e.g. OP_INSTANCE_REMOVE) completes
    # before an error job and messages arrive in reversed order.
    if status == 'success':
        vm.backendtime = etime

    # Notifications of success change the operating state
    state_for_success = VirtualMachine.OPER_STATE_FROM_OPCODE.get(opcode, None)
    if status == 'success' and state_for_success is not None:
        vm.operstate = state_for_success

    # Update the NICs of the VM
    if status == "success" and nics is not None:
        _process_net_status(vm, etime, nics)

    # Special case: if OP_INSTANCE_CREATE fails --> ERROR
    if opcode == 'OP_INSTANCE_CREATE' and status in ('canceled', 'error'):
        vm.operstate = 'ERROR'
        vm.backendtime = etime
    elif opcode == 'OP_INSTANCE_REMOVE':
        # Special case: OP_INSTANCE_REMOVE fails for machines in ERROR,
        # when no instance exists at the Ganeti backend.
        if status == "success" or (status == "error" and
                                   not vm_exists_in_backend(vm)):
            _process_net_status(vm, etime, nics=[])
            vm.operstate = state_for_success
            vm.backendtime = etime
            if not vm.deleted:
                vm.deleted = True
                # Issue and accept commission to Quotaholder
                quotas.issue_and_accept_commission(vm, delete=True)
                # the above has already saved the object and committed;
                # a second save would override others' changes, since the
                # object is now unlocked
                return

    vm.save()
Esempio n. 15
0
def reassign(vm, project):
    commands.validate_server_action(vm, "REASSIGN")
    action_fields = {"to_project": project, "from_project": vm.project}
    log.info("Reassigning VM %s from project %s to %s",
             vm, vm.project, project)
    vm.project = project
    vm.save()
    vm.volumes.filter(index=0, deleted=False).update(project=project)
    quotas.issue_and_accept_commission(vm, action="REASSIGN",
                                       action_fields=action_fields)
Esempio n. 16
0
def process_op_status(vm, etime, jobid, opcode, status, logmsg, nics=None):
    """Process a job progress notification from the backend

    Process an incoming message from the backend (currently Ganeti).
    Job notifications with a terminating status (sucess, error, or canceled),
    also update the operating state of the VM.

    """
    # See #1492, #1031, #1111 why this line has been removed
    #if (opcode not in [x[0] for x in VirtualMachine.BACKEND_OPCODES] or
    if status not in [x[0] for x in BACKEND_STATUSES]:
        raise VirtualMachine.InvalidBackendMsgError(opcode, status)

    vm.backendjobid = jobid
    vm.backendjobstatus = status
    vm.backendopcode = opcode
    vm.backendlogmsg = logmsg

    # Notifications of success change the operating state
    state_for_success = VirtualMachine.OPER_STATE_FROM_OPCODE.get(opcode, None)
    if status == 'success' and state_for_success is not None:
        vm.operstate = state_for_success

    # Update the NICs of the VM
    if status == "success" and nics is not None:
        _process_net_status(vm, etime, nics)

    # Special case: if OP_INSTANCE_CREATE fails --> ERROR
    if opcode == 'OP_INSTANCE_CREATE' and status in ('canceled', 'error'):
        vm.operstate = 'ERROR'
        vm.backendtime = etime
    elif opcode == 'OP_INSTANCE_REMOVE':
        # Set the deleted flag explicitly, cater for admin-initiated removals
        # Special case: OP_INSTANCE_REMOVE fails for machines in ERROR,
        # when no instance exists at the Ganeti backend.
        # See ticket #799 for all the details.
        #
        if (status == 'success' or
           (status == 'error' and (vm.operstate == 'ERROR' or
                                   vm.action == 'DESTROY'))):
            _process_net_status(vm, etime, nics=[])
            vm.deleted = True
            vm.operstate = state_for_success
            vm.backendtime = etime
            # Issue and accept commission to Quotaholder
            quotas.issue_and_accept_commission(vm, delete=True)

    # Update backendtime only for jobs that have been successfully completed,
    # since only these jobs update the state of the VM. Else a "race condition"
    # may occur when a successful job (e.g. OP_INSTANCE_REMOVE) completes
    # before an error job and messages arrive in reversed order.
    if status == 'success':
        vm.backendtime = etime

    vm.save()
Esempio n. 17
0
def reassign(vm, project):
    commands.validate_server_action(vm, "REASSIGN")
    action_fields = {"to_project": project, "from_project": vm.project}
    log.info("Reassigning VM %s from project %s to %s", vm, vm.project,
             project)
    vm.project = project
    vm.save()
    vm.volumes.filter(index=0, deleted=False).update(project=project)
    quotas.issue_and_accept_commission(vm,
                                       action="REASSIGN",
                                       action_fields=action_fields)
Esempio n. 18
0
def import_server(instance_name,
                  backend_id,
                  flavor_id,
                  image_id,
                  user_id,
                  new_public_nic,
                  stream=sys.stdout):
    flavor = common.get_flavor(flavor_id)
    backend = common.get_backend(backend_id)

    backend_client = backend.get_client()

    try:
        instance = backend_client.GetInstance(instance_name)
    except GanetiApiError as e:
        if e.code == 404:
            raise CommandError("Instance %s does not exist in backend %s" %
                               (instance_name, backend))
        else:
            raise CommandError("Unexpected error" + str(e))

    if not new_public_nic:
        check_instance_nics(instance)

    shutdown_instance(instance, backend_client, stream=stream)

    # Create the VM in DB
    stream.write("Creating VM entry in DB\n")
    vm = VirtualMachine.objects.create(name=instance_name,
                                       backend=backend,
                                       userid=user_id,
                                       imageid=image_id,
                                       flavor=flavor)

    quotas.issue_and_accept_commission(vm)

    if new_public_nic:
        remove_instance_nics(instance, backend_client, stream=stream)

    # Rename instance
    rename_instance(instance_name, vm.backend_vm_id, backend_client, stream)

    if new_public_nic:
        ports = servers.create_instance_ports(user_id)
        stream.write("Adding new NICs to server")
        [servers.associate_port_with_machine(port, vm) for port in ports]
        [connect_to_network(vm, port) for port in ports]

    # Startup instance
    startup_instance(vm.backend_vm_id, backend_client, stream=stream)

    backend.put_client(backend_client)
    return
Esempio n. 19
0
def reassign_floating_ip(floating_ip, project):
    action_fields = {
        "to_project": project,
        "from_project": floating_ip.project
    }
    log.info("Reassigning floating IP %s from project %s to %s", floating_ip,
             floating_ip.project, project)
    floating_ip.project = project
    floating_ip.save()
    quotas.issue_and_accept_commission(floating_ip,
                                       action="REASSIGN",
                                       action_fields=action_fields)
Esempio n. 20
0
def update_network_state(network):
    """Update the state of a Network based on BackendNetwork states.

    Update the state of a Network based on the operstate of the networks in the
    backends that network exists.

    The state of the network is:
    * ACTIVE: If it is 'ACTIVE' in at least one backend.
    * DELETED: If it is is 'DELETED' in all backends that have been created.

    This function also releases the resources (MAC prefix or Bridge) and the
    quotas for the network.

    """
    if network.deleted:
        # Network has already been deleted. Just assert that state is also
        # DELETED
        if not network.state == "DELETED":
            network.state = "DELETED"
            network.save()
        return

    backend_states = [s.operstate for s in network.backend_networks.all()]
    if not backend_states and network.action != "DESTROY":
        if network.state != "ACTIVE":
            network.state = "ACTIVE"
            network.save()
            return

    # Network is deleted when all BackendNetworks go to "DELETED" operstate
    deleted = reduce(lambda x, y: x == y and "DELETED", backend_states,
                     "DELETED")

    # Release the resources on the deletion of the Network
    if deleted:
        log.info("Network %r deleted. Releasing link %r mac_prefix %r",
                 network.id, network.mac_prefix, network.link)
        network.deleted = True
        network.state = "DELETED"
        if network.mac_prefix:
            if network.FLAVORS[network.flavor]["mac_prefix"] == "pool":
                release_resource(res_type="mac_prefix",
                                 value=network.mac_prefix)
        if network.link:
            if network.FLAVORS[network.flavor]["link"] == "pool":
                release_resource(res_type="bridge", value=network.link)

        # Issue commission
        if network.userid:
            quotas.issue_and_accept_commission(network, delete=True)
        elif not network.public:
            log.warning("Network %s does not have an owner!", network.id)
    network.save()
Esempio n. 21
0
def create(user_id, size, server=None, name=None, description=None,
           source_volume_id=None, source_snapshot_id=None,
           source_image_id=None, volume_type_id=None, metadata=None,
           project_id=None, shared_to_project=False):
    """Create a new volume and optionally attach it to a server.

    This function serves as the main entry-point for volume creation. It gets
    the necessary data either from the API or from an snf-manage command and
    then feeds that data to the lower-level functions that handle the actual
    creation of the volume and the server attachments.
    """
    volume_type = None

    # If given a server id, assert that it exists and that it belongs to the
    # user.
    if server:
        volume_type = server.flavor.volume_type
        # If the server's volume type conflicts with the provided volume type,
        # raise an exception.
        if volume_type_id and \
           volume_type.id != util.normalize_volume_type_id(volume_type_id):
            raise faults.BadRequest("Cannot create a volume with type '%s' to"
                                    " a server with volume type '%s'."
                                    % (volume_type_id, volume_type.id))

    # If the user has not provided a valid volume type, raise an exception.
    if volume_type is None:
        volume_type = util.get_volume_type(volume_type_id,
                                           include_deleted=False,
                                           exception=faults.BadRequest)

    # We cannot create a non-detachable volume without a server.
    if server is None:
        util.assert_detachable_volume_type(volume_type)

    volume = create_common(user_id, size, name=name,
                           description=description,
                           source_image_id=source_image_id,
                           source_snapshot_id=source_snapshot_id,
                           source_volume_id=source_volume_id,
                           volume_type=volume_type, metadata={},
                           project_id=project_id,
                           shared_to_project=shared_to_project)

    if server is not None:
        server_attachments.attach_volume(server, volume)
    else:
        quotas.issue_and_accept_commission(volume, action="BUILD")
        # If the volume has been created in the DB, consider it available.
        volume.status = "AVAILABLE"
        volume.save()

    return volume
Esempio n. 22
0
def create(user_id, size, server=None, name=None, description=None,
           source_volume_id=None, source_snapshot_id=None,
           source_image_id=None, volume_type_id=None, metadata=None,
           project_id=None, shared_to_project=False):
    """Create a new volume and optionally attach it to a server.

    This function serves as the main entry-point for volume creation. It gets
    the necessary data either from the API or from an snf-manage command and
    then feeds that data to the lower-level functions that handle the actual
    creation of the volume and the server attachments.
    """
    volume_type = None

    # If given a server id, assert that it exists and that it belongs to the
    # user.
    if server:
        volume_type = server.flavor.volume_type
        # If the server's volume type conflicts with the provided volume type,
        # raise an exception.
        if volume_type_id and \
           volume_type.id != util.normalize_volume_type_id(volume_type_id):
            raise faults.BadRequest("Cannot create a volume with type '%s' to"
                                    " a server with volume type '%s'."
                                    % (volume_type_id, volume_type.id))

    # If the user has not provided a valid volume type, raise an exception.
    if volume_type is None:
        volume_type = util.get_volume_type(volume_type_id,
                                           include_deleted=False,
                                           exception=faults.BadRequest)

    # We cannot create a non-detachable volume without a server.
    if server is None:
        util.assert_detachable_volume_type(volume_type)

    volume = create_common(user_id, size, name=name,
                           description=description,
                           source_image_id=source_image_id,
                           source_snapshot_id=source_snapshot_id,
                           source_volume_id=source_volume_id,
                           volume_type=volume_type, metadata={},
                           project_id=project_id,
                           shared_to_project=shared_to_project)

    if server is not None:
        server_attachments.attach_volume(server, volume)
    else:
        quotas.issue_and_accept_commission(volume, action="BUILD")
        # If the volume has been created in the DB, consider it available.
        volume.status = "AVAILABLE"
        volume.save()

    return volume
Esempio n. 23
0
def import_server(instance_name, backend_id, flavor_id, image_id, user_id,
                  new_public_nic, stream=sys.stdout):
    flavor = common.get_flavor(flavor_id)
    backend = common.get_backend(backend_id)

    backend_client = backend.get_client()

    try:
        instance = backend_client.GetInstance(instance_name)
    except GanetiApiError as e:
        if e.code == 404:
            raise CommandError("Instance %s does not exist in backend %s"
                               % (instance_name, backend))
        else:
            raise CommandError("Unexpected error" + str(e))

    if not new_public_nic:
        check_instance_nics(instance)

    shutdown_instance(instance, backend_client, stream=stream)

    # Create the VM in DB
    stream.write("Creating VM entry in DB\n")
    vm = VirtualMachine.objects.create(name=instance_name,
                                       backend=backend,
                                       userid=user_id,
                                       imageid=image_id,
                                       flavor=flavor)

    quotas.issue_and_accept_commission(vm)

    if new_public_nic:
        remove_instance_nics(instance, backend_client,
                             stream=stream)

    # Rename instance
    rename_instance(instance_name, vm.backend_vm_id, backend_client,
                    stream)

    if new_public_nic:
        ports = servers.create_instance_ports(user_id)
        stream.write("Adding new NICs to server")
        [servers.associate_port_with_machine(port, vm)
         for port in ports]
        [connect_to_network(vm, port) for port in ports]

    # Startup instance
    startup_instance(vm.backend_vm_id, backend_client, stream=stream)

    backend.put_client(backend_client)
    return
Esempio n. 24
0
def import_server(instance_name,
                  backend_id,
                  flavor_id,
                  image_id,
                  user_id,
                  new_public_nic,
                  stream=sys.stdout):
    flavor = common.get_flavor(flavor_id)
    backend = common.get_backend(backend_id)

    backend_client = backend.get_client()

    try:
        instance = backend_client.GetInstance(instance_name)
    except GanetiApiError as e:
        if e.code == 404:
            raise CommandError("Instance %s does not exist in backend %s" %
                               (instance_name, backend))
        else:
            raise CommandError("Unexpected error" + str(e))

    if new_public_nic:
        remove_instance_nics(instance, backend_client, stream=stream)
        (network, address) = allocate_public_address(backend)
        if address is None:
            raise CommandError("Can not allocate a public address."
                               " No available public network.")
        nic = {'ip': address, 'network': network.backend_id}
        add_public_nic(instance_name, nic, backend_client, stream=stream)
    else:
        check_instance_nics(instance)

    shutdown_instance(instance, backend_client, stream=stream)

    # Create the VM in DB
    stream.write("Creating VM entry in DB\n")
    vm = VirtualMachine.objects.create(name=instance_name,
                                       backend=backend,
                                       userid=user_id,
                                       imageid=image_id,
                                       flavor=flavor)

    quotas.issue_and_accept_commission(vm)
    # Rename instance
    rename_instance(instance_name, vm.backend_vm_id, backend_client, stream)
    # Startup instance
    startup_instance(vm.backend_vm_id, backend_client, stream=stream)

    backend.put_client(backend_client)
    return
Esempio n. 25
0
def delete_floating_ip(floating_ip):
    # Lock network to prevent deadlock
    Network.objects.select_for_update().get(id=floating_ip.network_id)

    # Return the address of the floating IP back to pool
    floating_ip.release_address()
    # And mark the floating IP as deleted
    floating_ip.deleted = True
    floating_ip.save()
    # Release quota for floating IP
    quotas.issue_and_accept_commission(floating_ip, action="DESTROY")
    transaction.commit()
    # Delete the floating IP from DB
    log.info("Deleted floating IP '%s' of user '%s", floating_ip,
             floating_ip.userid)
    floating_ip.delete()
Esempio n. 26
0
def reassign_volume(volume, project):
    if volume.index == 0:
        raise faults.Conflict("Cannot reassign: %s is a system volume" %
                              volume.id)
    if volume.machine_id is not None:
        server = util.get_server(volume.userid, volume.machine_id,
                                 for_update=True, non_deleted=True,
                                 exception=faults.BadRequest)
        commands.validate_server_action(server, "REASSIGN")
    action_fields = {"from_project": volume.project, "to_project": project}
    log.info("Reassigning volume %s from project %s to %s",
             volume.id, volume.project, project)
    volume.project = project
    volume.save()
    quotas.issue_and_accept_commission(volume, action="REASSIGN",
                                       action_fields=action_fields)
Esempio n. 27
0
def delete_floating_ip(floating_ip):
    # Lock network to prevent deadlock
    Network.objects.select_for_update().get(id=floating_ip.network_id)

    # Return the address of the floating IP back to pool
    floating_ip.release_address()
    # And mark the floating IP as deleted
    floating_ip.deleted = True
    floating_ip.save()
    # Release quota for floating IP
    quotas.issue_and_accept_commission(floating_ip, action="DESTROY")
    transaction.commit()
    # Delete the floating IP from DB
    log.info("Deleted floating IP '%s' of user '%s", floating_ip,
             floating_ip.userid)
    floating_ip.delete()
Esempio n. 28
0
File: ips.py Progetto: grnet/synnefo
def _delete_floating_ip(floating_ip_id, credentials, atomic_context=None):
    floating_ip = util.get_floating_ip_by_id(credentials,
                                             floating_ip_id, for_update=True)
    validate_ip_action(floating_ip, "DELETE", silent=False)

    # Lock network to prevent deadlock
    Network.objects.select_for_update().get(id=floating_ip.network_id)

    # Return the address of the floating IP back to pool
    floating_ip.release_address()
    # And mark the floating IP as deleted
    floating_ip.deleted = True
    floating_ip.save()
    # Release quota for floating IP
    quotas.issue_and_accept_commission(floating_ip, action="DESTROY",
                                       atomic_context=atomic_context)
    return floating_ip
Esempio n. 29
0
def reassign_volume(volume, project):
    if volume.index == 0:
        raise faults.Conflict("Cannot reassign: %s is a system volume" %
                              volume.id)
    if volume.machine_id is not None:
        server = util.get_server(volume.userid,
                                 volume.machine_id,
                                 for_update=True,
                                 non_deleted=True,
                                 exception=faults.BadRequest)
        commands.validate_server_action(server, "REASSIGN")
    action_fields = {"from_project": volume.project, "to_project": project}
    log.info("Reassigning volume %s from project %s to %s", volume.id,
             volume.project, project)
    volume.project = project
    volume.save()
    quotas.issue_and_accept_commission(volume,
                                       action="REASSIGN",
                                       action_fields=action_fields)
Esempio n. 30
0
def reassign(server_id,
             project,
             shared_to_project,
             credentials=None,
             atomic_context=None):
    vm = util.get_vm(server_id,
                     credentials,
                     for_update=True,
                     non_deleted=True,
                     non_suspended=True)
    commands.validate_server_action(vm, "REASSIGN")

    if vm.project == project:
        if vm.shared_to_project != shared_to_project:
            log.info("%s VM %s to project %s",
                     "Sharing" if shared_to_project else "Unsharing", vm,
                     project)
            vm.shared_to_project = shared_to_project
            vm.volumes.filter(index=0, deleted=False)\
                      .update(shared_to_project=shared_to_project)
            vm.save()
    else:
        action_fields = {"to_project": project, "from_project": vm.project}
        log.info("Reassigning VM %s from project %s to %s, shared: %s", vm,
                 vm.project, project, shared_to_project)
        if not (vm.backend.public
                or vm.backend.projects.filter(project=project).exists()):
            raise faults.Forbidden("Cannot reassign VM. Target project "
                                   "doesn't have access to the VM's backend.")
        if not FlavorPolicy.has_access_to_flavor(
                vm.flavor, credentials, project=project):
            raise faults.Forbidden("Cannot reassign VM. Target project "
                                   "doesn't have access to the VM's flavor.")
        vm.project = project
        vm.shared_to_project = shared_to_project
        vm.save()
        vm.volumes.filter(index=0, deleted=False)\
                  .update(project=project, shared_to_project=shared_to_project)
        quotas.issue_and_accept_commission(vm,
                                           action="REASSIGN",
                                           action_fields=action_fields,
                                           atomic_context=atomic_context)
    return vm
Esempio n. 31
0
def _delete_floating_ip(floating_ip_id, credentials, atomic_context=None):
    floating_ip = util.get_floating_ip_by_id(credentials,
                                             floating_ip_id,
                                             for_update=True)
    validate_ip_action(floating_ip, "DELETE", silent=False)

    # Lock network to prevent deadlock
    Network.objects.select_for_update().get(id=floating_ip.network_id)

    # Return the address of the floating IP back to pool
    floating_ip.release_address()
    # And mark the floating IP as deleted
    floating_ip.deleted = True
    floating_ip.save()
    # Release quota for floating IP
    quotas.issue_and_accept_commission(floating_ip,
                                       action="DESTROY",
                                       atomic_context=atomic_context)
    return floating_ip
Esempio n. 32
0
def delete(volume_id, credentials, atomic_context=None):
    """Delete a Volume.

    The canonical way of deleting a volume is to send a command to Ganeti to
    remove the volume from a specific server. There are two cases however when
    a volume may not be attached to a server:

    * Case 1: The volume has been created only in DB and was never attached to
    a server. In this case, we can simply mark the volume as deleted without
    using Ganeti to do so.
    * Case 2: The volume has been detached from a VM. This means that there are
    still data in the storage backend. Thus, in order to delete the volume
    safely, we must attach it to a helper VM, thereby handing the delete action
    to the dispatcher.
    """
    volume = util.get_volume(credentials,
                             volume_id, for_update=True, non_deleted=True)

    server_id = volume.machine_id
    if server_id is not None:
        server = get_vm(server_id)
        server_attachments.delete_volume(server, volume, atomic_context)
        log.info("Deleting volume '%s' from server '%s', job: %s",
                 volume.id, server_id, volume.backendjobid)
    elif volume.backendjobid is None:
        # Case 1: Uninitialized volume
        if volume.status not in ("AVAILABLE", "ERROR"):
            raise faults.BadRequest("Volume is in invalid state: %s" %
                                    volume.status)
        log.debug("Attempting to delete uninitialized volume %s.", volume)
        util.mark_volume_as_deleted(volume, immediate=True)
        quotas.issue_and_accept_commission(volume, action="DESTROY",
                                           atomic_context=atomic_context)
        log.info("Deleting uninitialized volume '%s'", volume.id)
    else:
        # Case 2: Detached volume
        log.debug("Attempting to delete detached volume %s", volume)
        delete_detached_volume(volume, atomic_context)
        log.info("Deleting volume '%s' from helper server '%s', job: %s",
                 volume.id, volume.machine.id, volume.backendjobid)

    return volume
Esempio n. 33
0
def reassign_floating_ip(floating_ip, project, shared_to_project):
    if floating_ip.project == project:
        if floating_ip.shared_to_project != shared_to_project:
            log.info("%s floating_ip %s to project %s",
                "Sharing" if shared_to_project else "Unsharing",
                floating_ip, project)
            floating_ip.shared_to_project = shared_to_project
            floating_ip.save()
    else:
        action_fields = {"to_project": project,
                         "from_project": floating_ip.project}
        log.info("Reassigning floating_ip %s from project %s to %s, shared: %s",
                floating_ip, floating_ip.project, project, shared_to_project)
        floating_ip.project = project
        floating_ip.shared_to_project = shared_to_project
        floating_ip.save()

        quotas.issue_and_accept_commission(floating_ip, action="REASSIGN",
                                           action_fields=action_fields)
    return floating_ip
Esempio n. 34
0
def create_floating_ip(credentials,
                       network_id=None,
                       address=None,
                       project=None,
                       shared_to_project=False,
                       atomic_context=None):
    userid = credentials.userid
    if network_id is None:
        floating_ip = allocate_public_ip(userid, floating_ip=True)
    else:
        network = util.get_network(network_id,
                                   credentials,
                                   for_update=True,
                                   non_deleted=True)
        if not network.floating_ip_pool:
            msg = ("Cannot allocate floating IP. Network %s is"
                   " not a floating IP pool.")
            raise faults.Conflict(msg % network.id)
        if network.action == "DESTROY":
            msg = "Cannot allocate floating IP. Network %s is being deleted."
            raise faults.Conflict(msg % network.id)

        # Allocate the floating IP
        floating_ip = allocate_ip(network,
                                  userid,
                                  address=address,
                                  floating_ip=True)

    if project is None:
        project = userid
    floating_ip.project = project
    floating_ip.shared_to_project = shared_to_project
    floating_ip.save()
    # Issue commission (quotas)
    quotas.issue_and_accept_commission(floating_ip,
                                       atomic_context=atomic_context)

    log.info("Created floating IP '%s' for user IP '%s'", floating_ip, userid)

    return floating_ip
Esempio n. 35
0
def reassign(network_id,
             project,
             shared_to_project,
             credentials,
             atomic_context=None):
    network = util.get_network(network_id,
                               credentials,
                               for_update=True,
                               non_deleted=True)

    if network.public:
        raise faults.Forbidden("Cannot reassign public network")

    if not credentials.is_admin and credentials.userid != network.userid:
        raise faults.Forbidden("Action 'reassign' is allowed only to the owner"
                               " of the network.")

    validate_network_action(network, "REASSIGN")
    if network.project == project:
        if network.shared_to_project != shared_to_project:
            log.info("%s network %s to project %s",
                     "Sharing" if shared_to_project else "Unsharing", network,
                     project)
            network.shared_to_project = shared_to_project
            network.save()
    else:
        action_fields = {
            "to_project": project,
            "from_project": network.project
        }
        log.info("Reassigning network %s from project %s to %s, shared: %s",
                 network, network.project, project, shared_to_project)
        network.project = project
        network.shared_to_project = shared_to_project
        network.save()
        quotas.issue_and_accept_commission(network,
                                           action="REASSIGN",
                                           action_fields=action_fields,
                                           atomic_context=atomic_context)
    return network
Esempio n. 36
0
def reassign(network, project, shared_to_project):
    if network.project == project:
        if network.shared_to_project != shared_to_project:
            log.info("%s network %s to project %s",
                     "Sharing" if shared_to_project else "Unsharing", network,
                     project)
            network.shared_to_project = shared_to_project
            network.save()
    else:
        action_fields = {
            "to_project": project,
            "from_project": network.project
        }
        log.info("Reassigning network %s from project %s to %s, shared: %s",
                 network, network.project, project, shared_to_project)
        network.project = project
        network.shared_to_project = shared_to_project
        network.save()
        quotas.issue_and_accept_commission(network,
                                           action="REASSIGN",
                                           action_fields=action_fields)
    return network
Esempio n. 37
0
    def handle(self, *args, **options):
        if len(args) < 1:
            raise CommandError("Please provide a network ID")

        network = get_network(args[0])

        self.stdout.write('Trying to remove network: %s\n' % str(network))

        if network.machines.exists():
            raise CommandError('Network is not empty. Can not delete')

        network.action = 'DESTROY'
        network.save()

        if network.userid:
            quotas.issue_and_accept_commission(network, delete=True)

        for bnet in network.backend_networks.exclude(operstate="DELETED"):
            delete_network(network, bnet.backend)

        self.stdout.write("Successfully submitted Ganeti jobs to"
                          " remove network %s" % network.backend_id)
Esempio n. 38
0
def reassign(vm, project, shared_to_project):
    commands.validate_server_action(vm, "REASSIGN")

    if vm.project == project:
        if vm.shared_to_project != shared_to_project:
            log.info("%s VM %s to project %s",
                "Sharing" if shared_to_project else "Unsharing",
                vm, project)
            vm.shared_to_project = shared_to_project
            vm.volumes.filter(index=0, deleted=False)\
                      .update(shared_to_project=shared_to_project)
            vm.save()
    else:
        action_fields = {"to_project": project, "from_project": vm.project}
        log.info("Reassigning VM %s from project %s to %s, shared: %s",
                vm, vm.project, project, shared_to_project)
        vm.project = project
        vm.shared_to_project = shared_to_project
        vm.save()
        vm.volumes.filter(index=0, deleted=False).update(project=project,
            shared_to_project=shared_to_project)
        quotas.issue_and_accept_commission(vm, action="REASSIGN",
                action_fields=action_fields)
    return vm
Esempio n. 39
0
def reassign(server_id, project, shared_to_project, credentials=None,
             atomic_context=None):
    vm = util.get_vm(server_id, credentials,
                     for_update=True, non_deleted=True, non_suspended=True)
    commands.validate_server_action(vm, "REASSIGN")

    if vm.project == project:
        if vm.shared_to_project != shared_to_project:
            log.info("%s VM %s to project %s",
                     "Sharing" if shared_to_project else "Unsharing",
                     vm, project)
            vm.shared_to_project = shared_to_project
            vm.volumes.filter(index=0, deleted=False)\
                      .update(shared_to_project=shared_to_project)
            vm.save()
    else:
        action_fields = {"to_project": project, "from_project": vm.project}
        log.info("Reassigning VM %s from project %s to %s, shared: %s",
                 vm, vm.project, project, shared_to_project)
        if not (vm.backend.public or
                vm.backend.projects.filter(project=project).exists()):
            raise faults.Forbidden("Cannot reassign VM. Target project "
                                   "doesn't have access to the VM's backend.")
        if not FlavorPolicy.has_access_to_flavor(vm.flavor, credentials,
                                                 project=project):
            raise faults.Forbidden("Cannot reassign VM. Target project "
                                   "doesn't have access to the VM's flavor.")
        vm.project = project
        vm.shared_to_project = shared_to_project
        vm.save()
        vm.volumes.filter(index=0, deleted=False)\
                  .update(project=project, shared_to_project=shared_to_project)
        quotas.issue_and_accept_commission(vm, action="REASSIGN",
                                           action_fields=action_fields,
                                           atomic_context=atomic_context)
    return vm
Esempio n. 40
0
def reassign_floating_ip(floating_ip_id,
                         project,
                         shared_to_project,
                         credentials,
                         atomic_context=None):
    floating_ip = util.get_floating_ip_by_id(credentials,
                                             floating_ip_id,
                                             for_update=True)
    if not credentials.is_admin and credentials.userid != floating_ip.userid:
        raise faults.Forbidden("Action 'reassign' is allowed only to the owner"
                               " of the floating IP.")
    validate_ip_action(floating_ip, "REASSIGN", silent=False)
    if floating_ip.project == project:
        if floating_ip.shared_to_project != shared_to_project:
            log.info("%s floating_ip %s to project %s",
                     "Sharing" if shared_to_project else "Unsharing",
                     floating_ip, project)
            floating_ip.shared_to_project = shared_to_project
            floating_ip.save()
    else:
        action_fields = {
            "to_project": project,
            "from_project": floating_ip.project
        }
        log.info(
            "Reassigning floating_ip %s from project %s to %s, shared: %s",
            floating_ip, floating_ip.project, project, shared_to_project)
        floating_ip.project = project
        floating_ip.shared_to_project = shared_to_project
        floating_ip.save()

        quotas.issue_and_accept_commission(floating_ip,
                                           action="REASSIGN",
                                           action_fields=action_fields,
                                           atomic_context=atomic_context)
    return floating_ip
Esempio n. 41
0
def create(userid, name, flavor, link=None, mac_prefix=None, mode=None,
           floating_ip_pool=False, tags=None, public=False, drained=False):
    if flavor is None:
        raise faults.BadRequest("Missing request parameter 'type'")
    elif flavor not in Network.FLAVORS.keys():
        raise faults.BadRequest("Invalid network type '%s'" % flavor)

    if mac_prefix is not None and flavor == "MAC_FILTERED":
        raise faults.BadRequest("Cannot override MAC_FILTERED mac-prefix")
    if link is not None and flavor == "PHYSICAL_VLAN":
        raise faults.BadRequest("Cannot override PHYSICAL_VLAN link")

    utils.check_name_length(name, Network.NETWORK_NAME_LENGTH, "Network name "
                            "is too long")

    try:
        fmode, flink, fmac_prefix, ftags = util.values_from_flavor(flavor)
    except EmptyPool:
        log.error("Failed to allocate resources for network of type: %s",
                  flavor)
        msg = "Failed to allocate resources for network."
        raise faults.ServiceUnavailable(msg)

    mode = mode or fmode
    link = link or flink
    mac_prefix = mac_prefix or fmac_prefix
    tags = tags or ftags

    validate_mac(mac_prefix + "0:00:00:00")

    # Check that given link is unique!
    if (link is not None and flavor == "IP_LESS_ROUTED" and
       Network.objects.filter(deleted=False, mode=mode, link=link).exists()):
        msg = "Link '%s' is already used." % link
        raise faults.BadRequest(msg)

    network = Network.objects.create(
        name=name,
        userid=userid,
        flavor=flavor,
        mode=mode,
        link=link,
        mac_prefix=mac_prefix,
        tags=tags,
        public=public,
        external_router=public,
        floating_ip_pool=floating_ip_pool,
        action='CREATE',
        state='ACTIVE',
        drained=drained)

    if link is None:
        network.link = "%slink-%d" % (settings.BACKEND_PREFIX_ID, network.id)
        network.save()

    # Issue commission to Quotaholder and accept it since at the end of
    # this transaction the Network object will be created in the DB.
    # Note: the following call does a commit!
    if not public:
        quotas.issue_and_accept_commission(network)

    return network
Esempio n. 42
0
def _db_create_server(credentials,
                      name,
                      flavor,
                      image,
                      metadata,
                      networks,
                      use_backend,
                      project,
                      volumes,
                      helper,
                      shared_to_project,
                      key_names,
                      atomic_context=None):

    rescue_properties = RescueProperties()
    try:
        rescue_properties.os = image["metadata"].get("OSFAMILY", '')
        rescue_properties.os_family = image["metadata"].get("OS", '')
    except KeyError as e:
        log.error("Failed to parse iamge info: %s", e)

    rescue_properties.save()

    # Create the ports for the server
    ports = create_instance_ports(credentials, networks)

    # We must save the VM instance now, so that it gets a valid
    # vm.backend_vm_id.
    vm = VirtualMachine.objects.create(name=name,
                                       backend=use_backend,
                                       userid=credentials.userid,
                                       project=project,
                                       shared_to_project=shared_to_project,
                                       imageid=image["id"],
                                       image_version=image["version"],
                                       key_names=json.dumps(key_names),
                                       flavor=flavor,
                                       operstate="BUILD",
                                       rescue_properties=rescue_properties,
                                       helper=helper)
    log.info("Created entry in DB for VM '%s'", vm)

    # Associate the ports with the server
    for index, port in enumerate(ports):
        associate_port_with_machine(port, vm)
        port.index = index
        port.save()

    # Create instance volumes
    server_vtype = flavor.volume_type
    server_volumes = []
    for index, vol_info in enumerate(volumes):
        if vol_info["source_type"] == "volume":
            uuid = vol_info["source_uuid"]
            v = get_volume(credentials,
                           uuid,
                           for_update=True,
                           non_deleted=True,
                           exception=faults.BadRequest)
            if v.volume_type_id != server_vtype.id:
                msg = ("Volume '%s' has type '%s' while flavor's volume type"
                       " is '%s'" % (v.id, v.volume_type_id, server_vtype.id))
                raise faults.BadRequest(msg)
            if v.status != "AVAILABLE":
                raise faults.BadRequest("Cannot use volume while it is in %s"
                                        " status" % v.status)
            v.delete_on_termination = vol_info["delete_on_termination"]
        else:
            v = _create_volume(user_id=credentials.userid,
                               volume_type=server_vtype,
                               project=project,
                               index=index,
                               shared_to_project=shared_to_project,
                               **vol_info)
        assign_volume_to_server(vm, v, index=index)
        server_volumes.append(v)

    # Create instance metadata
    for key, val in metadata.items():
        utils.check_name_length(key, VirtualMachineMetadata.KEY_LENGTH,
                                "Metadata key is too long")
        utils.check_name_length(val, VirtualMachineMetadata.VALUE_LENGTH,
                                "Metadata value is too long")
        VirtualMachineMetadata.objects.create(meta_key=key,
                                              meta_value=val,
                                              vm=vm)

    quotas.issue_and_accept_commission(vm,
                                       action="BUILD",
                                       atomic_context=atomic_context)
    return (vm.id, [port.id for port in ports
                    ], [volume.id for volume in server_volumes],
            {v.id: v.origin_size
             for v in server_volumes})
Esempio n. 43
0
def update_network_state(network):
    """Update the state of a Network based on BackendNetwork states.

    Update the state of a Network based on the operstate of the networks in the
    backends that network exists.

    The state of the network is:
    * ACTIVE: If it is 'ACTIVE' in at least one backend.
    * DELETED: If it is is 'DELETED' in all backends that have been created.

    This function also releases the resources (MAC prefix or Bridge) and the
    quotas for the network.

    """
    if network.deleted:
        # Network has already been deleted. Just assert that state is also
        # DELETED
        if not network.state == "DELETED":
            network.state = "DELETED"
            network.save()
        return

    backend_states = [s.operstate for s in network.backend_networks.all()]
    if not backend_states and network.action != "DESTROY":
        if network.state != "ACTIVE":
            network.state = "ACTIVE"
            network.save()
            return

    # Network is deleted when all BackendNetworks go to "DELETED" operstate
    deleted = reduce(lambda x, y: x == y and "DELETED", backend_states,
                     "DELETED")

    # Release the resources on the deletion of the Network
    if deleted:
        if network.ips.filter(deleted=False, floating_ip=True).exists():
            msg = "Cannot delete network %s! Floating IPs still in use!"
            log.error(msg % network)
            raise Exception(msg % network)
        log.info("Network %r deleted. Releasing link %r mac_prefix %r",
                 network.id, network.mac_prefix, network.link)
        network.deleted = True
        network.state = "DELETED"
        # Undrain the network, otherwise the network state will remain
        # as 'SNF:DRAINED'
        network.drained = False
        if network.mac_prefix:
            if network.FLAVORS[network.flavor]["mac_prefix"] == "pool":
                release_resource(res_type="mac_prefix",
                                 value=network.mac_prefix)
        if network.link:
            if network.FLAVORS[network.flavor]["link"] == "pool":
                release_resource(res_type="bridge", value=network.link)

        # Set all subnets as deleted
        network.subnets.update(deleted=True)
        # And delete the IP pools
        for subnet in network.subnets.all():
            if subnet.ipversion == 4:
                subnet.ip_pools.all().delete()
        # And all the backend networks since there are useless
        network.backend_networks.all().delete()

        # Issue commission
        if network.userid:
            quotas.issue_and_accept_commission(network, action="DESTROY")
            # the above has already saved the object and committed;
            # a second save would override others' changes, since the
            # object is now unlocked
            return
        elif not network.public:
            log.warning("Network %s does not have an owner!", network.id)
    network.save()
Esempio n. 44
0
def update_network_state(network):
    """Update the state of a Network based on BackendNetwork states.

    Update the state of a Network based on the operstate of the networks in the
    backends that network exists.

    The state of the network is:
    * ACTIVE: If it is 'ACTIVE' in at least one backend.
    * DELETED: If it is is 'DELETED' in all backends that have been created.

    This function also releases the resources (MAC prefix or Bridge) and the
    quotas for the network.

    """
    if network.deleted:
        # Network has already been deleted. Just assert that state is also
        # DELETED
        if not network.state == "DELETED":
            network.state = "DELETED"
            network.save()
        return

    backend_states = [s.operstate for s in network.backend_networks.all()]
    if not backend_states and network.action != "DESTROY":
        if network.state != "ACTIVE":
            network.state = "ACTIVE"
            network.save()
            return

    # Network is deleted when all BackendNetworks go to "DELETED" operstate
    deleted = reduce(lambda x, y: x == y and "DELETED", backend_states,
                     "DELETED")

    # Release the resources on the deletion of the Network
    if deleted:
        if network.ips.filter(deleted=False, floating_ip=True).exists():
            msg = "Cannot delete network %s! Floating IPs still in use!"
            log.error(msg % network)
            raise Exception(msg % network)
        log.info("Network %r deleted. Releasing link %r mac_prefix %r",
                 network.id, network.mac_prefix, network.link)
        network.deleted = True
        network.state = "DELETED"
        # Undrain the network, otherwise the network state will remain
        # as 'SNF:DRAINED'
        network.drained = False
        if network.mac_prefix:
            if network.FLAVORS[network.flavor]["mac_prefix"] == "pool":
                release_resource(res_type="mac_prefix",
                                 value=network.mac_prefix)
        if network.link:
            if network.FLAVORS[network.flavor]["link"] == "pool":
                release_resource(res_type="bridge", value=network.link)

        # Set all subnets as deleted
        network.subnets.update(deleted=True)
        # And delete the IP pools
        for subnet in network.subnets.all():
            if subnet.ipversion == 4:
                subnet.ip_pools.all().delete()
        # And all the backend networks since there are useless
        network.backend_networks.all().delete()

        # Issue commission
        if network.userid:
            quotas.issue_and_accept_commission(network, action="DESTROY")
            # the above has already saved the object and committed;
            # a second save would override others' changes, since the
            # object is now unlocked
            return
        elif not network.public:
            log.warning("Network %s does not have an owner!", network.id)
    network.save()
Esempio n. 45
0
def create(userid,
           name,
           flavor,
           link=None,
           mac_prefix=None,
           mode=None,
           floating_ip_pool=False,
           tags=None,
           public=False,
           drained=False,
           project=None,
           shared_to_project=False):
    if flavor is None:
        raise faults.BadRequest("Missing request parameter 'type'")
    elif flavor not in Network.FLAVORS.keys():
        raise faults.BadRequest("Invalid network type '%s'" % flavor)

    if mac_prefix is not None and flavor == "MAC_FILTERED":
        raise faults.BadRequest("Cannot override MAC_FILTERED mac-prefix")
    if link is not None and flavor == "PHYSICAL_VLAN":
        raise faults.BadRequest("Cannot override PHYSICAL_VLAN link")

    utils.check_name_length(name, Network.NETWORK_NAME_LENGTH, "Network name "
                            "is too long")

    try:
        fmode, flink, fmac_prefix, ftags = util.values_from_flavor(flavor)
    except EmptyPool:
        log.error("Failed to allocate resources for network of type: %s",
                  flavor)
        msg = "Failed to allocate resources for network."
        raise faults.ServiceUnavailable(msg)

    mode = mode or fmode
    link = link or flink
    mac_prefix = mac_prefix or fmac_prefix
    tags = tags or ftags

    validate_mac(mac_prefix + "0:00:00:00")

    # Check that given link is unique!
    if (link is not None and flavor == "IP_LESS_ROUTED"
            and Network.objects.filter(deleted=False, mode=mode,
                                       link=link).exists()):
        msg = "Link '%s' is already used." % link
        raise faults.BadRequest(msg)

    if project is None:
        project = userid

    network = Network.objects.create(name=name,
                                     userid=userid,
                                     project=project,
                                     shared_to_project=shared_to_project,
                                     flavor=flavor,
                                     mode=mode,
                                     link=link,
                                     mac_prefix=mac_prefix,
                                     tags=tags,
                                     public=public,
                                     external_router=public,
                                     floating_ip_pool=floating_ip_pool,
                                     action='CREATE',
                                     state='ACTIVE',
                                     drained=drained)

    if link is None:
        network.link = "%slink-%d" % (settings.BACKEND_PREFIX_ID, network.id)
        network.save()

    # Issue commission to Quotaholder and accept it since at the end of
    # this transaction the Network object will be created in the DB.
    # Note: the following call does a commit!
    if not public:
        quotas.issue_and_accept_commission(network)

    return network
Esempio n. 46
0
    def handle(self, *args, **options):
        if args:
            raise CommandError("Command doesn't accept any arguments")

        dry_run = options["dry_run"]
        name = options['name']
        subnet = options['subnet']
        backend_id = options['backend_id']
        public = options['public']
        flavor = options['flavor']
        mode = options['mode']
        link = options['link']
        mac_prefix = options['mac_prefix']
        tags = options['tags']
        userid = options["owner"]

        if not name:
            raise CommandError("Name is required")
        if not subnet:
            raise CommandError("Subnet is required")
        if not flavor:
            raise CommandError("Flavor is required")
        if public and not backend_id:
            raise CommandError("backend-id is required")
        if not userid and not public:
            raise CommandError("'owner' is required for private networks")

        if mac_prefix and flavor == "MAC_FILTERED":
            raise CommandError("Can not override MAC_FILTERED mac-prefix")
        if link and flavor == "PHYSICAL_VLAN":
            raise CommandError("Can not override PHYSICAL_VLAN link")

        if backend_id:
            backend = get_backend(backend_id)

        fmode, flink, fmac_prefix, ftags = values_from_flavor(flavor)
        mode = mode or fmode
        link = link or flink
        mac_prefix = mac_prefix or fmac_prefix
        tags = tags or ftags

        try:
            validate_mac(mac_prefix + "0:00:00:00")
        except InvalidMacAddress:
            raise CommandError("Invalid MAC prefix '%s'" % mac_prefix)
        subnet, gateway, subnet6, gateway6 = validate_network_info(options)

        if not link or not mode:
            raise CommandError("Can not create network."
                               " No connectivity link or mode")
        netinfo = {
           "name": name,
           "userid": options["owner"],
           "subnet": subnet,
           "gateway": gateway,
           "gateway6": gateway6,
           "subnet6": subnet6,
           "dhcp": options["dhcp"],
           "flavor": flavor,
           "public": public,
           "mode": mode,
           "link": link,
           "mac_prefix": mac_prefix,
           "tags": tags,
           "state": "ACTIVE"}

        if dry_run:
            self.stdout.write("Creating network:\n")
            pprint_table(self.stdout, tuple(netinfo.items()))
            return

        network = Network.objects.create(**netinfo)
        if userid:
            quotas.issue_and_accept_commission(network)

        if backend_id:
            # Create BackendNetwork only to the specified Backend
            network.create_backend_network(backend)
            create_network(network=network, backend=backend, connect=True)
Esempio n. 47
0
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
Esempio n. 48
0
def create_network(request):
    # Normal Response Code: 202
    # Error Response Codes: computeFault (400, 500),
    #                       serviceUnavailable (503),
    #                       unauthorized (401),
    #                       badMediaType(415),
    #                       badRequest (400),
    #                       forbidden (403)
    #                       overLimit (413)

    try:
        req = utils.get_request_dict(request)
        log.info('create_network %s', req)

        user_id = request.user_uniq
        try:
            d = req['network']
            name = d['name']
        except KeyError:
            raise faults.BadRequest("Malformed request")

        # Get and validate flavor. Flavors are still exposed as 'type' in the
        # API.
        flavor = d.get("type", None)
        if flavor is None:
            raise faults.BadRequest("Missing request parameter 'type'")
        elif flavor not in Network.FLAVORS.keys():
            raise faults.BadRequest("Invalid network type '%s'" % flavor)
        elif flavor not in settings.API_ENABLED_NETWORK_FLAVORS:
            raise faults.Forbidden("Can not create network of type '%s'" %
                                   flavor)

        public = d.get("public", False)
        if public:
            raise faults.Forbidden("Can not create a public network.")

        dhcp = d.get('dhcp', True)

        # Get and validate network parameters
        subnet = d.get('cidr', '192.168.1.0/24')
        subnet6 = d.get('cidr6', None)
        gateway = d.get('gateway', None)
        gateway6 = d.get('gateway6', None)
        # Check that user provided a valid subnet
        util.validate_network_params(subnet, gateway, subnet6, gateway6)

        try:
            mode, link, mac_prefix, tags = util.values_from_flavor(flavor)
            validate_mac(mac_prefix + "0:00:00:00")
            network = Network.objects.create(
                name=name,
                userid=user_id,
                subnet=subnet,
                subnet6=subnet6,
                gateway=gateway,
                gateway6=gateway6,
                dhcp=dhcp,
                flavor=flavor,
                mode=mode,
                link=link,
                mac_prefix=mac_prefix,
                tags=tags,
                action='CREATE',
                state='ACTIVE')
        except EmptyPool:
            log.error("Failed to allocate resources for network of type: %s",
                      flavor)
            raise faults.ServiceUnavailable("Failed to allocate network"
                                            " resources")

        # Issue commission to Quotaholder and accept it since at the end of
        # this transaction the Network object will be created in the DB.
        # Note: the following call does a commit!
        quotas.issue_and_accept_commission(network)
    except:
        transaction.rollback()
        raise
    else:
        transaction.commit()

    networkdict = network_to_dict(network, request.user_uniq)
    response = render_network(request, networkdict, status=202)

    return response
Esempio n. 49
0
    def handle(self, *args, **options):
        if args:
            raise CommandError("Command doesn't accept any arguments")

        dry_run = options["dry_run"]
        name = options['name']
        subnet = options['subnet']
        backend_id = options['backend_id']
        public = options['public']
        flavor = options['flavor']
        mode = options['mode']
        link = options['link']
        mac_prefix = options['mac_prefix']
        tags = options['tags']
        userid = options["owner"]

        if not name:
            raise CommandError("Name is required")
        if not subnet:
            raise CommandError("Subnet is required")
        if not flavor:
            raise CommandError("Flavor is required")
        if public and not backend_id:
            raise CommandError("backend-id is required")
        if not userid and not public:
            raise CommandError("'owner' is required for private networks")

        if mac_prefix and flavor == "MAC_FILTERED":
            raise CommandError("Can not override MAC_FILTERED mac-prefix")
        if link and flavor == "PHYSICAL_VLAN":
            raise CommandError("Can not override PHYSICAL_VLAN link")

        if backend_id:
            backend = get_backend(backend_id)

        fmode, flink, fmac_prefix, ftags = values_from_flavor(flavor)
        mode = mode or fmode
        link = link or flink
        mac_prefix = mac_prefix or fmac_prefix
        tags = tags or ftags

        try:
            validate_mac(mac_prefix + "0:00:00:00")
        except InvalidMacAddress:
            raise CommandError("Invalid MAC prefix '%s'" % mac_prefix)
        subnet, gateway, subnet6, gateway6 = validate_network_info(options)

        if not link or not mode:
            raise CommandError("Can not create network."
                               " No connectivity link or mode")
        netinfo = {
            "name": name,
            "userid": options["owner"],
            "subnet": subnet,
            "gateway": gateway,
            "gateway6": gateway6,
            "subnet6": subnet6,
            "dhcp": options["dhcp"],
            "flavor": flavor,
            "public": public,
            "mode": mode,
            "link": link,
            "mac_prefix": mac_prefix,
            "tags": tags,
            "state": "ACTIVE"
        }

        if dry_run:
            self.stdout.write("Creating network:\n")
            pprint_table(self.stdout, tuple(netinfo.items()))
            return

        network = Network.objects.create(**netinfo)
        if userid:
            quotas.issue_and_accept_commission(network)

        if backend_id:
            # Create BackendNetwork only to the specified Backend
            network.create_backend_network(backend)
            create_network(network=network, backend=backend, connect=True)
Esempio n. 50
0
def create_network(request):
    # Normal Response Code: 202
    # Error Response Codes: computeFault (400, 500),
    #                       serviceUnavailable (503),
    #                       unauthorized (401),
    #                       badMediaType(415),
    #                       badRequest (400),
    #                       forbidden (403)
    #                       overLimit (413)

    req = utils.get_request_dict(request)
    log.info('create_network %s', req)

    user_id = request.user_uniq
    try:
        d = req['network']
        name = d['name']
    except KeyError:
        raise faults.BadRequest("Malformed request")

    # Get and validate flavor. Flavors are still exposed as 'type' in the
    # API.
    flavor = d.get("type", None)
    if flavor is None:
        raise faults.BadRequest("Missing request parameter 'type'")
    elif flavor not in Network.FLAVORS.keys():
        raise faults.BadRequest("Invalid network type '%s'" % flavor)
    elif flavor not in settings.API_ENABLED_NETWORK_FLAVORS:
        raise faults.Forbidden("Can not create network of type '%s'" %
                               flavor)

    public = d.get("public", False)
    if public:
        raise faults.Forbidden("Can not create a public network.")

    dhcp = d.get('dhcp', True)

    # Get and validate network parameters
    subnet = d.get('cidr', '192.168.1.0/24')
    subnet6 = d.get('cidr6', None)
    gateway = d.get('gateway', None)
    gateway6 = d.get('gateway6', None)
    # Check that user provided a valid subnet
    util.validate_network_params(subnet, gateway, subnet6, gateway6)

    try:
        mode, link, mac_prefix, tags = util.values_from_flavor(flavor)
        validate_mac(mac_prefix + "0:00:00:00")
        network = Network.objects.create(
            name=name,
            userid=user_id,
            subnet=subnet,
            subnet6=subnet6,
            gateway=gateway,
            gateway6=gateway6,
            dhcp=dhcp,
            flavor=flavor,
            mode=mode,
            link=link,
            mac_prefix=mac_prefix,
            tags=tags,
            action='CREATE',
            state='ACTIVE')
    except EmptyPool:
        log.error("Failed to allocate resources for network of type: %s",
                  flavor)
        raise faults.ServiceUnavailable("Failed to allocate network resources")

    # Issue commission to Quotaholder and accept it since at the end of
    # this transaction the Network object will be created in the DB.
    # Note: the following call does a commit!
    quotas.issue_and_accept_commission(network)

    networkdict = network_to_dict(network, request.user_uniq)
    response = render_network(request, networkdict, status=202)

    return response
Esempio n. 51
0
def _db_create_server(
        credentials, name, flavor, image, metadata, networks, use_backend,
        project, volumes, helper, shared_to_project, key_names,
        atomic_context=None):

    rescue_properties = RescueProperties()
    try:
        rescue_properties.os = image["metadata"].get("OSFAMILY", '')
        rescue_properties.os_family = image["metadata"].get("OS", '')
    except KeyError as e:
        log.error("Failed to parse iamge info: %s", e)

    rescue_properties.save()

    # Create the ports for the server
    ports = create_instance_ports(credentials, networks)

    # We must save the VM instance now, so that it gets a valid
    # vm.backend_vm_id.
    vm = VirtualMachine.objects.create(name=name,
                                       backend=use_backend,
                                       userid=credentials.userid,
                                       project=project,
                                       shared_to_project=shared_to_project,
                                       imageid=image["id"],
                                       image_version=image["version"],
                                       key_names=json.dumps(key_names),
                                       flavor=flavor,
                                       operstate="BUILD",
                                       rescue_properties=rescue_properties,
                                       helper=helper)
    log.info("Created entry in DB for VM '%s'", vm)

    # Associate the ports with the server
    for index, port in enumerate(ports):
        associate_port_with_machine(port, vm)
        port.index = index
        port.save()

    # Create instance volumes
    server_vtype = flavor.volume_type
    server_volumes = []
    for index, vol_info in enumerate(volumes):
        if vol_info["source_type"] == "volume":
            uuid = vol_info["source_uuid"]
            v = get_volume(credentials, uuid, for_update=True,
                           non_deleted=True, exception=faults.BadRequest)
            if v.volume_type_id != server_vtype.id:
                msg = ("Volume '%s' has type '%s' while flavor's volume type"
                       " is '%s'" % (v.id, v.volume_type_id, server_vtype.id))
                raise faults.BadRequest(msg)
            if v.status != "AVAILABLE":
                raise faults.BadRequest("Cannot use volume while it is in %s"
                                        " status" % v.status)
            v.delete_on_termination = vol_info["delete_on_termination"]
        else:
            v = _create_volume(user_id=credentials.userid,
                               volume_type=server_vtype,
                               project=project, index=index,
                               shared_to_project=shared_to_project,
                               **vol_info)
        assign_volume_to_server(vm, v, index=index)
        server_volumes.append(v)

    # Create instance metadata
    for key, val in metadata.items():
        utils.check_name_length(key, VirtualMachineMetadata.KEY_LENGTH,
                                "Metadata key is too long")
        utils.check_name_length(val, VirtualMachineMetadata.VALUE_LENGTH,
                                "Metadata value is too long")
        VirtualMachineMetadata.objects.create(
            meta_key=key,
            meta_value=val,
            vm=vm)

    quotas.issue_and_accept_commission(vm, action="BUILD",
                                       atomic_context=atomic_context)
    return (vm.id,
            [port.id for port in ports],
            [volume.id for volume in server_volumes],
            {v.id: v.origin_size for v in server_volumes})