def on_post(self, req, resp, tenant_id):
        body = json.loads(req.stream.read().decode())
        try:
            name = body['keypair']['name']
            key = body['keypair'].get('public_key', generate_random_key())
        except (KeyError, TypeError):
            return error_handling.bad_request(
                resp, 'Not all fields exist to create keypair.')

        validate_result = validate_keypair_name(resp, name)
        if not validate_result:
            return

        client = req.sl_client
        mgr = SoftLayer.SshKeyManager(client)

        # Make sure the key with that label doesn't already exist
        existing_keys = mgr.list_keys(label=name)
        if existing_keys:
            return error_handling.duplicate(resp, 'Duplicate key by that name')

        try:
            keypair = mgr.add_key(key, name)
            resp.body = {'keypair': format_keypair(keypair)}
        except SoftLayer.SoftLayerAPIError as e:
            if 'Unable to generate a fingerprint' in e.faultString:
                return error_handling.bad_request(resp, e.faultString)
            if 'SSH key already exists' in e.faultString:
                return error_handling.duplicate(resp, e.faultString)
            raise
Exemple #2
0
    def on_post(self, req, resp, tenant_id):
        body = json.loads(req.stream.read().decode())
        try:
            name = body['keypair']['name']
            key = body['keypair'].get('public_key', generate_random_key())
        except (KeyError, TypeError):
            return error_handling.bad_request(
                resp, 'Not all fields exist to create keypair.')

        validate_result = validate_keypair_name(resp, name)
        if not validate_result:
            return

        client = req.env['sl_client']
        mgr = SoftLayer.SshKeyManager(client)

        # Make sure the key with that label doesn't already exist
        existing_keys = mgr.list_keys(label=name)
        if existing_keys:
            return error_handling.duplicate(resp, 'Duplicate key by that name')

        try:
            keypair = mgr.add_key(key, name)
            resp.body = {'keypair': format_keypair(keypair)}
        except SoftLayer.SoftLayerAPIError as e:
            if 'Unable to generate a fingerprint' in e.faultString:
                return error_handling.bad_request(resp, e.faultString)
            if 'SSH key already exists' in e.faultString:
                return error_handling.duplicate(resp, e.faultString)
            raise
Exemple #3
0
def validate_keypair_name(resp, key_name):
    safechars = "_- " + string.digits + string.ascii_letters
    clean_value = "".join(x for x in key_name if x in safechars)
    if clean_value != key_name:
        error_handling.bad_request(
            resp, 'Keypair name contains unsafe characters')
        return False

    if not 0 < len(key_name) < 256:
        error_handling.bad_request(
            resp, 'Keypair name must be between 1 and 255 characters long')
        return False

    return True
Exemple #4
0
    def on_get(self, req, resp, tenant_id, flavor_id):
        '''Returns the extra specs for a particular flavor

        '''
        for flavor in self.flavors:
            if str(flavor_id) == flavor['id']:
                extra_specs = flavor['extra_specs']
                resp.status = 200
                resp.body = {'extra_specs': extra_specs}
                return
            else:
                error_handling.bad_request(resp, message="Invalid Flavor ID "
                                           "requested.")
        return
def validate_keypair_name(resp, key_name):
    safechars = "_- " + string.digits + string.ascii_letters
    clean_value = "".join(x for x in key_name if x in safechars)
    if clean_value != key_name:
        error_handling.bad_request(
            resp, 'Keypair name contains unsafe characters')
        return False

    if not 0 < len(key_name) < 256:
        error_handling.bad_request(
            resp, 'Keypair name must be between 1 and 255 characters long')
        return False

    return True
Exemple #6
0
    def on_post(self, req, resp, tenant_id=None):
        body = json.loads(req.stream.read().decode())

        image_id = body.get('id', str(uuid.uuid4()))
        url = body.get('direct_url')
        osRefCode = body.get('os_version', None)
        if not all([url, osRefCode]):
            raise bad_request(resp, "Swift url and OS code must be given")

        configuration = {
            'name': body.get('name'),
            'note': '',
            'operatingSystemReferenceCode': osRefCode,
            'uri': url
        }

        image_service = req.env['sl_client'][
            'SoftLayer_Virtual_Guest_Block_Device_Template_Group']
        img = image_service.createFromExternalSource(configuration)
        resp.body = {
            'id': img['globalIdentifier'],
            'name': body['name'],
            'status': 'queued',
            'visibility': 'private',
            'tags': [],
            'created_at': img['createDate'],
            'updated_at': img['createDate'],
            'self': self.app.get_endpoint_url(
                'image', req, 'v2_image', image_guid=image_id),
            'file': self.app.get_endpoint_url(
                'image', req, 'v2_image_file', image_guid=image_id),
            'schema': self.app.get_endpoint_url('image',
                                                req,
                                                'v2_schema_image'),
        }
Exemple #7
0
    def on_post(self, req, resp, tenant_id):
        """Create volume (SL Portable storage)."""
        client = req.env['sl_client']

        try:
            body = json.loads(req.stream.read().decode())
            # required field in the create volume payload
            namestr = body['volume'].get("display_name")
            volreq = body['volume']
            # portable storage order cannot have empty name
            name = (config.CONF['volume']['volume_name_prefix'] +
                    (namestr if namestr else ""))

            # size is required option for volume create. Throw type exception
            # if it is invalid
            size = int(volreq['size'])
            # availability_zone is optional, don't throw exception if
            # it is not available
            availability_zone = (
                body['volume'].get('availability_zone')
                or config.CONF['volume']['default_availability_zone'])
            volume_type = body['volume'].get('volume_type')

        except Exception:
            return error_handling.bad_request(resp, 'Malformed request body')

        try:
            volinfo = self._create_volume(tenant_id, client, resp,
                                          size, name=name,
                                          zone=availability_zone,
                                          volume_type=volume_type)

            resp.status = HTTP.ACCEPTED

            if volinfo:
                resp.body = {'volume':
                             format_volume(tenant_id, volinfo, client)}
                resp.body['volume'].update({'status': 'creating'})
            else:
                # Cannot generate a valid response without knowning
                # the volume id when order takes too long to complete.
                # This should be a rare case, but it could break openstack
                # since the volume create caller always expect a volume id
                # uppon successful return. The approach here is to fail
                # the volume create operation and leak one portable storage
                # volume. User can always cancel from SL portal.
                return error_handling.volume_fault(
                    resp, "Portable storage order delayed")

        except SoftLayer.SoftLayerAPIError as e:
            return error_handling.error(resp,
                                        "SoftLayerAPIError",
                                        e.faultString,
                                        code=HTTP.INTERNAL_SERVER_ERROR)
        except Exception as e:
            return error_handling.volume_fault(resp, str(e))
