Skip to content

CreateMachineDisk doesn't work #156

Description

@Smithx10

Client add disk:

❯ which tt
tt: aliased to triton

❯ tt inst get test-disks | jq .disk
102400
❯ tt inst get test-disks | jq .disks
[
  {
    "size": 10240,
    "block_size": 8192,
    "boot": true,
    "image": "ede15ae3-a2ed-4636-a4d5-c130cbd9c297",
    "id": "33ee02e6-9239-4acb-913f-3bf6f88e3c42"
  },
  {
    "size": 10240,
    "block_size": 4096,
    "id": "12f0e114-abfc-4972-95dd-b7071e95b72a"
  }
]
❯ tt inst get test-disks | jq .state
"stopped"
❯ tt inst disk add test-disks 20480
triton instance disk add: error (InternalError): Internal Error

CloudAPI error:

[2026-08-22T02:22:35.598Z] ERROR: cloudapi/456881 on e49bd1aa-2c21-4850-86dc-61d8d9c9f192: unexpected error (req_id=6951be18-eae1-4e32-be59-f5d9988ce998)
    InvalidArgumentError: Cannot set block_size and image_uuid.

[root@e49bd1aa-2c21-4850-86dc-61d8d9c9f192 (us-southeast-1:cloudapi0) /opt/smartdc/cloudapi]# cat package.json | json version
9.20.0

createDisk iterates over every disk of the instance when adding a new disk and hits the error condition where a disk being added cannot have a block_size specified when it has an image. Looks like this check already exists in lib/machines.js, not sure we need it in lib/endpoints/disks.js

https://github.com/TritonDataCenter/sdc-cloudapi/blob/master/lib/endpoints/disks.js#L93

function createDisk(req, res, next) {
    assert.ok(req.sdc);

    var log = req.log;
    var headers = { 'x-request-id': req.getId() };
    var context = { caller: req._auditCtx };
    var origin = req.params.origin || 'cloudapi';
    var vmUuid = req.vm.uuid;
    var ownerUuid = req.account.uuid;
    var size = req.params.size;
    var pciSlot = req.params.pci_slot;

    req.vm.disks = req.vm.disks || [];

    if (req.vm.brand !== 'bhyve') {
        next(InvalidArgumentError('Disk Creation is supported only for ' +
            'BHYVE VMs'));
        return;
    }

    if (req.vm.state !== 'stopped') {
        next(new InvalidArgumentError('VM must be stopped'));
        return;
    }

    if (!size) {
        next(new MissingParameterError('size must be specified'));
        return;
    }

    if (size !== 'remaining' && isNaN(+size)) {
        next(new InvalidArgumentError('size must be a number'));
        return;
    }

    if (pciSlot !== undefined && !PCI_SLOT_RE.test(pciSlot)) {
        next(new InvalidArgumentError('pci_slot has wrong format'));
        return;
    }

    if (req.vm.disks.length >= MAX_ALLOWED_VM_DISKS) {
        next(new InvalidArgumentError('A maximum of ' + MAX_ALLOWED_VM_DISKS +
            ' disks per VM are supported'));
        return;
    }

    // Check requested block size, if any.
    req.vm.disks.forEach(function vrs(disk, i) {
        if (disk.hasOwnProperty('block_size')) {
            if (disk.hasOwnProperty('image_uuid')) {
                throw new InvalidArgumentError(
                    'Cannot set block_size and image_uuid.'
                );
            }
            if (!diskValidation.validRecordSize(disk.block_size)) {
                throw new InvalidArgumentError(
                    'Invalid block_size: ' + disk.block_size +
                    ' on disk: ' + i + '. Must be 512-131072 and ' +
                    'a power of 2.'
                );
            }
        }
    });

    if (pciSlot) {
        var diskId = getDiskUuid(vmUuid, pciSlot);
    }

    if (size === 'remaining') {
        if (!req.vm.flexible_disk_size) {
            next(new InvalidArgumentError('remaining is only supported for ' +
                'VMs created with flexible_disk_size packages'));
            return;
        }

        var disksSum = req.vm.disks.reduce(function sumDisk(sum, disk) {
            return (sum + Number(disk.size) || 0);
        }, 0);
        size = req.vm.flexible_disk_size - disksSum;
    }

    req.sdc.vmapi.createDisk({
        uuid: vmUuid,
        owner_uuid: ownerUuid,
        disk_uuid: diskId,
        pci_slot: pciSlot,
        size: size,
        origin: origin,
        context: context
    }, {
        log: log,
        headers: headers
    }, function createDiskCb(err, job) {
        if (err) {
            next(err);
            return;
        }

        var login = req.account.login;
        log.debug({
            request: format('POST /%s/machines/%s/disks -> ok', login, vmUuid),
            job: job
        });

        if (!pciSlot) {
            res.send(202);
            next();
            return;
        }

        var location = '/' + login + '/machines/' + vmUuid + '/disks/' + diskId;
        res.header('Location', location);

        var disk = {
            uuid: diskId,
            pci_slot: pciSlot,
            size: size,
            boot: false,
            state: 'creating'
        };

        res.send(translate(disk));

        next();
    });
}

https://github.com/TritonDataCenter/sdc-cloudapi/blob/master/lib/machines.js#L565

                // Check requested block size, if any.
                disks.forEach(function vrs(disk, i) {
                    if (disk.hasOwnProperty('block_size')) {
                        if (disk.hasOwnProperty('image_uuid')) {
                            throw new InvalidArgumentError(
                                'Cannot set block_size and image_uuid.'
                            );
                        }
                        if (!diskValidation.validRecordSize(disk.block_size)) {
                            throw new InvalidArgumentError(
                                'Invalid block_size: ' + disk.block_size +
                                ' on disk: ' + i + '. Must be 512-131072 and ' +
                                'a power of 2.'
                            );
                        }
                    }
                });

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions