Ejemplo n.º 1
0
def _rename(network, name):
    validate_network_action(network, "RENAME")
    utils.check_name_length(name, Network.NETWORK_NAME_LENGTH, "Network name "
                            "is too long")
    network.name = name
    network.save()
    return network
Ejemplo n.º 2
0
def create(userid,
           name,
           password,
           flavor,
           image,
           metadata={},
           personality=[],
           networks=None,
           use_backend=None):
    if use_backend is None:
        # Allocate server to a Ganeti backend
        use_backend = allocate_new_server(userid, flavor)

    utils.check_name_length(name, VirtualMachine.VIRTUAL_MACHINE_NAME_LENGTH,
                            "Server name is too long")

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

    # 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 = None
        if provider in settings.GANETI_CLONE_PROVIDERS:
            flavor.disk_origin = image['checksum']
            image['backend_id'] = 'null'
    else:
        flavor.disk_provider = None

    # 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=userid,
                                       imageid=image["id"],
                                       flavor=flavor,
                                       operstate="BUILD")
    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()

    for key, val in metadata.items():
        VirtualMachineMetadata.objects.create(meta_key=key,
                                              meta_value=val,
                                              vm=vm)

    # Create the server in Ganeti.
    vm = create_server(vm, ports, flavor, image, personality, password)

    return vm
Ejemplo n.º 3
0
def create_common(user_id, size, name=None, description=None,
                  source_volume_id=None, source_snapshot_id=None,
                  source_image_id=None, volume_type=None, metadata=None,
                  project_id=None, shared_to_project=False):
    """Common tasks and checks for the creation of a new volume.

    This function processes the necessary arguments in order to call the
    `_create_volume` function, which creates the volume in the DB.

    The main duty of `create_common` is to handle the metadata creation of the
    volume and to update the quota of the user.
    """
    # Assert that not more than one source are used
    sources = filter(lambda x: x is not None,
                     [source_volume_id, source_snapshot_id, source_image_id])
    if len(sources) > 1:
        raise faults.BadRequest("Volume can not have more than one source!")

    if source_volume_id is not None:
        source_type = "volume"
        source_uuid = source_volume_id
    elif source_snapshot_id is not None:
        source_type = "snapshot"
        source_uuid = source_snapshot_id
    elif source_image_id is not None:
        source_type = "image"
        source_uuid = source_image_id
    else:
        source_type = "blank"
        source_uuid = None

    if project_id is None:
        project_id = user_id

    if metadata is not None and \
       len(metadata) > settings.CYCLADES_VOLUME_MAX_METADATA:
        raise faults.BadRequest("Volumes cannot have more than %s metadata "
                                "items" %
                                settings.CYCLADES_VOLUME_MAX_METADATA)

    volume = _create_volume(user_id, project_id, size, source_type,
                            source_uuid, volume_type=volume_type,
                            name=name, description=description, index=None,
                            shared_to_project=shared_to_project)

    if metadata is not None:
        for meta_key, meta_val in metadata.items():
            utils.check_name_length(meta_key, VolumeMetadata.KEY_LENGTH,
                                    "Metadata key is too long")
            utils.check_name_length(meta_val, VolumeMetadata.VALUE_LENGTH,
                                    "Metadata value is too long")
            volume.metadata.create(key=meta_key, value=meta_val)

    return volume
Ejemplo n.º 4
0
def rename(server, new_name):
    """Rename a VirtualMachine."""
    utils.check_name_length(new_name,
                            VirtualMachine.VIRTUAL_MACHINE_NAME_LENGTH,
                            "Server name is too long")
    old_name = server.name
    server.name = new_name
    server.save()
    log.info("Renamed server '%s' from '%s' to '%s'", server, old_name,
             new_name)
    return server
Ejemplo n.º 5
0
def rename(server, new_name):
    """Rename a VirtualMachine."""
    utils.check_name_length(new_name,
                            VirtualMachine.VIRTUAL_MACHINE_NAME_LENGTH,
                            "Server name is too long")
    old_name = server.name
    server.name = new_name
    server.save()
    log.info("Renamed server '%s' from '%s' to '%s'", server, old_name,
             new_name)
    return server
Ejemplo n.º 6
0
def update_volume_metadata(request, volume_id, reset=False):
    req = utils.get_json_body(request)
    log.debug("User: %s, Volume: %s Action: update_metadata, Request: %s",
              request.user_uniq, volume_id, req)

    meta_dict = utils.get_attribute(req,
                                    "metadata",
                                    required=True,
                                    attr_type=dict)
    for key, value in meta_dict.items():
        check_name_length(key, VolumeMetadata.KEY_LENGTH,
                          "Metadata key is too long.")
        check_name_length(value, VolumeMetadata.VALUE_LENGTH,
                          "Metadata value is too long.")
    volume = util.get_volume(request.user_uniq,
                             request.user_projects,
                             volume_id,
                             for_update=True,
                             non_deleted=True)
    if reset:
        if len(meta_dict) > settings.CYCLADES_VOLUME_MAX_METADATA:
            raise faults.BadRequest("Volumes cannot have more than %s metadata"
                                    " items" %
                                    settings.CYCLADES_VOLUME_MAX_METADATA)

        volume.metadata.all().delete()
        for key, value in meta_dict.items():
            volume.metadata.create(key=key, value=value)
    else:
        if len(meta_dict) + len(volume.metadata.all()) - \
           len(volume.metadata.all().filter(key__in=meta_dict.keys())) > \
           settings.CYCLADES_VOLUME_MAX_METADATA:
            raise faults.BadRequest("Volumes cannot have more than %s metadata"
                                    " items" %
                                    settings.CYCLADES_VOLUME_MAX_METADATA)

        for key, value in meta_dict.items():
            try:
                # Update existing metadata
                meta = volume.metadata.get(key=key)
                meta.value = value
                meta.save()
            except VolumeMetadata.DoesNotExist:
                # Or create a new one
                volume.metadata.create(key=key, value=value)

    log.info("User %s updated metadata for volume %s", request.user_uniq,
             volume.id)

    metadata = volume.metadata.values_list('key', 'value')
    data = json.dumps({"metadata": dict(metadata)})
    return HttpResponse(data, content_type="application/json", status=200)
Ejemplo n.º 7
0
def rename(server_id, new_name, credentials=None):
    """Rename a VirtualMachine."""
    server = util.get_vm(server_id, credentials,
                         for_update=True, non_deleted=True, non_suspended=True)
    utils.check_name_length(new_name,
                            VirtualMachine.VIRTUAL_MACHINE_NAME_LENGTH,
                            "Server name is too long")
    old_name = server.name
    server.name = new_name
    server.save()
    log.info("Renamed server '%s' from '%s' to '%s'", server, old_name,
             new_name)
    return server