Exemple #8
0
    def on_get(self, req, resp, tenant_id, flavor_id, key_id):
        '''Returns the requested key from the optional extra specs

        '''
        for flavor in self.flavors:
            if str(flavor_id) == flavor['id']:
                extra_specs = flavor['extra_specs']
                if key_id in extra_specs:
                    resp.status = 200
                    resp.body = {key_id: extra_specs[key_id]}
                    return
                else:
                    error_handling.bad_request(resp, message="Invalid Key ID "
                                               "requested")
                    return
            else:
                error_handling.bad_request(resp, message="Invalid Flavor ID "
                                           "requested.")
                return
Exemple #9
0
    def on_post(self, req, resp, tenant_id):
        payload = {}
        client = req.env['sl_client']
        body = json.loads(req.stream.read().decode())

        payload['hostname'] = body['server']['name']
        payload['domain'] = config.CONF['default_domain'] or 'jumpgate.com'
        payload['image_id'] = body['server']['imageRef']

        # TODO(kmcdonald) - How do we set this accurately?
        payload['hourly'] = True

        networks = utils.lookup(body, 'server', 'networks')
        cci = SoftLayer.CCIManager(client)

        try:
            self._handle_flavor(payload, body)
            self._handle_sshkeys(payload, body, client)
            self._handle_user_data(payload, body)
            self._handle_datacenter(payload, body)
            if networks:
                self._handle_network(payload, client, networks)
            new_instance = cci.create_instance(**payload)
        except Exception as e:
            return error_handling.bad_request(resp, message=str(e))

        # This should be the first tag that the VS set. Adding any more tags
        # will replace this tag
        try:
            flavor_id = int(body['server'].get('flavorRef'))
            vs = client['Virtual_Guest']
            vs.setTags('{"flavor_id": ' + str(flavor_id) + '}',
                       id=new_instance['id'])
        except Exception:
            pass

        resp.set_header('x-compute-request-id', 'create')
        resp.status = 202
        resp.body = {
            'server': {
                'id':
                new_instance['id'],
                'links': [{
                    'href':
                    self.app.get_endpoint_url('compute',
                                              req,
                                              'v2_server',
                                              instance_id=new_instance['id']),
                    'rel':
                    'self'
                }],
                'adminPass':
                '',
            }
        }
Exemple #10
0
    def on_get(self, req, resp, tenant_id, volume_id):

        client = req.env['sl_client']

        if volume_id and len(volume_id) <= OPENSTACK_VOLUME_UUID_LEN:
            # show volume details by volume id
            # /v1/{tenant_id}/volumes/{volume_id}
            self._show_volume(tenant_id, volume_id, client, req, resp)
        else:
            return error_handling.bad_request(resp,
                                              message="Malformed request body")
Exemple #11
0
    def on_delete(self, req, resp, tenant_id, volume_id):

        client = req.env['sl_client']

        if volume_id and len(volume_id) <= OPENSTACK_VOLUME_UUID_LEN:
            # show volume details by volume id
            # /v1/{tenant_id}/volumes/{volume_id}
            self._delete_volume(tenant_id, volume_id, client, req, resp)
        else:
            return error_handling.bad_request(resp,
                                              message="Invalid volume Id")
Exemple #12
0
def filter_flavor_refs(req, resp, flavor_refs):
    if req.get_param("marker") is not None:
        marker = req.get_param("marker")
        flavor_refs = [f for f in flavor_refs if str(f["id"]) > marker]

    if req.get_param("minDisk") is not None:
        try:
            min_disk = int(req.get_param("minDisk"))
            flavor_refs = [f for f in flavor_refs if f["disk"] >= min_disk]
        except ValueError:
            bad_request(resp, message="Invalid minDisk parameter.")
            return

    if req.get_param("minRam") is not None:
        try:
            min_ram = int(req.get_param("minRam"))
            flavor_refs = [f for f in flavor_refs if f["ram"] >= min_ram]
        except ValueError:
            bad_request(resp, message="Invalid minRam parameter.")
            return

    if req.get_param("limit") is not None:
        try:
            limit = int(req.get_param("limit"))
            flavor_refs = flavor_refs[:limit]
        except ValueError:
            bad_request(resp, message="Invalid limit parameter.")
            return

    return flavor_refs
Exemple #13
0
def filter_flavor_refs(req, resp, flavor_refs):
    if req.get_param('marker') is not None:
        marker = req.get_param('marker')
        flavor_refs = [f for f in flavor_refs if str(f['id']) > marker]

    if req.get_param('minDisk') is not None:
        try:
            min_disk = int(req.get_param('minDisk'))
            flavor_refs = [f for f in flavor_refs
                           if f['disk'] >= min_disk]
        except ValueError:
            error_handling.bad_request(resp,
                                       message="Invalid minDisk parameter.")
            return

    if req.get_param('minRam') is not None:
        try:
            min_ram = int(req.get_param('minRam'))
            flavor_refs = [f for f in flavor_refs if f['ram'] >= min_ram]
        except ValueError:
            error_handling.bad_request(resp,
                                       message="Invalid minRam parameter.")
            return

    if req.get_param('limit') is not None:
        try:
            limit = int(req.get_param('limit'))
            flavor_refs = flavor_refs[:limit]
        except ValueError:
            error_handling.bad_request(resp,
                                       message="Invalid limit parameter.")
            return

    return flavor_refs
Exemple #14
0
    def on_delete(self, req, resp, tenant_id, server_id):
        client = req.env["sl_client"]
        cci = CCIManager(client)

        try:
            cci.cancel_instance(server_id)
        except SoftLayerAPIError as e:
            if "active transaction" in e.faultString:
                return bad_request(
                    resp, message="Can not cancel an instance when there is already" " an active transaction", code=409
                )
            raise
        resp.status = 204
Exemple #15
0
    def on_delete(self, req, resp, tenant_id, server_id):
        client = req.env['sl_client']
        cci = SoftLayer.CCIManager(client)

        try:
            cci.cancel_instance(server_id)
        except SoftLayer.SoftLayerAPIError as e:
            if 'active transaction' in e.faultString:
                return error_handling.bad_request(
                    resp,
                    message='Can not cancel an instance when there is already'
                    ' an active transaction', code=409)
            raise
        resp.status = 204
