func storagePoolVolumeTypePut(d *Daemon, r *http.Request, volumeTypeName string) Response {
	// Get the name of the storage volume.
	var volumeName string
	fields := strings.Split(mux.Vars(r)["name"], "/")

	if len(fields) == 3 && fields[1] == "snapshots" {
		// Handle volume snapshots
		volumeName = fmt.Sprintf("%s%s%s", fields[0], shared.SnapshotDelimiter, fields[2])
	} else if len(fields) > 1 {
		volumeName = fmt.Sprintf("%s%s%s", fields[0], shared.SnapshotDelimiter, fields[1])
	} else if len(fields) > 0 {
		// Handle volume
		volumeName = fields[0]
	} else {
		return BadRequest(fmt.Errorf("invalid storage volume %s", mux.Vars(r)["name"]))
	}

	// Get the name of the storage pool the volume is supposed to be
	// attached to.
	poolName := mux.Vars(r)["pool"]

	// Convert the volume type name to our internal integer representation.
	volumeType, err := storagePoolVolumeTypeNameToType(volumeTypeName)
	if err != nil {
		return BadRequest(err)
	}
	// Check that the storage volume type is valid.
	if !shared.IntInSlice(volumeType, supportedVolumeTypes) {
		return BadRequest(fmt.Errorf("invalid storage volume type %s", volumeTypeName))
	}

	poolID, pool, err := d.cluster.StoragePoolGet(poolName)
	if err != nil {
		return SmartError(err)
	}

	response := ForwardedResponseIfTargetIsRemote(d, r)
	if response != nil {
		return response
	}

	response = ForwardedResponseIfVolumeIsRemote(d, r, poolID, volumeName, volumeType)
	if response != nil {
		return response
	}

	// Get the existing storage volume.
	_, volume, err := d.cluster.StoragePoolNodeVolumeGetType(volumeName, volumeType, poolID)
	if err != nil {
		return SmartError(err)
	}

	// Validate the ETag
	etag := []interface{}{volumeName, volume.Type, volume.Config}

	err = util.EtagCheck(r, etag)
	if err != nil {
		return PreconditionFailed(err)
	}

	req := api.StorageVolumePut{}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		return BadRequest(err)
	}

	if req.Restore != "" {
		ctsUsingVolume, err := storagePoolVolumeUsedByRunningContainersWithProfilesGet(d.State(), poolName, volume.Name, storagePoolVolumeTypeNameCustom, true)
		if err != nil {
			return InternalError(err)
		}

		if len(ctsUsingVolume) != 0 {
			return BadRequest(fmt.Errorf("Cannot restore custom volume used by running containers"))
		}

		err = storagePoolVolumeRestore(d.State(), poolName, volumeName, volumeType, req.Restore)
		if err != nil {
			return SmartError(err)
		}
	} else {
		// Validate the configuration
		err = storageVolumeValidateConfig(volumeName, req.Config, pool)
		if err != nil {
			return BadRequest(err)
		}

		err = storagePoolVolumeUpdate(d.State(), poolName, volumeName, volumeType, req.Description, req.Config)
		if err != nil {
			return SmartError(err)
		}
	}

	return EmptySyncResponse
}
func storagePoolVolumeTypePut(d *Daemon, r *http.Request, volumeTypeName string) Response {
	
	var volumeName string
	fields := strings.Split(mux.Vars(r)["name"], "/")

	if len(fields) == 3 && fields[1] == "snapshots" {
		
		volumeName = fmt.Sprintf("%s%s%s", fields[0], shared.SnapshotDelimiter, fields[2])
	} else if len(fields) > 1 {
		volumeName = fmt.Sprintf("%s%s%s", fields[0], shared.SnapshotDelimiter, fields[1])
	} else if len(fields) > 0 {
		
		volumeName = fields[0]
	} else {
		return BadRequest(fmt.Errorf("invalid storage volume %s", mux.Vars(r)["name"]))
	}

	
	
	poolName := mux.Vars(r)["pool"]

	
	volumeType, err := storagePoolVolumeTypeNameToType(volumeTypeName)
	if err != nil {
		return BadRequest(err)
	}
	
	if !shared.IntInSlice(volumeType, supportedVolumeTypes) {
		return BadRequest(fmt.Errorf("invalid storage volume type %s", volumeTypeName))
	}

	poolID, pool, err := d.cluster.StoragePoolGet(poolName)
	if err != nil {
		return SmartError(err)
	}

	response := ForwardedResponseIfTargetIsRemote(d, r)
	if response != nil {
		return response
	}

	response = ForwardedResponseIfVolumeIsRemote(d, r, poolID, volumeName, volumeType)
	if response != nil {
		return response
	}

	
	_, volume, err := d.cluster.StoragePoolNodeVolumeGetType(volumeName, volumeType, poolID)
	if err != nil {
		return SmartError(err)
	}

	
	etag := []interface{}{volumeName, volume.Type, volume.Config}

	err = util.EtagCheck(r, etag)
	if err != nil {
		return PreconditionFailed(err)
	}

	req := api.StorageVolumePut{}
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		return BadRequest(err)
	}

	if req.Restore != "" {
		ctsUsingVolume, err := storagePoolVolumeUsedByRunningContainersWithProfilesGet(d.State(), poolName, volume.Name, storagePoolVolumeTypeNameCustom, true)
		if err != nil {
			return InternalError(err)
		}

		if len(ctsUsingVolume) != 0 {
			return BadRequest(fmt.Errorf("Cannot restore custom volume used by running containers"))
		}

		err = storagePoolVolumeRestore(d.State(), poolName, volumeName, volumeType, req.Restore)
		if err != nil {
			return SmartError(err)
		}
	} else {
		
		err = storageVolumeValidateConfig(volumeName, req.Config, pool)
		if err != nil {
			return BadRequest(err)
		}

		err = storagePoolVolumeUpdate(d.State(), poolName, volumeName, volumeType, req.Description, req.Config)
		if err != nil {
			return SmartError(err)
		}
	}

	return EmptySyncResponse
}
func storagePoolVolumeTypePut ( d * Daemon , r * http . Request , volumeTypeName string ) Response { // Get the name of the storage volume. var volumeName string fields := strings . Split ( mux . Vars ( r ) [ " " ] , " " ) if len ( fields ) == 3 && fields [ 1 ] == " " { // Handle volume snapshots volumeName = fmt . Sprintf ( " " , fields [ 0 ] , shared . SnapshotDelimiter , fields [ 2 ] ) } else if len ( fields ) > 1 { volumeName = fmt . Sprintf ( " " , fields [ 0 ] , shared . SnapshotDelimiter , fields [ 1 ] ) } else if len ( fields ) > 0 { // Handle volume volumeName = fields [ 0 ] } else { return BadRequest ( fmt . Errorf ( " " , mux . Vars ( r ) [ " " ] ) ) } // Get the name of the storage pool the volume is supposed to be // attached to. poolName := mux . Vars ( r ) [ " " ] // Convert the volume type name to our internal integer representation. volumeType , err := storagePoolVolumeTypeNameToType ( volumeTypeName ) if err != nil { return BadRequest ( err ) } // Check that the storage volume type is valid. if ! shared . IntInSlice ( volumeType , supportedVolumeTypes ) { return BadRequest ( fmt . Errorf ( " " , volumeTypeName ) ) } poolID , pool , err := d . cluster . StoragePoolGet ( poolName ) if err != nil { return SmartError ( err ) } response := ForwardedResponseIfTargetIsRemote ( d , r ) if response != nil { return response } response = ForwardedResponseIfVolumeIsRemote ( d , r , poolID , volumeName , volumeType ) if response != nil { return response } // Get the existing storage volume. _ , volume , err := d . cluster . StoragePoolNodeVolumeGetType ( volumeName , volumeType , poolID ) if err != nil { return SmartError ( err ) } // Validate the ETag etag := [ ] interface { } { volumeName , volume . Type , volume . Config } err = util . EtagCheck ( r , etag ) if err != nil { return PreconditionFailed ( err ) } req := api . StorageVolumePut { } if err := json . NewDecoder ( r . Body ) . Decode ( & req ) ; err != nil { return BadRequest ( err ) } if req . Restore != " " { ctsUsingVolume , err := storagePoolVolumeUsedByRunningContainersWithProfilesGet ( d . State ( ) , poolName , volume . Name , storagePoolVolumeTypeNameCustom , true ) if err != nil { return InternalError ( err ) } if len ( ctsUsingVolume ) != 0 { return BadRequest ( fmt . Errorf ( " " ) ) } err = storagePoolVolumeRestore ( d . State ( ) , poolName , volumeName , volumeType , req . Restore ) if err != nil { return SmartError ( err ) } } else { // Validate the configuration err = storageVolumeValidateConfig ( volumeName , req . Config , pool ) if err != nil { return BadRequest ( err ) } err = storagePoolVolumeUpdate ( d . State ( ) , poolName , volumeName , volumeType , req . Description , req . Config ) if err != nil { return SmartError ( err ) } } return EmptySyncResponse }
// /1.0/storage-pools/{pool}/volumes/{type}/{name}
/ 1 . 0 / storage - pools / { pool } / volumes / { type } / { name }