Ejemplo n.º 8
0
def create(userid, name, password, flavor, image, metadata={},
           personality=[], networks=None, use_backend=None):
    if use_backend is None:
        # Allocate server to a Ganeti backend
        use_backend = allocate_new_server(userid, flavor)

    utils.check_name_length(name, VirtualMachine.VIRTUAL_MACHINE_NAME_LENGTH,
                            "Server name is too long")

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

    # 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 = None
        if provider in settings.GANETI_CLONE_PROVIDERS:
            flavor.disk_origin = image['checksum']
            image['backend_id'] = 'null'
    else:
        flavor.disk_provider = None

    # 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=userid,
                                       imageid=image["id"],
                                       flavor=flavor,
                                       operstate="BUILD")
    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()

    for key, val in metadata.items():
        VirtualMachineMetadata.objects.create(
            meta_key=key,
            meta_value=val,
            vm=vm)

    # Create the server in Ganeti.
    vm = create_server(vm, ports, flavor, image, personality, password)

    return vm
Ejemplo n.º 9
0
def update(volume, name=None, description=None, delete_on_termination=None):
    if name is not None:
        utils.check_name_length(name, Volume.NAME_LENGTH,
                                "Volume name is too long")
        volume.name = name
    if description is not None:
        utils.check_name_length(description, Volume.DESCRIPTION_LENGTH,
                                "Volume description is too long")
        volume.description = description
    if delete_on_termination is not None:
        validate_volume_termination(volume.volume_type, delete_on_termination)
        volume.delete_on_termination = delete_on_termination

    volume.save()
    return volume
Ejemplo n.º 10
0
def update(volume, name=None, description=None, delete_on_termination=None):
    if name is not None:
        utils.check_name_length(name, Volume.NAME_LENGTH,
                                "Volume name is too long")
        volume.name = name
    if description is not None:
        utils.check_name_length(description, Volume.DESCRIPTION_LENGTH,
                                "Volume description is too long")
        volume.description = description
    if delete_on_termination is not None:
        validate_volume_termination(volume.volume_type, delete_on_termination)
        volume.delete_on_termination = delete_on_termination

    volume.save()
    return volume
Ejemplo n.º 11
0
def update_volume_metadata(request, volume_id, reset=False):
    credentials = request.credentials
    req = utils.get_json_body(request)
    log.debug("User: %s, Volume: %s Action: update_metadata, Request: %s",
              credentials.userid, volume_id, req)

    meta_dict = utils.get_attribute(req, "metadata", required=True,
                                    attr_type=dict)
    for key, value in meta_dict.items():
        check_name_length(key, VolumeMetadata.KEY_LENGTH,
                          "Metadata key is too long.")
        check_name_length(value, VolumeMetadata.VALUE_LENGTH,
                          "Metadata value is too long.")
    volume = util.get_volume(request.credentials,
                             volume_id, for_update=True, non_deleted=True)
    if reset:
        if len(meta_dict) > settings.CYCLADES_VOLUME_MAX_METADATA:
            raise faults.BadRequest("Volumes cannot have more than %s metadata"
                                    " items" %
                                    settings.CYCLADES_VOLUME_MAX_METADATA)

        volume.metadata.all().delete()
        for key, value in meta_dict.items():
            volume.metadata.create(key=key, value=value)
    else:
        if len(meta_dict) + len(volume.metadata.all()) - \
           len(volume.metadata.all().filter(key__in=meta_dict.keys())) > \
           settings.CYCLADES_VOLUME_MAX_METADATA:
            raise faults.BadRequest("Volumes cannot have more than %s metadata"
                                    " items" %
                                    settings.CYCLADES_VOLUME_MAX_METADATA)

        for key, value in meta_dict.items():
            try:
                # Update existing metadata
                meta = volume.metadata.get(key=key)
                meta.value = value
                meta.save()
            except VolumeMetadata.DoesNotExist:
                # Or create a new one
                volume.metadata.create(key=key, value=value)

    log.info("User %s updated metadata for volume %s", credentials.userid,
             volume.id)

    metadata = volume.metadata.values_list('key', 'value')
    data = json.dumps({"metadata": dict(metadata)})
    return HttpResponse(data, content_type="application/json", status=200)
Ejemplo n.º 12
0
def rename(server_id, new_name, credentials=None):
    """Rename a VirtualMachine."""
    server = util.get_vm(server_id,
                         credentials,
                         for_update=True,
                         non_deleted=True,
                         non_suspended=True)
    utils.check_name_length(new_name,
                            VirtualMachine.VIRTUAL_MACHINE_NAME_LENGTH,
                            "Server name is too long")
    old_name = server.name
    server.name = new_name
    server.save()
    log.info("Renamed server '%s' from '%s' to '%s'", server, old_name,
             new_name)
    return server
Ejemplo n.º 13
0
def update(volume_id, name=None, description=None, delete_on_termination=None,
           credentials=None):
    volume = util.get_volume(credentials,
                             volume_id, for_update=True, non_deleted=True)

    if name is not None:
        utils.check_name_length(name, Volume.NAME_LENGTH,
                                "Volume name is too long")
        volume.name = name
    if description is not None:
        utils.check_name_length(description, Volume.DESCRIPTION_LENGTH,
                                "Volume description is too long")
        volume.description = description
    if delete_on_termination is not None:
        validate_volume_termination(volume.volume_type, delete_on_termination)
        volume.delete_on_termination = delete_on_termination

    volume.save()
    return volume
Ejemplo n.º 14
0
def update_subnet(sub_id, name, user_id):
    """Update the fields of a subnet
    Only the name can be updated

    """
    log.info('Update subnet %s, name %s' % (sub_id, name))

    try:
        subnet = Subnet.objects.get(id=sub_id)
    except:
        raise api.faults.ItemNotFound("Subnet not found")

    if user_id != subnet.network.userid:
        raise api.faults.Forbidden("Forbidden operation")

    utils.check_name_length(name, Subnet.SUBNET_NAME_LENGTH, "Subnet name is "
                            " too long")

    subnet.name = name
    subnet.save()

    return subnet
Ejemplo n.º 15
0
def update_subnet(sub_id, name, user_id):
    """Update the fields of a subnet
    Only the name can be updated

    """
    log.info('Update subnet %s, name %s' % (sub_id, name))

    try:
        subnet = Subnet.objects.get(id=sub_id)
    except:
        raise api.faults.ItemNotFound("Subnet not found")

    if user_id != subnet.network.userid:
        raise api.faults.Forbidden("Forbidden operation")

    utils.check_name_length(name, Subnet.SUBNET_NAME_LENGTH, "Subnet name is "
                            " too long")

    subnet.name = name
    subnet.save()

    return subnet