Exemple #16
0
    def on_post(self, req, resp, tenant_id):
        payload = {}
        client = req.env['sl_client']
        body = json.loads(req.stream.read().decode())

        payload['hostname'] = body['server']['name']
        payload['domain'] = config.CONF['default_domain'] or 'jumpgate.com'
        payload['image_id'] = body['server']['imageRef']

        # TODO(kmcdonald) - How do we set this accurately?
        payload['hourly'] = True

        networks = utils.lookup(body, 'server', 'networks')
        cci = SoftLayer.CCIManager(client)

        try:
            self._handle_flavor(payload, body)
            self._handle_sshkeys(payload, body, client)
            self._handle_user_data(payload, body)
            self._handle_datacenter(payload, body)
            if networks:
                self._handle_network(payload, client, networks)
            new_instance = cci.create_instance(**payload)
        except Exception as e:
            return error_handling.bad_request(resp, message=str(e))

        # This should be the first tag that the VS set. Adding any more tags
        # will replace this tag
        try:
            flavor_id = int(body['server'].get('flavorRef'))
            vs = client['Virtual_Guest']
            vs.setTags('{"flavor_id": ' + str(flavor_id) + '}',
                       id=new_instance['id'])
        except Exception:
            pass

        resp.set_header('x-compute-request-id', 'create')
        resp.status = 202
        resp.body = {'server': {
            # Casted to string to make tempest pass
            'id': str(new_instance['id']),
            'links': [{
                'href': self.app.get_endpoint_url(
                    'compute', req, 'v2_server',
                    instance_id=new_instance['id']),
                'rel': 'self'}],
            'adminPass': '',
            # TODO(imkarrer) - Added security_groups to make tempest pass, need real groups  # noqa
            'security_groups': []
        }}
Exemple #17
0
    def on_put(self, req, resp, tenant_id, server_id):
        client = req.env['sl_client']
        cci = CCIManager(client)
        body = json.loads(req.stream.read().decode())

        if 'name' in lookup(body, 'server'):
            if lookup(body, 'server', 'name').strip() == '':
                return bad_request(resp, message='Server name is blank')

            cci.edit(server_id, hostname=lookup(body, 'server', 'name'))

        instance = cci.get_instance(server_id, mask=get_virtual_guest_mask())

        results = get_server_details_dict(self.app, req, instance)
        resp.body = {'server': results}
Exemple #18
0
    def on_put(self, req, resp, tenant_id, server_id):
        client = req.env["sl_client"]
        cci = CCIManager(client)
        body = json.loads(req.stream.read().decode())

        if "name" in lookup(body, "server"):
            if lookup(body, "server", "name").strip() == "":
                return bad_request(resp, message="Server name is blank")

            cci.edit(server_id, hostname=lookup(body, "server", "name"))

        instance = cci.get_instance(server_id, mask=get_virtual_guest_mask())

        results = get_server_details_dict(self.app, req, instance)
        resp.body = {"server": results}
Exemple #19
0
    def on_delete(self, req, resp, tenant_id, server_id):
        client = req.env['sl_client']
        cci = CCIManager(client)

        try:
            cci.cancel_instance(server_id)
        except SoftLayerAPIError as e:
            if 'active transaction' in e.faultString:
                return bad_request(
                    resp,
                    message='Can not cancel an instance when there is already'
                    ' an active transaction',
                    code=409)
            raise
        resp.status = 204
Exemple #20
0
    def on_put(self, req, resp, tenant_id, server_id):
        client = req.sl_client
        vs = SoftLayer.VSManager(client)
        body = json.loads(req.stream.read().decode())

        if 'name' in utils.lookup(body, 'server'):
            if utils.lookup(body, 'server', 'name').strip() == '':
                return error_handling.bad_request(
                    resp, message='Server name is blank')

            vs.edit(server_id, hostname=utils.lookup(body, 'server', 'name'))

        instance = vs.get_instance(server_id, mask=get_virtual_guest_mask())

        results = get_server_details_dict(self.app, req, instance, False)
        resp.body = {'server': results}
Exemple #21
0
    def on_put(self, req, resp, tenant_id, server_id):
        client = req.env['sl_client']
        cci = CCIManager(client)
        body = json.loads(req.stream.read().decode())

        if 'name' in lookup(body, 'server'):
            if lookup(body, 'server', 'name').strip() == '':
                return bad_request(resp, message='Server name is blank')

            cci.edit(server_id, hostname=lookup(body, 'server', 'name'))

        instance = cci.get_instance(server_id,
                                    mask=get_virtual_guest_mask())

        results = get_server_details_dict(self.app, req, instance)
        resp.body = {'server': results}
def get_volume(req, resp, tenant_id, volume_id=None):
    LOG.debug("Retrieving information for volume with id: %s", volume_id)

    # volume id are represented by uuuid.uuid4()
    if volume_id and len(volume_id) > OPENSTACK_VOLUME_UUID_LEN:
        return error_handling.bad_request(resp,
                                          message='Volume ID is too long; '
                                          'must be less than 11 characters '
                                          'in length')
    client = req.sl_client

    iscsi = client['Network_Storage_Iscsi']
    vol = iscsi.getObject(id=volume_id, mask=get_network_storage_mask())
    LOG.debug("volume returned from softlayer: %s", vol)
    resp.body = {'volume': format_volume(tenant_id, vol)}
    resp.status = HTTP.OK
    LOG.debug("response for volume details: %s", resp.body)
Exemple #23
0
    def on_get(self, req, resp, tenant_id, instance_id, volume_id):
        '''Shows details for the specified volume attachment.'''
        try:
            instance_id = int(instance_id)
        except Exception:
            return error_handling.not_found(resp,
                                            "Invalid instance ID specified.")

        if volume_id and len(volume_id) > OPENSTACK_VOLUME_UUID_LEN:
            return error_handling.bad_request(resp,
                                              message="Malformed request body")

        # since detail has the same info as the input request params, we can
        # just return the values back in the response using the request params.
        # But instead we will do sanity check to ensure the volume_id belongs
        # to the instance.
        vg_client = req.sl_client['Virtual_Guest']
        try:
            blkDevices = vg_client.getBlockDevices(mask='id, diskImage.type',
                                                   id=instance_id)
            vols = [
                x for x in blkDevices
                if x['diskImage']['type']['keyName'] != 'SWAP'
            ]
            for vol in vols:
                json_response = None
                vol_disk_id = vol['diskImage']['id']
                if str(vol_disk_id) == volume_id:
                    json_response = {
                        "volumeAttachment": {
                            "device": "",
                            "id": vol_disk_id,
                            "serverId": instance_id,
                            "volumeId": vol_disk_id
                        }
                    }
                    break
            if json_response:
                resp.body = json_response
            else:
                return error_handling.volume_fault(resp,
                                                   'Invalid volume id.',
                                                   code=HTTP.BAD_REQUEST)
        except Exception as e:
            return error_handling.volume_fault(resp, e.faultString)
