lxd/storage_volumes.go
func storagePoolVolumesGet(d *Daemon, r *http.Request) Response {
	project := projectParam(r)
	poolName := mux.Vars(r)["name"]

	recursion := util.IsRecursionRequest(r)

	// Retrieve ID of the storage pool (and check if the storage pool
	// exists).
	poolID, err := d.cluster.StoragePoolGetID(poolName)
	if err != nil {
		return SmartError(err)
	}

	// Get all volumes currently attached to the storage pool by ID of the
	// pool and project.
	//
	// We exclude volumes of type image, since those are special: they are
	// stored using the storage_volumes table, but are effectively a cache
	// which is not tied to projects, so we always link the to the default
	// project. This means that we want to filter image volumes and return
	// only the ones that have fingerprints matching images actually in use
	// by the project.
	volumes, err := d.cluster.StoragePoolVolumesGet(project, poolID, supportedVolumeTypesExceptImages)
	if err != nil && err != db.ErrNoSuchObject {
		return SmartError(err)
	}

	imageVolumes, err := d.cluster.StoragePoolVolumesGet("default", poolID, []int{storagePoolVolumeTypeImage})
	if err != nil && err != db.ErrNoSuchObject {
		return SmartError(err)
	}

	projectImages, err := d.cluster.ImagesGet(project, false)
	if err != nil {
		return SmartError(err)
	}
	for _, volume := range imageVolumes {
		if shared.StringInSlice(volume.Name, projectImages) {
			volumes = append(volumes, volume)
		}
	}

	resultString := []string{}
	for _, volume := range volumes {
		apiEndpoint, err := storagePoolVolumeTypeNameToAPIEndpoint(volume.Type)
		if err != nil {
			return InternalError(err)
		}

		if apiEndpoint == storagePoolVolumeAPIEndpointContainers {
			apiEndpoint = "container"
		} else if apiEndpoint == storagePoolVolumeAPIEndpointImages {
			apiEndpoint = "image"
		}

		if !recursion {
			volName, snapName, ok := containerGetParentAndSnapshotName(volume.Name)
			if ok {
				resultString = append(resultString,
					fmt.Sprintf("/%s/storage-pools/%s/volumes/%s/%s/snapshots/%s",
						version.APIVersion, poolName, apiEndpoint, volName, snapName))
			} else {
				resultString = append(resultString,
					fmt.Sprintf("/%s/storage-pools/%s/volumes/%s/%s",
						version.APIVersion, poolName, apiEndpoint, volume.Name))
			}
		} else {
			volumeUsedBy, err := storagePoolVolumeUsedByGet(d.State(), project, volume.Name, volume.Type)
			if err != nil {
				return InternalError(err)
			}
			volume.UsedBy = volumeUsedBy
		}
	}

	if !recursion {
		return SyncResponse(true, resultString)
	}

	return SyncResponse(true, volumes)
}
func storagePoolVolumesGet(d *Daemon, r *http.Request) Response {
	project := projectParam(r)
	poolName := mux.Vars(r)["name"]

	recursion := util.IsRecursionRequest(r)

	// Retrieve ID of the storage pool (and check if the storage pool
	// exists).
	poolID, err := d.cluster.StoragePoolGetID(poolName)
	if err != nil {
		return SmartError(err)
	}

	// Get all volumes currently attached to the storage pool by ID of the
	// pool and project.
	//
	// We exclude volumes of type image, since those are special: they are
	// stored using the storage_volumes table, but are effectively a cache
	// which is not tied to projects, so we always link the to the default
	// project. This means that we want to filter image volumes and return
	// only the ones that have fingerprints matching images actually in use
	// by the project.
	volumes, err := d.cluster.StoragePoolVolumesGet(project, poolID, supportedVolumeTypesExceptImages)
	if err != nil && err != db.ErrNoSuchObject {
		return SmartError(err)
	}

	imageVolumes, err := d.cluster.StoragePoolVolumesGet("default", poolID, []int{storagePoolVolumeTypeImage})
	if err != nil && err != db.ErrNoSuchObject {
		return SmartError(err)
	}

	projectImages, err := d.cluster.ImagesGet(project, false)
	if err != nil {
		return SmartError(err)
	}
	for _, volume := range imageVolumes {
		if shared.StringInSlice(volume.Name, projectImages) {
			volumes = append(volumes, volume)
		}
	}

	resultString := []string{}
	for _, volume := range volumes {
		apiEndpoint, err := storagePoolVolumeTypeNameToAPIEndpoint(volume.Type)
		if err != nil {
			return InternalError(err)
		}

		if apiEndpoint == storagePoolVolumeAPIEndpointContainers {
			apiEndpoint = "container"
		} else if apiEndpoint == storagePoolVolumeAPIEndpointImages {
			apiEndpoint = "image"
		}

		if !recursion {
			volName, snapName, ok := containerGetParentAndSnapshotName(volume.Name)
			if ok {
				resultString = append(resultString,
					fmt.Sprintf("/%s/storage-pools/%s/volumes/%s/%s/snapshots/%s",
						version.APIVersion, poolName, apiEndpoint, volName, snapName))
			} else {
				resultString = append(resultString,
					fmt.Sprintf("/%s/storage-pools/%s/volumes/%s/%s",
						version.APIVersion, poolName, apiEndpoint, volume.Name))
			}
		} else {
			volumeUsedBy, err := storagePoolVolumeUsedByGet(d.State(), project, volume.Name, volume.Type)
			if err != nil {
				return InternalError(err)
			}
			volume.UsedBy = volumeUsedBy
		}
	}

	if !recursion {
		return SyncResponse(true, resultString)
	}

	return SyncResponse(true, volumes)
}
func storagePoolVolumesGet ( d * Daemon , r * http . Request ) Response { project := projectParam ( r ) poolName := mux . Vars ( r ) [ " " ] recursion := util . IsRecursionRequest ( r ) // Retrieve ID of the storage pool (and check if the storage pool // exists). poolID , err := d . cluster . StoragePoolGetID ( poolName ) if err != nil { return SmartError ( err ) } // Get all volumes currently attached to the storage pool by ID of the // pool and project. // // We exclude volumes of type image, since those are special: they are // stored using the storage_volumes table, but are effectively a cache // which is not tied to projects, so we always link the to the default // project. This means that we want to filter image volumes and return // only the ones that have fingerprints matching images actually in use // by the project. volumes , err := d . cluster . StoragePoolVolumesGet ( project , poolID , supportedVolumeTypesExceptImages ) if err != nil && err != db . ErrNoSuchObject { return SmartError ( err ) } imageVolumes , err := d . cluster . StoragePoolVolumesGet ( " " , poolID , [ ] int { storagePoolVolumeTypeImage } ) if err != nil && err != db . ErrNoSuchObject { return SmartError ( err ) } projectImages , err := d . cluster . ImagesGet ( project , false ) if err != nil { return SmartError ( err ) } for _ , volume := range imageVolumes { if shared . StringInSlice ( volume . Name , projectImages ) { volumes = append ( volumes , volume ) } } resultString := [ ] string { } for _ , volume := range volumes { apiEndpoint , err := storagePoolVolumeTypeNameToAPIEndpoint ( volume . Type ) if err != nil { return InternalError ( err ) } if apiEndpoint == storagePoolVolumeAPIEndpointContainers { apiEndpoint = " " } else if apiEndpoint == storagePoolVolumeAPIEndpointImages { apiEndpoint = " " } if ! recursion { volName , snapName , ok := containerGetParentAndSnapshotName ( volume . Name ) if ok { resultString = append ( resultString , fmt . Sprintf ( " " , version . APIVersion , poolName , apiEndpoint , volName , snapName ) ) } else { resultString = append ( resultString , fmt . Sprintf ( " " , version . APIVersion , poolName , apiEndpoint , volume . Name ) ) } } else { volumeUsedBy , err := storagePoolVolumeUsedByGet ( d . State ( ) , project , volume . Name , volume . Type ) if err != nil { return InternalError ( err ) } volume . UsedBy = volumeUsedBy } } if ! recursion { return SyncResponse ( true , resultString ) } return SyncResponse ( true , volumes ) }
// /1.0/storage-pools/{name}/volumes
// List all storage volumes attached to a given storage pool.
/ 1 . 0 / storage - pools / { name } / volumes List all storage volumes attached to a given storage pool .