Ejemplo n.º 16
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})
Ejemplo n.º 17
0
def _create_volume(server,
                   user_id,
                   project,
                   size,
                   source_type,
                   source_uuid,
                   volume_type,
                   name=None,
                   description=None,
                   index=None,
                   delete_on_termination=True):

    utils.check_name_length(name, Volume.NAME_LENGTH,
                            "Volume name is too long")
    utils.check_name_length(description, Volume.DESCRIPTION_LENGTH,
                            "Volume description is too long")
    validate_volume_termination(volume_type, delete_on_termination)

    if index is None:
        # Counting a server's volumes is safe, because we have an
        # X-lock on the server.
        index = server.volumes.filter(deleted=False).count()

    if size is not None:
        try:
            size = int(size)
        except (TypeError, ValueError):
            raise faults.BadRequest("Volume 'size' needs to be a positive"
                                    " integer value.")
        if size < 1:
            raise faults.BadRequest("Volume size must be a positive integer")
        if size > settings.CYCLADES_VOLUME_MAX_SIZE:
            raise faults.BadRequest("Maximum volume size is '%sGB'" %
                                    settings.CYCLADES_VOLUME_MAX_SIZE)

    # Only ext_ disk template supports cloning from another source. Otherwise
    # is must be the root volume so that 'snf-image' fill the volume
    can_have_source = (index == 0 or volume_type.provider
                       in settings.GANETI_CLONE_PROVIDERS)
    if not can_have_source and source_type != "blank":
        msg = ("Cannot specify a 'source' attribute for volume type '%s' with"
               " disk template '%s'" %
               (volume_type.id, volume_type.disk_template))
        raise faults.BadRequest(msg)

    source_version = None
    origin_size = None
    # TODO: Check Volume/Snapshot Status
    if source_type == "snapshot":
        source_snapshot = util.get_snapshot(user_id,
                                            source_uuid,
                                            exception=faults.BadRequest)
        snap_status = source_snapshot.get("status", "").upper()
        if snap_status != OBJECT_AVAILABLE:
            raise faults.BadRequest("Cannot create volume from snapshot, while"
                                    " snapshot is in '%s' status" %
                                    snap_status)
        source = Volume.prefix_source(source_uuid, source_type="snapshot")
        if size is None:
            raise faults.BadRequest("Volume size is required")
        elif (size << 30) < int(source_snapshot["size"]):
            raise faults.BadRequest("Volume size '%s' is smaller than"
                                    " snapshot's size '%s'" %
                                    (size << 30, source_snapshot["size"]))
        source_version = source_snapshot["version"]
        origin = source_snapshot["mapfile"]
        origin_size = source_snapshot["size"]
    elif source_type == "image":
        source_image = util.get_image(user_id,
                                      source_uuid,
                                      exception=faults.BadRequest)
        img_status = source_image.get("status", "").upper()
        if img_status != OBJECT_AVAILABLE:
            raise faults.BadRequest("Cannot create volume from image, while"
                                    " image is in '%s' status" % img_status)
        if size is None:
            raise faults.BadRequest("Volume size is required")
        elif (size << 30) < int(source_image["size"]):
            raise faults.BadRequest("Volume size '%s' is smaller than"
                                    " image's size '%s'" %
                                    (size << 30, source_image["size"]))
        source = Volume.prefix_source(source_uuid, source_type="image")
        source_version = source_image["version"]
        origin = source_image["mapfile"]
        origin_size = source_image["size"]
    elif source_type == "blank":
        if size is None:
            raise faults.BadRequest("Volume size is required")
        source = origin = None
    elif source_type == "volume":
        # Currently, Archipelago does not support cloning a volume
        raise faults.BadRequest("Cloning a volume is not supported")
        # source_volume = util.get_volume(user_id, source_uuid,
        #                                 for_update=True, non_deleted=True,
        #                                 exception=faults.BadRequest)
        # if source_volume.status != "IN_USE":
        #     raise faults.BadRequest("Cannot clone volume while it is in '%s'"
        #                             " status" % source_volume.status)
        # # If no size is specified, use the size of the volume
        # if size is None:
        #     size = source_volume.size
        # elif size < source_volume.size:
        #     raise faults.BadRequest("Volume size cannot be smaller than the"
        #                             " source volume")
        # source = Volume.prefix_source(source_uuid, source_type="volume")
        # origin = source_volume.backend_volume_uuid
    else:
        raise faults.BadRequest("Unknown source type")

    volume = Volume.objects.create(userid=user_id,
                                   project=project,
                                   size=size,
                                   volume_type=volume_type,
                                   name=name,
                                   machine=server,
                                   description=description,
                                   delete_on_termination=delete_on_termination,
                                   source=source,
                                   source_version=source_version,
                                   origin=origin,
                                   index=index,
                                   status="CREATING")

    # Store the size of the origin in the volume object but not in the DB.
    # We will have to change this in order to support detachable volumes.
    volume.origin_size = origin_size

    return volume