Exemple #24
0
    def on_delete(self, req, resp, tenant_id, instance_id, volume_id):
        """Detach the requested volume from the specified instance."""
        try:
            instance_id = int(instance_id)
        except Exception:
            return error_handling.not_found(resp,
                                            "Invalid instance ID specified.")

        if volume_id and len(volume_id) > OPENSTACK_VOLUME_UUID_LEN:
            return error_handling.bad_request(resp,
                                              message="Malformed request body")

        vdi_client = req.env['sl_client']['Virtual_Disk_Image']

        # first let's check if the volume is already attached
        try:
            volinfo = vdi_client.getObject(id=volume_id, mask='blockDevices')
            blkDevices = volinfo['blockDevices']
            if len(blkDevices) > 0:
                guestId_list = [blkDevice['guestId'] for blkDevice
                                in blkDevices]
                for guest_id in guestId_list:
                    if guest_id == instance_id:
                        try:
                            # detach the volume here
                            vg_client = req.env['sl_client']['Virtual_Guest']
                            vg_client.detachDiskImage(volume_id,
                                                      id=instance_id)
                            break
                        except Exception as e:
                            error_handling.volume_fault(resp,
                                                        e.faultString)
                    else:
                        return error_handling.volume_fault(
                            resp,
                            'The requested disk image is attached to another '
                            'guest and cannot be detached.',
                            code=HTTP.BAD_REQUEST)

        except Exception as e:
            return error_handling.volume_fault(resp, e.faultString,
                                               code=500)

        resp.status = HTTP.ACCEPTED
Exemple #25
0
    def on_delete(self, req, resp, tenant_id, instance_id, volume_id):
        """Detach the requested volume from the specified instance."""
        try:
            instance_id = int(instance_id)
        except Exception:
            return error_handling.not_found(resp,
                                            "Invalid instance ID specified.")

        if volume_id and len(volume_id) > OPENSTACK_VOLUME_UUID_LEN:
            return error_handling.bad_request(resp,
                                              message="Malformed request body")

        vdi_client = req.sl_client['Virtual_Disk_Image']

        # first let's check if the volume is already attached
        try:
            volinfo = vdi_client.getObject(id=volume_id, mask='blockDevices')
            blkDevices = volinfo['blockDevices']
            if len(blkDevices) > 0:
                guestId_list = [
                    blkDevice['guestId'] for blkDevice in blkDevices
                ]
                for guest_id in guestId_list:
                    if guest_id == instance_id:
                        try:
                            # detach the volume here
                            vg_client = req.sl_client['Virtual_Guest']
                            vg_client.detachDiskImage(volume_id,
                                                      id=instance_id)
                            break
                        except Exception as e:
                            error_handling.volume_fault(resp, e.faultString)
                    else:
                        return error_handling.volume_fault(
                            resp,
                            'The requested disk image is attached to another '
                            'guest and cannot be detached.',
                            code=HTTP.BAD_REQUEST)

        except Exception as e:
            return error_handling.volume_fault(resp, e.faultString, code=500)

        resp.status = HTTP.ACCEPTED
Exemple #26
0
    def on_get(self, req, resp, subnet_id):
        """Shows information for a specified subnet. (subnet-show)

        @param req: Http Request body
        @param resp: Http Response body
        @param subnet_id: subnet id
        @return: Bad request if the id is not a valid integer
        """
        client = req.env['sl_client']
        tenant_id = req.env['auth']['tenant_id']
        try:
            subnet_id = int(subnet_id)
        except Exception:
            return error_handling.bad_request(resp,
                                              message="Malformed request body")

        subnet = client['Network_Subnet'].getObject(id=subnet_id,
                                                    mask=SUBNET_MASK)
        resp.body = {'subnet': format_subnetwork(subnet, tenant_id)}
        resp.status = 200
Exemple #27
0
    def on_get(self, req, resp, subnet_id):
        """Shows information for a specified subnet. (subnet-show)

        @param req: Http Request body
        @param resp: Http Response body
        @param subnet_id: subnet id
        @return: Bad request if the id is not a valid integer
        """
        client = req.sl_client
        tenant_id = req.env['auth']['tenant_id']
        try:
            subnet_id = int(subnet_id)
        except Exception:
            return error_handling.bad_request(resp,
                                              message="Malformed request body")

        subnet = client['Network_Subnet'].getObject(id=subnet_id,
                                                    mask=SUBNET_MASK)
        resp.body = {'subnet': format_subnetwork(subnet, tenant_id)}
        resp.status = 200
Exemple #28
0
    def on_get(self, req, resp, network_id):
        """Shows information for a specified network. (net-show)

        @param req: Http Request body
        @param resp: Http Response body
        @param network_id: Network Id
        @return: Http status
        """
        client = req.env['sl_client']
        tenant_id = req.env['auth']['tenant_id']
        try:
            network_id = int(network_id)
        except Exception:
            return error_handling.bad_request(resp,
                                              message="Malformed request body")

        vlan = client['Network_Vlan'].getObject(id=network_id,
                                                mask=NETWORK_MASK)

        resp.body = {'network': format_network(vlan, tenant_id)}
        resp.status = 200
Exemple #29
0
    def on_get(self, req, resp, network_id):
        """Shows information for a specified network. (net-show)

        @param req: Http Request body
        @param resp: Http Response body
        @param network_id: Network Id
        @return: Http status
        """
        client = req.env['sl_client']
        tenant_id = req.env['auth']['tenant_id']
        try:
            network_id = int(network_id)
        except Exception:
            return error_handling.bad_request(resp,
                                              message="Malformed request body")

        vlan = client['Network_Vlan'].getObject(id=network_id,
                                                mask=NETWORK_MASK)

        resp.body = {'network': format_network(vlan, tenant_id)}
        resp.status = 200
Exemple #30
0
    def on_get(self, req, resp, tenant_id, instance_id, volume_id):
        '''Shows details for the specified volume attachment.'''
        try:
            instance_id = int(instance_id)
        except Exception:
            return error_handling.not_found(resp,
                                            "Invalid instance ID specified.")

        if volume_id and len(volume_id) > OPENSTACK_VOLUME_UUID_LEN:
            return error_handling.bad_request(resp,
                                              message="Malformed request body")

        # since detail has the same info as the input request params, we can
        # just return the values back in the response using the request params.
        # But instead we will do sanity check to ensure the volume_id belongs
        # to the instance.
        vg_client = req.env['sl_client']['Virtual_Guest']
        try:
            blkDevices = vg_client.getBlockDevices(mask='id, diskImage.type',
                                                   id=instance_id)
            vols = [x for x in blkDevices
                    if x['diskImage']['type']['keyName'] != 'SWAP']
            for vol in vols:
                json_response = None
                vol_disk_id = vol['diskImage']['id']
                if str(vol_disk_id) == volume_id:
                    json_response = {"volumeAttachment":
                                     {"device": "", "id": vol_disk_id,
                                      "serverId": instance_id,
                                      "volumeId": vol_disk_id}}
                    break
            if json_response:
                resp.body = json_response
            else:
                error_handling.volume_fault(resp, 'Invalid volume id.',
                                            code=HTTP.BAD_REQUEST)
        except Exception as e:
            error_handling.volume_fault(resp, e.faultString)
