As it currently stands, images are created implicitly when a volume is created using a new imageUUID. Although this is practical for the current use cases, it doesn't present a semetrical API. Other vdsm objects have create/delete methods.i
Furthermore, it preents challenges when trying to model VDSM in a REST API. Let's say I want to create a new disk for a VM. I would want to issue the following sequence of commands:
POST -> /vdsm-api/storagedomains/<sdUUID>/images/create <- HTTP/202 Accepted: /vdsm-api/tasks/<task-uuid> GET -> /vdsm-api/tasks/<task-uuid> <- HTTP/200 OK: /vdsm-api/storagedomains/<sdUUID>/images/<imgUUID> POST -> /vdsm-api/storagedomains/<sdUUID>/images/<imgUUID>/volumes/create <- HTTP/202 Accepted: /vdsm-api/tasks/<task-uuid> GET -> /vdsm-api/tasks/<task-uuid> <- HTTP/200 OK: /vdsm-api/storagedomains/<sdUUID>/images/<imgUUID>/volumes/<volUUID>
The only way to support this pattern is to allow for the explicit creation of an image with an empty volume chain.
Signed-off-by: Adam Litke agl@us.ibm.com
diff --git a/vdsm/storage/spm.py b/vdsm/storage/spm.py index 849b9d2..1222752 100644 --- a/vdsm/storage/spm.py +++ b/vdsm/storage/spm.py @@ -820,6 +820,23 @@ class SPM: repoPath = os.path.join(self.storage_repository, spUUID) image.Image(repoPath).multiMove(srcDomUUID, dstDomUUID, imgDict, vmUUID, force)
+ def createImage(self, sdUUID, spUUID, imgUUID): + """ + Create a new, empty image + + :param sdUUID: The UUID of the storage domain that contains the images. + :type sdUUID: UUID + :param spUUID: The UUID of the storage pool that contains the images. + :type spUUID: UUID + :param imgUUID: The UUID of the image you want to delete. + :type imgUUID: UUID + + """ + hsm.HSM.getPool(spUUID) #Validates that the pool is connected. WHY? + hsm.HSM.validateSdUUID(sdUUID) + repoPath = os.path.join(self.storage_repository, spUUID) + image.Image(repoPath).create(sdUUID, imgUUID) + return dict(uuid=imgUUID)
def deleteImage(self, sdUUID, spUUID, imgUUID, postZero, force): """ @@ -1470,6 +1487,18 @@ class SPM: imgUUID, volumes, misc.parseBool(postZero), misc.parseBool(force) )
+ def public_createImage(self, sdUUID, spUUID, imgUUID): + """ + Create a new, empty image + """ + argsStr = "sdUUID=%s, spUUID=%s, imgUUID=%s" % \ + (str(sdUUID), str(spUUID), str(imgUUID)) + vars.task.setDefaultException(se.ImagePathError(argsStr)) + hsm.HSM.getPool(spUUID) #Validates that the pool is connected. WHY? + hsm.HSM.validateSdUUID(sdUUID) + misc.validateUUID(imgUUID, 'imgUUID') + vars.task.getSharedLock(STORAGE, sdUUID) + self._schedule("createImage", self.createImage, sdUUID, spUUID, imgUUID)
def public_deleteImage(self, sdUUID, spUUID, imgUUID, postZero=False, force=False): """