Ejemplo n.º 18
0
def _create_subnet(network_id,
                   user_id,
                   cidr,
                   name,
                   ipversion=4,
                   gateway=None,
                   dhcp=True,
                   slaac=True,
                   dns_nameservers=None,
                   allocation_pools=None,
                   host_routes=None):
    """Create a subnet

    network_id and the desired cidr are mandatory, everything else is optional

    """

    try:
        network_id = int(network_id)
        network = Network.objects.select_for_update().get(id=network_id)
    except (ValueError, TypeError):
        raise api.faults.BadRequest("Malformed network ID")
    except Network.DoesNotExist:
        raise api.faults.ItemNotFound("No network found with that ID")

    if network.deleted:
        raise api.faults.BadRequest("Network has been deleted")

    if user_id != network.userid:
        raise api.faults.Forbidden("Forbidden operation")

    if ipversion not in [4, 6]:
        raise api.faults.BadRequest("Malformed IP version type")

    check_number_of_subnets(network, ipversion)

    if network.backend_networks.exists():
        raise api.faults.BadRequest("Cannot create subnet in network %s, VMs"
                                    " are already connected to this network" %
                                    network_id)

    try:
        cidr_ip = ipaddr.IPNetwork(cidr)
    except ValueError:
        raise api.faults.BadRequest("Malformed CIDR")

    if ipversion == 6:
        validate_subnet_params(subnet6=cidr, gateway6=gateway)
    else:
        validate_subnet_params(subnet=cidr, gateway=gateway)

    utils.check_name_length(name, Subnet.SUBNET_NAME_LENGTH, "Subnet "
                            "name is too long")
    sub = Subnet.objects.create(name=name,
                                network=network,
                                cidr=cidr,
                                ipversion=ipversion,
                                gateway=gateway,
                                userid=network.userid,
                                public=network.public,
                                dhcp=dhcp,
                                host_routes=host_routes,
                                dns_nameservers=dns_nameservers)

    network.subnet_ids.append(sub.id)
    network.save()

    gateway_ip = ipaddr.IPAddress(gateway) if gateway else None

    if allocation_pools is not None:
        if ipversion == 6:
            raise api.faults.Conflict("Can't allocate an IP Pool in IPv6")
    elif ipversion == 4:
        # Check if the gateway is the first IP of the subnet, or the last. In
        # that case create a single ip pool.
        if gateway_ip:
            if int(gateway_ip) - int(cidr_ip) == 1:
                allocation_pools = [(gateway_ip + 1, cidr_ip.broadcast - 1)]
            elif int(cidr_ip.broadcast) - int(gateway_ip) == 1:
                allocation_pools = [(cidr_ip.network + 1, gateway_ip - 1)]
            else:
                # If the gateway isn't the first available ip, create two
                # different ip pools adjacent to said ip
                allocation_pools = [(cidr_ip.network + 1, gateway_ip - 1),
                                    (gateway_ip + 1, cidr_ip.broadcast - 1)]
        else:
            allocation_pools = [(cidr_ip.network + 1, cidr_ip.broadcast - 1)]

    if allocation_pools:
        # Validate the allocation pools
        validate_pools(allocation_pools, cidr_ip, gateway_ip)
        create_ip_pools(allocation_pools, cidr_ip, sub)

    return sub
Ejemplo n.º 19
0
def _create_subnet(network_id, user_id, cidr, name, ipversion=4, gateway=None,
                   dhcp=True, slaac=True, dns_nameservers=None,
                   allocation_pools=None, host_routes=None):
    """Create a subnet

    network_id and the desired cidr are mandatory, everything else is optional

    """

    try:
        network_id = int(network_id)
        network = Network.objects.select_for_update().get(id=network_id)
    except (ValueError, TypeError):
        raise api.faults.BadRequest("Malformed network ID")
    except Network.DoesNotExist:
        raise api.faults.ItemNotFound("No network found with that ID")

    if network.deleted:
        raise api.faults.BadRequest("Network has been deleted")

    if user_id != network.userid:
        raise api.faults.Forbidden("Forbidden operation")

    if ipversion not in [4, 6]:
        raise api.faults.BadRequest("Malformed IP version type")

    check_number_of_subnets(network, ipversion)

    if network.backend_networks.exists():
        raise api.faults.BadRequest("Cannot create subnet in network %s, VMs"
                                    " are already connected to this network" %
                                    network_id)

    try:
        cidr_ip = ipaddr.IPNetwork(cidr)
    except ValueError:
        raise api.faults.BadRequest("Malformed CIDR")

    if ipversion == 6:
        validate_subnet_params(subnet6=cidr, gateway6=gateway)
    else:
        validate_subnet_params(subnet=cidr, gateway=gateway)

    utils.check_name_length(name, Subnet.SUBNET_NAME_LENGTH, "Subnet "
                            "name is too long")
    sub = Subnet.objects.create(name=name, network=network, cidr=cidr,
                                ipversion=ipversion, gateway=gateway,
                                userid=network.userid, public=network.public,
                                dhcp=dhcp, host_routes=host_routes,
                                dns_nameservers=dns_nameservers)

    network.subnet_ids.append(sub.id)
    network.save()

    gateway_ip = ipaddr.IPAddress(gateway) if gateway else None

    if allocation_pools is not None:
        if ipversion == 6:
            raise api.faults.Conflict("Can't allocate an IP Pool in IPv6")
    elif ipversion == 4:
        # Check if the gateway is the first IP of the subnet, or the last. In
        # that case create a single ip pool.
        if gateway_ip:
            if int(gateway_ip) - int(cidr_ip) == 1:
                allocation_pools = [(gateway_ip + 1, cidr_ip.broadcast - 1)]
            elif int(cidr_ip.broadcast) - int(gateway_ip) == 1:
                allocation_pools = [(cidr_ip.network + 1, gateway_ip - 1)]
            else:
                # If the gateway isn't the first available ip, create two
                # different ip pools adjacent to said ip
                allocation_pools = [(cidr_ip.network + 1, gateway_ip - 1),
                                    (gateway_ip + 1, cidr_ip.broadcast - 1)]
        else:
            allocation_pools = [(cidr_ip.network + 1, cidr_ip.broadcast - 1)]

    if allocation_pools:
        # Validate the allocation pools
        validate_pools(allocation_pools, cidr_ip, gateway_ip)
        create_ip_pools(allocation_pools, cidr_ip, sub)

    return sub
Ejemplo n.º 20
0
def rename(network, name):
    utils.check_name_length(name, Network.NETWORK_NAME_LENGTH, "Network name "
                            "is too long")
    network.name = name
    network.save()
    return network