Exemple #31
0
    def on_post(self, req, resp, tenant_id):
        payload = {}
        client = req.sl_client
        body = json.loads(req.stream.read().decode())

        payload['hostname'] = body['server']['name']
        payload['domain'] = config.CONF['default_domain'] or 'jumpgate.com'
        payload['image_id'] = body['server']['imageRef']

        # TODO(kmcdonald) - How do we set this accurately?
        payload['hourly'] = True

        networks = utils.lookup(body, 'server', 'networks')
        vs = SoftLayer.VSManager(client)

        try:
            self._handle_flavor(payload, body)
            self._handle_sshkeys(payload, body, client)

            # NOTE(mriedem): This is a hack but we need to stash the user_id
            # in the metadata on the virtual guest since the user's account
            # might not let them lookup billing information later during GET.
            self._stash_user_id_in_metadata(req, body)

            self._handle_user_data(payload, body)
            self._handle_datacenter(payload, body)
            if networks:
                self._handle_network(payload, client, networks)
            new_instance = vs.create_instance(**payload)
        except Exception as e:
            return error_handling.bad_request(resp, message=str(e))

        # This should be the first tag that the VS set. Adding any more tags
        # will replace this tag
        try:
            flavor_id = int(body['server'].get('flavorRef'))
            vs = client['Virtual_Guest']
            vs.setTags('{"flavor_id": ' + str(flavor_id) + '}',
                       id=new_instance['id'])
        except Exception:
            pass

        resp.set_header('x-compute-request-id', 'create')
        resp.status = 202
        resp.body = {
            'server': {
                # Casted to string to make tempest pass
                'id':
                str(new_instance['id']),
                'links': [{
                    'href':
                    self.app.get_endpoint_url('compute',
                                              req,
                                              'v2_server',
                                              instance_id=new_instance['id']),
                    'rel':
                    'self'
                }],
                'adminPass':
                '',
                # TODO(imkarrer) - Added security_groups to make tempest pass, need real groups  # noqa
                'security_groups': []
            }
        }
Exemple #32
0
    def on_post(self, req, resp, tenant_id, instance_id):
        body = json.loads(req.stream.read().decode())

        if len(body) == 0:
            return error_handling.bad_request(resp,
                                              message="Malformed request body")

        vg_client = req.env['sl_client']['Virtual_Guest']
        cci = SoftLayer.CCIManager(req.env['sl_client'])

        try:
            instance_id = int(instance_id)
        except Exception:
            return error_handling.not_found(resp,
                                            "Invalid instance ID specified.")

        instance = cci.get_instance(instance_id)

        if 'pause' in body or 'suspend' in body:
            try:
                vg_client.pause(id=instance_id)
            except SoftLayer.SoftLayerAPIError as e:
                if 'Unable to pause instance' in e.faultString:
                    return error_handling.duplicate(resp, e.faultString)
                raise
            resp.status = 202
            return
        elif 'unpause' in body or 'resume' in body:
            vg_client.resume(id=instance_id)
            resp.status = 202
            return
        elif 'reboot' in body:
            if body['reboot'].get('type') == 'SOFT':
                vg_client.rebootSoft(id=instance_id)
            elif body['reboot'].get('type') == 'HARD':
                vg_client.rebootHard(id=instance_id)
            else:
                vg_client.rebootDefault(id=instance_id)
            resp.status = 202
            return
        elif 'os-stop' in body:
            vg_client.powerOff(id=instance_id)
            resp.status = 202
            return
        elif 'os-start' in body:
            vg_client.powerOn(id=instance_id)
            resp.status = 202
            return
        elif 'createImage' in body:
            image_name = body['createImage']['name']
            disks = []

            for disk in filter(lambda x: x['device'] == '0',
                               instance['blockDevices']):
                disks.append(disk)

            try:
                vg_client.createArchiveTransaction(
                    image_name,
                    disks,
                    "Auto-created by OpenStack compatibility layer",
                    id=instance_id,
                )
                # Workaround for not having an image guid until the image is
                # fully created. TODO(nbeitenmiller): Fix this
                cci.wait_for_transaction(instance_id, 300)
                _filter = {
                    'privateBlockDeviceTemplateGroups': {
                        'name': {'operation': image_name},
                        'createDate': {
                            'operation': 'orderBy',
                            'options': [{'name': 'sort', 'value': ['DESC']}],
                        }
                    }}

                acct = req.env['sl_client']['Account']
                matching_image = acct.getPrivateBlockDeviceTemplateGroups(
                    mask='id, globalIdentifier', filter=_filter, limit=1)
                image_guid = matching_image.get('globalIdentifier')

                url = self.app.get_endpoint_url('image', req, 'v2_image',
                                                image_guid=image_guid)

                resp.status = 202
                resp.set_header('location', url)
            except SoftLayer.SoftLayerAPIError as e:
                error_handling.compute_fault(resp, e.faultString)
            return
        elif 'os-getConsoleOutput' in body:
            resp.status = 501
            return
        elif 'resize' in body:
            flavor_id = int(body['resize'].get('flavorRef'))
            if flavor_id not in flavors.FLAVORS:
                return error_handling.bad_request(
                    resp, message="Invalid flavor id in the request body")
            flavor = flavors.FLAVORS[flavor_id]
            cci.upgrade(instance_id, cpus=flavor['cpus'],
                        memory=flavor['ram'] / 1024)
            resp.status = 202
            return
        elif 'confirmResize' in body:
            resp.status = 204
            return

        return error_handling.bad_request(
            resp,
            message="There is no such action: %s" % list(body.keys()),
            code=400)
Exemple #33
0
    def on_post(self, req, resp, tenant_id):
        client = req.env['sl_client']
        body = json.loads(req.stream.read().decode())
        flavor_id = int(body['server'].get('flavorRef'))
        if flavor_id not in flavors.FLAVORS:
            return error_handling.bad_request(resp,
                                              'Flavor could not be found')

        flavor = flavors.FLAVORS[flavor_id]

        ssh_keys = []
        key_name = body['server'].get('key_name')
        if key_name:
            sshkey_mgr = SoftLayer.SshKeyManager(client)
            keys = sshkey_mgr.list_keys(label=key_name)
            if len(keys) == 0:
                return error_handling.bad_request(resp,
                                                  'KeyPair could not be found')
            ssh_keys.append(keys[0]['id'])

        private_network_only = False
        networks = utils.lookup(body, 'server', 'networks')
        if networks:
            # Make sure they're valid networks
            if not all([network['uuid'] in ['public', 'private']
                        in network for network in networks]):
                return error_handling.bad_request(resp,
                                                  message='Invalid network')

            # Find out if it's private only
            if not any([network['uuid'] == 'public'
                        in network for network in networks]):
                private_network_only = True

        user_data = {}
        if utils.lookup(body, 'server', 'metadata'):
            user_data['metadata'] = utils.lookup(body, 'server', 'metadata')
        if utils.lookup(body, 'server', 'user_data'):
            user_data['user_data'] = utils.lookup(body, 'server', 'user_data')
        if utils.lookup(body, 'server', 'personality'):
            user_data['personality'] = utils.lookup(body,
                                                    'server',
                                                    'personality')

        datacenter = (utils.lookup(body, 'server', 'availability_zone')
                      or config.CONF['compute']['default_availability_zone'])
        if not datacenter:
            return error_handling.bad_request(resp,
                                              'availability_zone missing')

        cci = SoftLayer.CCIManager(client)

        payload = {
            'hostname': body['server']['name'],
            'domain': config.CONF['default_domain'] or 'jumpgate.com',
            'cpus': flavor['cpus'],
            'memory': flavor['ram'],
            'local_disk': False if flavor['disk-type'] == 'SAN' else True,
            'hourly': True,  # TODO(kmcdonald) - How do we set this accurately?
            'datacenter': datacenter,
            'image_id': body['server']['imageRef'],
            'ssh_keys': ssh_keys,
            'private': private_network_only,
            'userdata': json.dumps(user_data),
        }

        try:
            new_instance = cci.create_instance(**payload)
        except ValueError as e:
            return error_handling.bad_request(resp, message=str(e))

        resp.set_header('x-compute-request-id', 'create')
        resp.status = 202
        resp.body = {'server': {
            'id': new_instance['id'],
            'links': [{
                'href': self.app.get_endpoint_url(
                    'compute', req, 'v2_server',
                    instance_id=new_instance['id']),
                'rel': 'self'}],
            'adminPass': '',
        }}