Ejemplo n.º 21
0
def _create_volume(user_id, project, size, source_type, source_uuid,
                   volume_type, name=None, description=None, index=None,
                   delete_on_termination=True, shared_to_project=False):
    """Create the volume in the DB.

    This function can be called from two different places:
    1) During server creation, when creating the volumes of a new server
    2) During volume creation.
    """
    utils.check_name_length(name, Volume.NAME_LENGTH,
                            "Volume name is too long")
    utils.check_name_length(description, Volume.DESCRIPTION_LENGTH,
                            "Volume description is too long")
    validate_volume_termination(volume_type, delete_on_termination)

    if size is not None:
        try:
            size = int(size)
        except (TypeError, ValueError):
            raise faults.BadRequest("Volume size must be a positive integer")
        if size < 1:
            raise faults.BadRequest("Volume size must be a positive integer")
        if size > settings.CYCLADES_VOLUME_MAX_SIZE:
            raise faults.BadRequest("Maximum volume size is %sGB" %
                                    settings.CYCLADES_VOLUME_MAX_SIZE)

    # Only ext_ disk template supports cloning from another source. Otherwise
    # it must be the root volume so that 'snf-image' fill the volume
    can_have_source = (index == 0 or
                       volume_type.provider in settings.GANETI_CLONE_PROVIDERS)
    if not can_have_source and source_type != "blank":
        msg = ("Cannot specify a 'source' attribute for volume type '%s' with"
               " disk template '%s'" %
               (volume_type.id, volume_type.disk_template))
        raise faults.BadRequest(msg)

    source_version = None
    origin_size = None
    # TODO: Check Volume/Snapshot Status
    if source_type == "snapshot":
        source_snapshot = util.get_snapshot(user_id, source_uuid,
                                            exception=faults.BadRequest)
        snap_status = source_snapshot.get("status", "").upper()
        if snap_status != OBJECT_AVAILABLE:
            raise faults.BadRequest("Cannot create volume from snapshot, while"
                                    " snapshot is in '%s' status" %
                                    snap_status)
        source = Volume.prefix_source(source_uuid,
                                      source_type="snapshot")
        if size is None:
            raise faults.BadRequest("Volume size is required")
        elif (size << 30) < int(source_snapshot["size"]):
            raise faults.BadRequest("Volume size '%s' is smaller than"
                                    " snapshot's size '%s'"
                                    % (size << 30, source_snapshot["size"]))
        source_version = source_snapshot["version"]
        origin = source_snapshot["mapfile"]
        origin_size = source_snapshot["size"]
    elif source_type == "image":
        source_image = util.get_image(user_id, source_uuid,
                                      exception=faults.BadRequest)
        img_status = source_image.get("status", "").upper()
        if img_status != OBJECT_AVAILABLE:
            raise faults.BadRequest("Cannot create volume from image, while"
                                    " image is in '%s' status" % img_status)
        if size is None:
            raise faults.BadRequest("Volume size is required")
        elif (size << 30) < int(source_image["size"]):
            raise faults.BadRequest("Volume size '%s' is smaller than"
                                    " image's size '%s'"
                                    % (size << 30, source_image["size"]))
        source = Volume.prefix_source(source_uuid, source_type="image")
        source_version = source_image["version"]
        origin = source_image["mapfile"]
        origin_size = source_image["size"]
    elif source_type == "blank":
        if size is None:
            raise faults.BadRequest("Volume size is required")
        source = origin = None
    elif source_type == "volume":
        # Currently, Archipelago does not support cloning a volume
        raise faults.BadRequest("Cloning a volume is not supported")
        # source_volume = util.get_volume(user_id, source_uuid,
        #                                 for_update=True, non_deleted=True,
        #                                 exception=faults.BadRequest)
        # if source_volume.status != "IN_USE":
        #     raise faults.BadRequest("Cannot clone volume while it is in '%s'"
        #                             " status" % source_volume.status)
        # # If no size is specified, use the size of the volume
        # if size is None:
        #     size = source_volume.size
        # elif size < source_volume.size:
        #     raise faults.BadRequest("Volume size cannot be smaller than the"
        #                             " source volume")
        # source = Volume.prefix_source(source_uuid, source_type="volume")
        # origin = source_volume.backend_volume_uuid
    else:
        raise faults.BadRequest("Unknown source type")

    volume = Volume.objects.create(userid=user_id,
                                   project=project,
                                   index=index,
                                   shared_to_project=shared_to_project,
                                   size=size,
                                   volume_type=volume_type,
                                   name=name,
                                   description=description,
                                   delete_on_termination=delete_on_termination,
                                   source=source,
                                   source_version=source_version,
                                   origin=origin,
                                   status="CREATING")

    # Store the size of the origin in the volume object but not in the DB.
    # We will have to change this in order to support detachable volumes.
    volume.origin_size = origin_size

    return volume
Ejemplo n.º 22
0
def create(credentials,
           name,
           password,
           flavor,
           image_id,
           metadata={},
           personality=[],
           networks=None,
           use_backend=None,
           project=None,
           volumes=None,
           helper=False,
           user_data="",
           shared_to_project=False,
           key_names=None):

    userid = credentials.userid
    utils.check_name_length(name, VirtualMachine.VIRTUAL_MACHINE_NAME_LENGTH,
                            "Server name is too long")

    # Get the image, if any, that is used for the first volume
    vol_image_id = None
    if volumes:
        vol = volumes[0]
        if vol["source_type"] in ["image", "snapshot"]:
            vol_image_id = vol["source_uuid"]

    # Check conflict between server's and volume's image
    if image_id and vol_image_id and image_id != vol_image_id:
        raise faults.BadRequest("The specified server's image is different"
                                " from the the source of the first volume.")
    elif vol_image_id and not image_id:
        image_id = vol_image_id
    elif not image_id:
        raise faults.BadRequest("You need to specify either an image or a"
                                " block device mapping.")

    if len(metadata) > settings.CYCLADES_VM_MAX_METADATA:
        raise faults.BadRequest("Virtual Machines cannot have more than %s "
                                "metadata items" %
                                settings.CYCLADES_VM_MAX_METADATA)
    # Get image info
    image = util.get_image_dict(image_id, userid)

    if not volumes:
        # If no volumes are specified, we automatically create a volume with
        # the size of the flavor and filled with the specified image.
        volumes = [{
            "source_type": "image",
            "source_uuid": image_id,
            "size": flavor.disk,
            "delete_on_termination": True
        }]
    assert (len(volumes) > 0), "Cannot create server without volumes"

    if volumes[0]["source_type"] == "blank":
        raise faults.BadRequest("Root volume cannot be blank")

    try:
        is_system = (image["owner"] == settings.SYSTEM_IMAGES_OWNER)
        img, created = Image.objects.get_or_create(uuid=image["id"],
                                                   version=image["version"])
        if created:
            img.owner = image["owner"]
            img.name = image["name"]
            img.location = image["location"]
            img.mapfile = image["mapfile"]
            img.is_public = image["is_public"]
            img.is_snapshot = image["is_snapshot"]
            img.is_system = is_system
            img.os = image["metadata"].get("OS", "unknown")
            img.osfamily = image["metadata"].get("OSFAMILY", "unknown")
            img.save()

    except Exception as e:
        # Image info is not critical. Continue if it fails for any reason
        log.warning("Failed to store image info: %s", e)

    if project is None:
        project = userid

    if use_backend is None:
        # Allocate server to a Ganeti backend
        use_backend = allocate_new_server(userid, project, flavor)

    if key_names is None:
        key_names = []

    auth_keys = '\n'.join(
        [util.get_keypair(key_name, userid).content for key_name in key_names])

    vm_id, port_ids, volume_ids, origin_sizes = _db_create_server(
        credentials, name, flavor, image, metadata, networks, use_backend,
        project, volumes, helper, shared_to_project, key_names)

    return _create_server(vm_id, port_ids, volume_ids, flavor, image,
                          personality, user_data, password, auth_keys,
                          origin_sizes)
Ejemplo n.º 23
0
def _create_port(userid, network, machine=None, use_ipaddress=None,
                 address=None, name="", security_groups=None,
                 device_owner=None):
    """Create a new port on the specified network.

    Create a new Port(NetworkInterface model) on the specified Network. If
    'machine' is specified, the machine will be connected to the network using
    this port. If 'use_ipaddress' argument is specified, the port will be
    assigned this IPAddress. Otherwise, an IPv4 address from the IPv4 subnet
    will be allocated.

    """
    if network.state != "ACTIVE":
        raise faults.Conflict("Cannot create port while network '%s' is in"
                              " '%s' status" % (network.id, network.state))
    elif network.action == "DESTROY":
        msg = "Cannot create port. Network %s is being deleted."
        raise faults.Conflict(msg % network.id)

    utils.check_name_length(name, NetworkInterface.NETWORK_IFACE_NAME_LENGTH,
                            "Port name is too long")

    ipaddress = None
    if use_ipaddress is not None:
        # Use an existing IPAddress object.
        ipaddress = use_ipaddress
        if ipaddress and (ipaddress.network_id != network.id):
            msg = "IP Address %s does not belong to network %s"
            raise faults.Conflict(msg % (ipaddress.address, network.id))
    else:
        # Do not allow allocation of new IPs if the network is drained
        if network.drained:
            raise faults.Conflict("Cannot create port while network %s is in"
                                  " 'SNF:DRAINED' status" % network.id)
        # If network has IPv4 subnets, try to allocate the address that the
        # the user specified or a random one.
        if network.subnets.filter(ipversion=4).exists():
            ipaddress = ips.allocate_ip(network, userid=userid,
                                        address=address)
        elif address is not None:
            raise faults.BadRequest("Address %s is not a valid IP for the"
                                    " defined network subnets" % address)

    if ipaddress is not None and ipaddress.nic is not None:
        raise faults.Conflict("IP address '%s' is already in use" %
                              ipaddress.address)

    port = NetworkInterface.objects.create(network=network,
                                           state="DOWN",
                                           userid=userid,
                                           device_owner=None,
                                           name=name)

    # add the security groups if any
    if security_groups:
        port.security_groups.add(*security_groups)

    if ipaddress is not None:
        # Associate IPAddress with the Port
        ipaddress.nic = port
        ipaddress.save()

    if machine is not None:
        # Connect port to the instance.
        machine = connect(machine, network, port)
        jobID = machine.task_job_id
        log.info("Created Port %s with IP %s. Ganeti Job: %s",
                 port, ipaddress, jobID)
    else:
        log.info("Created Port %s with IP %s not attached to any instance",
                 port, ipaddress)

    return port
Ejemplo n.º 24
0
def create(credentials, name, password, flavor, image_id, metadata={},
           personality=[], networks=None, use_backend=None, project=None,
           volumes=None, helper=False, user_data="",
           shared_to_project=False, key_names=None):

    userid = credentials.userid
    utils.check_name_length(name, VirtualMachine.VIRTUAL_MACHINE_NAME_LENGTH,
                            "Server name is too long")

    # Get the image, if any, that is used for the first volume
    vol_image_id = None
    if volumes:
        vol = volumes[0]
        if vol["source_type"] in ["image", "snapshot"]:
            vol_image_id = vol["source_uuid"]

    # Check conflict between server's and volume's image
    if image_id and vol_image_id and image_id != vol_image_id:
        raise faults.BadRequest("The specified server's image is different"
                                " from the the source of the first volume.")
    elif vol_image_id and not image_id:
        image_id = vol_image_id
    elif not image_id:
        raise faults.BadRequest("You need to specify either an image or a"
                                " block device mapping.")

    if len(metadata) > settings.CYCLADES_VM_MAX_METADATA:
        raise faults.BadRequest("Virtual Machines cannot have more than %s "
                                "metadata items" %
                                settings.CYCLADES_VM_MAX_METADATA)
    # Get image info
    image = util.get_image_dict(image_id, userid)

    if not volumes:
        # If no volumes are specified, we automatically create a volume with
        # the size of the flavor and filled with the specified image.
        volumes = [{"source_type": "image",
                    "source_uuid": image_id,
                    "size": flavor.disk,
                    "delete_on_termination": True}]
    assert(len(volumes) > 0), "Cannot create server without volumes"

    if volumes[0]["source_type"] == "blank":
        raise faults.BadRequest("Root volume cannot be blank")

    try:
        is_system = (image["owner"] == settings.SYSTEM_IMAGES_OWNER)
        img, created = Image.objects.get_or_create(uuid=image["id"],
                                                   version=image["version"])
        if created:
            img.owner = image["owner"]
            img.name = image["name"]
            img.location = image["location"]
            img.mapfile = image["mapfile"]
            img.is_public = image["is_public"]
            img.is_snapshot = image["is_snapshot"]
            img.is_system = is_system
            img.os = image["metadata"].get("OS", "unknown")
            img.osfamily = image["metadata"].get("OSFAMILY", "unknown")
            img.save()

    except Exception as e:
        # Image info is not critical. Continue if it fails for any reason
        log.warning("Failed to store image info: %s", e)

    if project is None:
        project = userid

    if use_backend is None:
        # Allocate server to a Ganeti backend
        use_backend = allocate_new_server(userid, project, flavor)

    if key_names is None:
        key_names = []

    auth_keys = '\n'.join([
        util.get_keypair(key_name, userid).content for key_name in key_names
    ])


    vm_id, port_ids, volume_ids, origin_sizes = _db_create_server(
        credentials, name, flavor, image, metadata, networks, use_backend,
        project, volumes, helper, shared_to_project,
        key_names)

    return _create_server(vm_id, port_ids, volume_ids, flavor, image,
                          personality, user_data, password, auth_keys,
                          origin_sizes)