Exemple #34
0
    def on_post(self, req, resp, tenant_id, instance_id):
        body = json.loads(req.stream.read().decode())

        if len(body) == 0:
            return bad_request(resp, message="Malformed request body")

        vg_client = req.env["sl_client"]["Virtual_Guest"]
        cci = CCIManager(req.env["sl_client"])

        try:
            instance_id = int(instance_id)
        except ValueError:
            return not_found(resp, "Invalid instance ID specified.")

        instance = cci.get_instance(instance_id)

        if "pause" in body or "suspend" in body:
            try:
                vg_client.pause(id=instance_id)
            except SoftLayerAPIError as e:
                if "Unable to pause instance" in e.faultString:
                    return duplicate(resp, e.faultString)
                raise
            resp.status = 202
            return
        elif "unpause" in body or "resume" in body:
            vg_client.resume(id=instance_id)
            resp.status = 202
            return
        elif "reboot" in body:
            if body["reboot"].get("type") == "SOFT":
                vg_client.rebootSoft(id=instance_id)
            elif body["reboot"].get("type") == "HARD":
                vg_client.rebootHard(id=instance_id)
            else:
                vg_client.rebootDefault(id=instance_id)
            resp.status = 202
            return
        elif "os-stop" in body:
            vg_client.powerOff(id=instance_id)
            resp.status = 202
            return
        elif "os-start" in body:
            vg_client.powerOn(id=instance_id)
            resp.status = 202
            return
        elif "createImage" in body:
            image_name = body["createImage"]["name"]
            disks = []

            for disk in filter(lambda x: x["device"] == "0", instance["blockDevices"]):
                disks.append(disk)

            try:
                vg_client.createArchiveTransaction(
                    image_name, disks, "Auto-created by OpenStack compatibility layer", id=instance_id
                )
                # Workaround for not having an image guid until the image is
                # fully created. TODO: Fix this
                cci.wait_for_transaction(instance_id, 300)
                _filter = {
                    "privateBlockDeviceTemplateGroups": {
                        "name": {"operation": image_name},
                        "createDate": {"operation": "orderBy", "options": [{"name": "sort", "value": ["DESC"]}]},
                    }
                }

                acct = req.env["sl_client"]["Account"]
                matching_image = acct.getPrivateBlockDeviceTemplateGroups(
                    mask="id, globalIdentifier", filter=_filter, limit=1
                )
                image_guid = matching_image.get("globalIdentifier")

                url = self.app.get_endpoint_url("image", req, "v2_image", image_guid=image_guid)

                resp.status = 202
                resp.set_header("location", url)
            except SoftLayerAPIError as e:
                compute_fault(resp, e.faultString)
            return
        elif "os-getConsoleOutput" in body:
            resp.status = 501
            return

        return bad_request(resp, message="There is no such action: %s" % list(body.keys()), code=400)
Exemple #35
0
    def on_post(self, req, resp, tenant_id):
        client = req.env['sl_client']
        body = json.loads(req.stream.read().decode())
        flavor_id = int(body['server'].get('flavorRef'))
        if flavor_id not in FLAVORS:
            return bad_request(resp, 'Flavor could not be found')

        flavor = FLAVORS[flavor_id]

        ssh_keys = []
        key_name = body['server'].get('key_name')
        if key_name:
            sshkey_mgr = SshKeyManager(client)
            keys = sshkey_mgr.list_keys(label=key_name)
            if len(keys) == 0:
                return bad_request(resp, 'KeyPair could not be found')
            ssh_keys.append(keys[0]['id'])

        private_network_only = False
        networks = lookup(body, 'server', 'networks')
        if networks:
            # Make sure they're valid networks
            if not all([
                    network['uuid'] in ['public', 'private'] in network
                    for network in networks
            ]):
                return bad_request(resp, message='Invalid network')

            # Find out if it's private only
            if not any([
                    network['uuid'] == 'public' in network
                    for network in networks
            ]):
                private_network_only = True

        user_data = {}
        if lookup(body, 'server', 'metadata'):
            user_data['metadata'] = lookup(body, 'server', 'metadata')
        if lookup(body, 'server', 'user_data'):
            user_data['user_data'] = lookup(body, 'server', 'user_data')
        if lookup(body, 'server', 'personality'):
            user_data['personality'] = lookup(body, 'server', 'personality')

        datacenter = None
        if lookup(body, 'server', 'availability_zone'):
            datacenter = lookup(body, 'server', 'availability_zone')

        cci = CCIManager(client)

        payload = {
            'hostname': body['server']['name'],
            'domain': 'jumpgate.com',  # TODO - Don't hardcode this
            'cpus': flavor['cpus'],
            'memory': flavor['ram'],
            'hourly': True,  # TODO - How do we set this accurately?
            'datacenter': datacenter,
            'image_id': body['server']['imageRef'],
            'ssh_keys': ssh_keys,
            'private': private_network_only,
            'userdata': json.dumps(user_data),
        }

        try:
            new_instance = cci.create_instance(**payload)
        except ValueError as e:
            return bad_request(resp, message=str(e))

        resp.set_header('x-compute-request-id', 'create')
        resp.status = 202
        resp.body = {
            'server': {
                'id':
                new_instance['id'],
                'links': [{
                    'href':
                    self.app.get_endpoint_url('compute',
                                              req,
                                              'v2_server',
                                              instance_id=new_instance['id']),
                    'rel':
                    'self'
                }],
                'adminPass':
                '',
            }
        }