Ejemplo n.º 25
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
Ejemplo n.º 26
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
Ejemplo n.º 27
0
def create(user_id,
           size,
           server_id,
           name=None,
           description=None,
           source_volume_id=None,
           source_snapshot_id=None,
           source_image_id=None,
           volume_type_id=None,
           metadata=None,
           project=None):

    # Currently we cannot create volumes without being attached to a server
    if server_id is None:
        raise faults.BadRequest("Volume must be attached to server")
    server = util.get_server(user_id,
                             server_id,
                             for_update=True,
                             non_deleted=True,
                             exception=faults.BadRequest)

    server_vtype = server.flavor.volume_type
    if volume_type_id is not None:
        volume_type = util.get_volume_type(volume_type_id,
                                           include_deleted=False,
                                           exception=faults.BadRequest)
        if volume_type != server_vtype:
            raise faults.BadRequest("Cannot create a volume with type '%s' to"
                                    " a server with volume type '%s'." %
                                    (volume_type.id, server_vtype.id))
    else:
        volume_type = server_vtype

    # Assert that not more than one source are used
    sources = filter(lambda x: x is not None,
                     [source_volume_id, source_snapshot_id, source_image_id])
    if len(sources) > 1:
        raise faults.BadRequest("Volume can not have more than one source!")

    if source_volume_id is not None:
        source_type = "volume"
        source_uuid = source_volume_id
    elif source_snapshot_id is not None:
        source_type = "snapshot"
        source_uuid = source_snapshot_id
    elif source_image_id is not None:
        source_type = "image"
        source_uuid = source_image_id
    else:
        source_type = "blank"
        source_uuid = None

    if project is None:
        project = user_id

    if metadata is not None and \
       len(metadata) > settings.CYCLADES_VOLUME_MAX_METADATA:
        raise faults.BadRequest("Volumes cannot have more than %s metadata "
                                "items" %
                                settings.CYCLADES_VOLUME_MAX_METADATA)

    volume = _create_volume(server,
                            user_id,
                            project,
                            size,
                            source_type,
                            source_uuid,
                            volume_type=volume_type,
                            name=name,
                            description=description,
                            index=None)

    if metadata is not None:
        for meta_key, meta_val in metadata.items():
            utils.check_name_length(meta_key, VolumeMetadata.KEY_LENGTH,
                                    "Metadata key is too long")
            utils.check_name_length(meta_val, VolumeMetadata.VALUE_LENGTH,
                                    "Metadata key is too long")
            volume.metadata.create(key=meta_key, value=meta_val)

    server_attachments.attach_volume(server, volume)

    return volume
Ejemplo n.º 28
0
def create(userid, name, password, flavor, image_id, metadata={},
           personality=[], networks=None, use_backend=None, project=None,
           volumes=None, helper=False, user_projects=None,
           shared_to_project=False):

    utils.check_name_length(name, VirtualMachine.VIRTUAL_MACHINE_NAME_LENGTH,
                            "Server name is too long")

    # Get the image, if any, that is used for the first volume
    vol_image_id = None
    if volumes:
        vol = volumes[0]
        if vol["source_type"] in ["image", "snapshot"]:
            vol_image_id = vol["source_uuid"]

    # Check conflict between server's and volume's image
    if image_id and vol_image_id and image_id != vol_image_id:
        raise faults.BadRequest("The specified server's image is different"
                                " from the the source of the first volume.")
    elif vol_image_id and not image_id:
        image_id = vol_image_id
    elif not image_id:
        raise faults.BadRequest("You need to specify either an image or a"
                                " block device mapping.")

    if len(metadata) > settings.CYCLADES_VM_MAX_METADATA:
        raise faults.BadRequest("Virtual Machines cannot have more than %s "
                                "metadata items" %
                                settings.CYCLADES_VM_MAX_METADATA)
    # Get image info
    image = util.get_image_dict(image_id, userid)

    if not volumes:
        # If no volumes are specified, we automatically create a volume with
        # the size of the flavor and filled with the specified image.
        volumes = [{"source_type": "image",
                    "source_uuid": image_id,
                    "size": flavor.disk,
                    "delete_on_termination": True}]
    assert(len(volumes) > 0), "Cannot create server without volumes"

    if volumes[0]["source_type"] == "blank":
        raise faults.BadRequest("Root volume cannot be blank")

    try:
        is_system = (image["owner"] == settings.SYSTEM_IMAGES_OWNER)
        img, created = Image.objects.get_or_create(uuid=image["id"],
                                                   version=image["version"])
        if created:
            img.owner = image["owner"]
            img.name = image["name"]
            img.location = image["location"]
            img.mapfile = image["mapfile"]
            img.is_public = image["is_public"]
            img.is_snapshot = image["is_snapshot"]
            img.is_system = is_system
            img.os = image["metadata"].get("OS", "unknown")
            img.osfamily = image["metadata"].get("OSFAMILY", "unknown")
            img.save()
    except Exception as e:
        # Image info is not critical. Continue if it fails for any reason
        log.warning("Failed to store image info: %s", e)

    if use_backend is None:
        # Allocate server to a Ganeti backend
        use_backend = allocate_new_server(userid, flavor)

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

    if project is None:
        project = userid

    # 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=userid,
                                       project=project,
                                       shared_to_project=shared_to_project,
                                       imageid=image["id"],
                                       image_version=image["version"],
                                       flavor=flavor,
                                       operstate="BUILD",
                                       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(userid, user_projects, 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=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)

    # Create the server in Ganeti.
    vm = create_server(vm, ports, server_volumes, flavor, image, personality,
                       password)

    return vm
Ejemplo n.º 29
0
def create(userid,
           name,
           password,
           flavor,
           image_id,
           metadata={},
           personality=[],
           networks=None,
           use_backend=None,
           project=None,
           volumes=None):

    utils.check_name_length(name, VirtualMachine.VIRTUAL_MACHINE_NAME_LENGTH,
                            "Server name is too long")

    # Get the image, if any, that is used for the first volume
    vol_image_id = None
    if volumes:
        vol = volumes[0]
        if vol["source_type"] in ["image", "snapshot"]:
            vol_image_id = vol["source_uuid"]

    # Check conflict between server's and volume's image
    if image_id and vol_image_id and image_id != vol_image_id:
        raise faults.BadRequest("The specified server's image is different"
                                " from the the source of the first volume.")
    elif vol_image_id and not image_id:
        image_id = vol_image_id
    elif not image_id:
        raise faults.BadRequest("You need to specify either an image or a"
                                " block device mapping.")

    if len(metadata) > settings.CYCLADES_VM_MAX_METADATA:
        raise faults.BadRequest("Virtual Machines cannot have more than %s "
                                "metadata items" %
                                settings.CYCLADES_VM_MAX_METADATA)
    # Get image info
    image = util.get_image_dict(image_id, userid)

    if not volumes:
        # If no volumes are specified, we automatically create a volume with
        # the size of the flavor and filled with the specified image.
        volumes = [{
            "source_type": "image",
            "source_uuid": image_id,
            "size": flavor.disk,
            "delete_on_termination": True
        }]
    assert (len(volumes) > 0), "Cannot create server without volumes"

    if volumes[0]["source_type"] == "blank":
        raise faults.BadRequest("Root volume cannot be blank")

    try:
        is_system = (image["owner"] == settings.SYSTEM_IMAGES_OWNER)
        img, created = Image.objects.get_or_create(uuid=image["id"],
                                                   version=image["version"])
        if created:
            img.owner = image["owner"]
            img.name = image["name"]
            img.location = image["location"]
            img.mapfile = image["mapfile"]
            img.is_public = image["is_public"]
            img.is_snapshot = image["is_snapshot"]
            img.is_system = is_system
            img.os = image["metadata"].get("OS", "unknown")
            img.osfamily = image["metadata"].get("OSFAMILY", "unknown")
            img.save()
    except Exception as e:
        # Image info is not critical. Continue if it fails for any reason
        log.warning("Failed to store image info: %s", e)

    if use_backend is None:
        # Allocate server to a Ganeti backend
        use_backend = allocate_new_server(userid, flavor)

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

    if project is None:
        project = userid

    # 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=userid,
                                       project=project,
                                       imageid=image["id"],
                                       image_version=image["version"],
                                       flavor=flavor,
                                       operstate="BUILD")
    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(userid,
                           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"]
            v.machine = vm
            v.index = index
            v.save()
        else:
            v = _create_volume(server=vm,
                               user_id=userid,
                               volume_type=server_vtype,
                               project=project,
                               index=index,
                               **vol_info)
        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)

    # Create the server in Ganeti.
    vm = create_server(vm, ports, server_volumes, flavor, image, personality,
                       password)

    return vm
Ejemplo n.º 30
0
def rename(network, name):
    utils.check_name_length(name, Network.NETWORK_NAME_LENGTH, "Network name "
                            "is too long")
    network.name = name
    network.save()
    return network
Ejemplo n.º 31
0
def create(user_id, size, server_id, name=None, description=None,
           source_volume_id=None, source_snapshot_id=None,
           source_image_id=None, volume_type_id=None, metadata=None,
           project=None):

    # Currently we cannot create volumes without being attached to a server
    if server_id is None:
        raise faults.BadRequest("Volume must be attached to server")
    server = util.get_server(user_id, server_id, for_update=True,
                             non_deleted=True,
                             exception=faults.BadRequest)

    server_vtype = server.flavor.volume_type
    if volume_type_id is not None:
        volume_type = util.get_volume_type(volume_type_id,
                                           include_deleted=False,
                                           exception=faults.BadRequest)
        if volume_type != server_vtype:
            raise faults.BadRequest("Cannot create a volume with type '%s' to"
                                    " a server with volume type '%s'."
                                    % (volume_type.id, server_vtype.id))
    else:
        volume_type = server_vtype

    # Assert that not more than one source are used
    sources = filter(lambda x: x is not None,
                     [source_volume_id, source_snapshot_id, source_image_id])
    if len(sources) > 1:
        raise faults.BadRequest("Volume can not have more than one source!")

    if source_volume_id is not None:
        source_type = "volume"
        source_uuid = source_volume_id
    elif source_snapshot_id is not None:
        source_type = "snapshot"
        source_uuid = source_snapshot_id
    elif source_image_id is not None:
        source_type = "image"
        source_uuid = source_image_id
    else:
        source_type = "blank"
        source_uuid = None

    if project is None:
        project = user_id

    if metadata is not None and \
       len(metadata) > settings.CYCLADES_VOLUME_MAX_METADATA:
        raise faults.BadRequest("Volumes cannot have more than %s metadata "
                                "items" %
                                settings.CYCLADES_VOLUME_MAX_METADATA)

    volume = _create_volume(server, user_id, project, size,
                            source_type, source_uuid,
                            volume_type=volume_type, name=name,
                            description=description, index=None)

    if metadata is not None:
        for meta_key, meta_val in metadata.items():
            utils.check_name_length(meta_key, VolumeMetadata.KEY_LENGTH,
                                    "Metadata key is too long")
            utils.check_name_length(meta_val, VolumeMetadata.VALUE_LENGTH,
                                    "Metadata key is too long")
            volume.metadata.create(key=meta_key, value=meta_val)

    server_attachments.attach_volume(server, volume)

    return volume
Ejemplo n.º 32
0
def _create_port(userid,
                 network,
                 machine=None,
                 use_ipaddress=None,
                 address=None,
                 name="",
                 security_groups=None,
                 device_owner=None):
    """Create a new port on the specified network.

    Create a new Port(NetworkInterface model) on the specified Network. If
    'machine' is specified, the machine will be connected to the network using
    this port. If 'use_ipaddress' argument is specified, the port will be
    assigned this IPAddress. Otherwise, an IPv4 address from the IPv4 subnet
    will be allocated.

    """
    if network.state != "ACTIVE":
        raise faults.Conflict("Cannot create port while network '%s' is in"
                              " '%s' status" % (network.id, network.state))
    elif network.action == "DESTROY":
        msg = "Cannot create port. Network %s is being deleted."
        raise faults.Conflict(msg % network.id)
    elif network.drained:
        raise faults.Conflict("Cannot create port while network %s is in"
                              " 'SNF:DRAINED' status" % network.id)

    utils.check_name_length(name, NetworkInterface.NETWORK_IFACE_NAME_LENGTH,
                            "Port name is too long")

    ipaddress = None
    if use_ipaddress is not None:
        # Use an existing IPAddress object.
        ipaddress = use_ipaddress
        if ipaddress and (ipaddress.network_id != network.id):
            msg = "IP Address %s does not belong to network %s"
            raise faults.Conflict(msg % (ipaddress.address, network.id))
    else:
        # If network has IPv4 subnets, try to allocate the address that the
        # the user specified or a random one.
        if network.subnets.filter(ipversion=4).exists():
            ipaddress = ips.allocate_ip(network,
                                        userid=userid,
                                        address=address)
        elif address is not None:
            raise faults.BadRequest("Address %s is not a valid IP for the"
                                    " defined network subnets" % address)

    if ipaddress is not None and ipaddress.nic is not None:
        raise faults.Conflict("IP address '%s' is already in use" %
                              ipaddress.address)

    port = NetworkInterface.objects.create(network=network,
                                           state="DOWN",
                                           userid=userid,
                                           device_owner=None,
                                           name=name)

    # add the security groups if any
    if security_groups:
        port.security_groups.add(*security_groups)

    if ipaddress is not None:
        # Associate IPAddress with the Port
        ipaddress.nic = port
        ipaddress.save()

    if machine is not None:
        # Connect port to the instance.
        machine = connect(machine, network, port)
        jobID = machine.task_job_id
        log.info("Created Port %s with IP %s. Ganeti Job: %s", port, ipaddress,
                 jobID)
    else:
        log.info("Created Port %s with IP %s not attached to any instance",
                 port, ipaddress)

    return port
Ejemplo n.º 33
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})