Exemple #36
0
    def on_post(self, req, resp, tenant_id):
        """Create volume (SL Portable storage)

        :param req: Falcon request object
        :param resp: Falcon request object
        :param tenant_id: Softlayer tenant_id
        :param return: Falcon response object with openstack response body
        """
        client = req.env['sl_client']
        try:
            v_type_zone = None
            rounding = False
            body = json.loads(req.stream.read().decode())
            if body['volume']['volume_type'] is not None:
                if not self.volume_types['volume_types']:
                    resp.status = HTTP.INTERNAL_SERVER_ERROR
                    return error_handling.volume_fault(resp,
                                                       "Server has no"
                                                       " types to select")
                foundType = False
                for type in self.volume_types['volume_types']:
                    if type['name'] == body['volume']['volume_type']:
                        foundType = True
                        v_type_zone = (
                            type['extra_specs']['capabilities:volume_backend_name']  # noqa
                            )
                        rounding = (
                            type['extra_specs']['drivers:exact_capacity']
                            )
                if not foundType:
                    resp.status = 400
                    raise Exception('Specify a volume with a valid name')

            # required field in the create volume payload
            namestr = body['volume'].get("display_name")
            volreq = body['volume']
            # portable storage order cannot have empty name
            name = (config.CONF['volume']['volume_name_prefix'] +
                    (namestr if namestr else ""))

            # size is required option for volume create. Throw type exception
            # if it is invalid
            size = int(volreq['size'])
            # availability_zone is optional, don't throw exception if
            # it is not available
            availability_zone = (body['volume'].get('availability_zone')
                                 or
                                 v_type_zone
                                 or
                                 config.CONF['volume']['default_availability_zone'])  # noqa
            volume_type = body['volume'].get('volume_type')

        except Exception as e:
            return error_handling.bad_request(resp, str(e))

        try:
            volinfo = self._create_volume(tenant_id, client, resp,
                                          size, name=name,
                                          zone=availability_zone,
                                          volume_type=volume_type,
                                          exact_capacity=rounding)

            resp.status = HTTP.ACCEPTED

            if volinfo:
                resp.body = {'volume':
                             format_volume(tenant_id, volinfo, client)}
                resp.body['volume'].update({'status': 'creating'})
            else:
                # Cannot generate a valid response without knowning
                # the volume id when order takes too long to complete.
                # This should be a rare case, but it could break openstack
                # since the volume create caller always expect a volume id
                # uppon successful return. The approach here is to fail
                # the volume create operation and leak one portable storage
                # volume. User can always cancel from SL portal.

                return error_handling.volume_fault(resp,
                                                   "Portable storage"
                                                   " order delayed")

        except SoftLayer.SoftLayerAPIError as e:
            return error_handling.error(resp,
                                        "SoftLayerAPIError",
                                        e.faultString,
                                        code=e.faultCode)
        except Exception as e:
            return error_handling.volume_fault(resp, str(e))
Exemple #37
0
    def on_post(self, req, resp, tenant_id, instance_id):
        '''Attaches a specified volume to a specified server.'''
        body = json.loads(req.stream.read().decode())

        if (len(body) == 0 or 'volumeAttachment' not in body
                or 'volumeId' not in body['volumeAttachment']):
            return error_handling.bad_request(resp,
                                              message="Malformed "
                                              "request body")

        vg_client = req.env['sl_client']['Virtual_Guest']

        try:
            instance_id = int(instance_id)
        except Exception:
            return error_handling.not_found(resp,
                                            "Invalid instance ID specified.")

        volume_id = body['volumeAttachment']['volumeId']
        if volume_id and len(volume_id) > OPENSTACK_VOLUME_UUID_LEN:
            return error_handling.bad_request(resp,
                                              message="Malformed "
                                              "request body")

        vdi_client = req.env['sl_client']['Virtual_Disk_Image']
        volinfo = None

        # first let's check if the volume is already attached
        try:
            volinfo = vdi_client.getObject(id=volume_id, mask='blockDevices')
            blkDevices = volinfo['blockDevices']
            if (len(blkDevices) > 0):
                guestId_list = [
                    blkDevice['guestId'] for blkDevice in blkDevices
                ]
                for guest_id in guestId_list:
                    if (guest_id == instance_id):
                        return error_handling.volume_fault(
                            resp,
                            'The requested disk image is already attached to '
                            'this guest.',
                            code=HTTP.BAD_REQUEST)
                    else:
                        return error_handling.volume_fault(
                            resp,
                            'The requested disk image is already attached to '
                            'another guest.',
                            code=HTTP.BAD_REQUEST)
        except Exception as e:
            return error_handling.volume_fault(resp,
                                               e.faultString,
                                               code=HTTP.NOT_FOUND)

        try:
            # providing different size doesn't seem to have any impact on the
            # outcome hence using 10 as default size.
            disk_check = vg_client.checkHostDiskAvailability(10,
                                                             id=instance_id)
        except Exception:
            disk_check = True

        try:
            if disk_check:
                sl_transaction = vg_client.attachDiskImage(volume_id,
                                                           id=instance_id)
                resp.body = {
                    "volumeAttachment": {
                        "device": "",
                        "id": sl_transaction['id'],
                        "serverId": instance_id,
                        "volumeId": volume_id
                    }
                }
                resp.status = HTTP.ACCEPTED
            else:
                return error_handling.volume_fault(
                    resp,
                    'Action causes migration to a new host. Migration is not '
                    'allowed.',
                    code=HTTP.BAD_REQUEST)
        except Exception as e:
            error_handling.volume_fault(resp, e.faultString)
Exemple #38
0
    def on_post(self, req, resp, tenant_id, instance_id):
        body = json.loads(req.stream.read().decode())

        if len(body) == 0:
            return bad_request(resp, message="Malformed request body")

        vg_client = req.env['sl_client']['Virtual_Guest']
        cci = CCIManager(req.env['sl_client'])

        try:
            instance_id = int(instance_id)
        except ValueError:
            return not_found(resp, "Invalid instance ID specified.")

        instance = cci.get_instance(instance_id)

        if 'pause' in body or 'suspend' in body:
            try:
                vg_client.pause(id=instance_id)
            except SoftLayerAPIError as e:
                if 'Unable to pause instance' in e.faultString:
                    return duplicate(resp, e.faultString)
                raise
            resp.status = 202
            return
        elif 'unpause' in body or 'resume' in body:
            vg_client.resume(id=instance_id)
            resp.status = 202
            return
        elif 'reboot' in body:
            if body['reboot'].get('type') == 'SOFT':
                vg_client.rebootSoft(id=instance_id)
            elif body['reboot'].get('type') == 'HARD':
                vg_client.rebootHard(id=instance_id)
            else:
                vg_client.rebootDefault(id=instance_id)
            resp.status = 202
            return
        elif 'os-stop' in body:
            vg_client.powerOff(id=instance_id)
            resp.status = 202
            return
        elif 'os-start' in body:
            vg_client.powerOn(id=instance_id)
            resp.status = 202
            return
        elif 'createImage' in body:
            image_name = body['createImage']['name']
            disks = []

            for disk in filter(lambda x: x['device'] == '0',
                               instance['blockDevices']):
                disks.append(disk)

            try:
                vg_client.createArchiveTransaction(
                    image_name,
                    disks,
                    "Auto-created by OpenStack compatibility layer",
                    id=instance_id,
                )
                # Workaround for not having an image guid until the image is
                # fully created. TODO: Fix this
                cci.wait_for_transaction(instance_id, 300)
                _filter = {
                    'privateBlockDeviceTemplateGroups': {
                        'name': {
                            'operation': image_name
                        },
                        'createDate': {
                            'operation': 'orderBy',
                            'options': [{
                                'name': 'sort',
                                'value': ['DESC']
                            }],
                        }
                    }
                }

                acct = req.env['sl_client']['Account']
                matching_image = acct.getPrivateBlockDeviceTemplateGroups(
                    mask='id, globalIdentifier', filter=_filter, limit=1)
                image_guid = matching_image.get('globalIdentifier')

                url = self.app.get_endpoint_url('image',
                                                req,
                                                'v2_image',
                                                image_guid=image_guid)

                resp.status = 202
                resp.set_header('location', url)
            except SoftLayerAPIError as e:
                compute_fault(resp, e.faultString)
            return
        elif 'os-getConsoleOutput' in body:
            resp.status = 501
            return

        return bad_request(resp,
                           message="There is no such action: %s" %
                           list(body.keys()),
                           code=400)
Exemple #39
0
    def on_post(self, req, resp, tenant_id, instance_id):
        '''Attaches a specified volume to a specified server.'''
        body = json.loads(req.stream.read().decode())

        if any([len(body) == 0,
                'volumeAttachment' not in body,
                'volumeId' not in body['volumeAttachment']]):
            return error_handling.bad_request(resp,
                                              message="Malformed request body")

        vg_client = req.env['sl_client']['Virtual_Guest']

        try:
            instance_id = int(instance_id)
        except Exception:
            return error_handling.not_found(resp,
                                            "Invalid instance ID specified.")

        volume_id = body['volumeAttachment']['volumeId']
        if volume_id and len(volume_id) > OPENSTACK_VOLUME_UUID_LEN:
            return error_handling.bad_request(resp,
                                              message="Malformed request body")

        vdi_client = req.env['sl_client']['Virtual_Disk_Image']
        volinfo = None

        # first let's check if the volume is already attached
        try:
            volinfo = vdi_client.getObject(id=volume_id,
                                           mask='blockDevices')
            blkDevices = volinfo['blockDevices']
            if (len(blkDevices) > 0):
                guestId_list = [blkDevice['guestId'] for blkDevice
                                in blkDevices]
                for guest_id in guestId_list:
                    if (guest_id == instance_id):
                        return error_handling.volume_fault(
                            resp,
                            'The requested disk image is already attached to '
                            'this guest.',
                            code=HTTP.BAD_REQUEST)
                    else:
                        return error_handling.volume_fault(
                            resp,
                            'The requested disk image is already attached to '
                            'another guest.',
                            code=HTTP.BAD_REQUEST)
        except Exception as e:
            return error_handling.volume_fault(resp,
                                               e.faultString,
                                               code=HTTP.NOT_FOUND)

        try:
            # providing different size doesn't seem to have any impact on the
            # outcome hence using 10 as default size.
            disk_check = vg_client.checkHostDiskAvailability(10,
                                                             id=instance_id)
        except Exception:
            disk_check = True

        try:
            if disk_check:
                sl_transaction = vg_client.attachDiskImage(volume_id,
                                                           id=instance_id)
                resp.body = {"volumeAttachment":
                             {"device": "",
                              "id": sl_transaction['id'],
                              "serverId": instance_id,
                              "volumeId": volume_id}}
                resp.status = HTTP.ACCEPTED
            else:
                return error_handling.volume_fault(
                    resp,
                    'Action causes migration to a new host. Migration is not '
                    'allowed.',
                    code=HTTP.BAD_REQUEST)
        except Exception as e:
            error_handling.volume_fault(resp, e.faultString)
Exemple #40
0
    def on_post(self, req, resp, tenant_id):
        client = req.env["sl_client"]
        body = json.loads(req.stream.read().decode())
        flavor_id = int(body["server"].get("flavorRef"))
        if flavor_id not in FLAVORS:
            return bad_request(resp, "Flavor could not be found")

        flavor = FLAVORS[flavor_id]

        ssh_keys = []
        key_name = body["server"].get("key_name")
        if key_name:
            sshkey_mgr = SshKeyManager(client)
            keys = sshkey_mgr.list_keys(label=key_name)
            if len(keys) == 0:
                return bad_request(resp, "KeyPair could not be found")
            ssh_keys.append(keys[0]["id"])

        private_network_only = False
        networks = lookup(body, "server", "networks")
        if networks:
            # Make sure they're valid networks
            if not all([network["uuid"] in ["public", "private"] in network for network in networks]):
                return bad_request(resp, message="Invalid network")

            # Find out if it's private only
            if not any([network["uuid"] == "public" in network for network in networks]):
                private_network_only = True

        user_data = {}
        if lookup(body, "server", "metadata"):
            user_data["metadata"] = lookup(body, "server", "metadata")
        if lookup(body, "server", "user_data"):
            user_data["user_data"] = lookup(body, "server", "user_data")
        if lookup(body, "server", "personality"):
            user_data["personality"] = lookup(body, "server", "personality")

        datacenter = None
        if lookup(body, "server", "availability_zone"):
            datacenter = lookup(body, "server", "availability_zone")

        cci = CCIManager(client)

        payload = {
            "hostname": body["server"]["name"],
            "domain": CONF["default_domain"] or "jumpgate.com",
            "cpus": flavor["cpus"],
            "memory": flavor["ram"],
            "local_disk": False if flavor["disk-type"] == "SAN" else True,
            "hourly": True,  # TODO - How do we set this accurately?
            "datacenter": datacenter,
            "image_id": body["server"]["imageRef"],
            "ssh_keys": ssh_keys,
            "private": private_network_only,
            "userdata": json.dumps(user_data),
        }

        try:
            new_instance = cci.create_instance(**payload)
        except ValueError as e:
            return bad_request(resp, message=str(e))

        resp.set_header("x-compute-request-id", "create")
        resp.status = 202
        resp.body = {
            "server": {
                "id": new_instance["id"],
                "links": [
                    {
                        "href": self.app.get_endpoint_url("compute", req, "v2_server", instance_id=new_instance["id"]),
                        "rel": "self",
                    }
                ],
                "adminPass": "",
            }
        }