client/lxd_storage_volumes.go
func (r *ProtocolLXD) CopyStoragePoolVolume(pool string, source ContainerServer, sourcePool string, volume api.StorageVolume, args *StoragePoolVolumeCopyArgs) (RemoteOperation, error) {
	if !r.HasExtension("storage_api_local_volume_handling") {
		return nil, fmt.Errorf("The server is missing the required \"storage_api_local_volume_handling\" API extension")
	}

	if args != nil && args.VolumeOnly && !r.HasExtension("storage_api_volume_snapshots") {
		return nil, fmt.Errorf("The target server is missing the required \"storage_api_volume_snapshots\" API extension")
	}

	req := api.StorageVolumesPost{
		Name: args.Name,
		Type: volume.Type,
		Source: api.StorageVolumeSource{
			Name:       volume.Name,
			Type:       "copy",
			Pool:       sourcePool,
			VolumeOnly: args.VolumeOnly,
		},
	}
	req.Config = volume.Config
	req.Description = volume.Description

	if r == source {
		// Send the request
		op, _, err := r.queryOperation("POST", fmt.Sprintf("/storage-pools/%s/volumes/%s", url.QueryEscape(pool), url.QueryEscape(volume.Type)), req, "")
		if err != nil {
			return nil, err
		}

		rop := remoteOperation{
			targetOp: op,
			chDone:   make(chan bool),
		}

		// Forward targetOp to remote op
		go func() {
			rop.err = rop.targetOp.Wait()
			close(rop.chDone)
		}()

		return &rop, nil
	}

	if !r.HasExtension("storage_api_remote_volume_handling") {
		return nil, fmt.Errorf("The server is missing the required \"storage_api_remote_volume_handling\" API extension")
	}

	sourceReq := api.StorageVolumePost{
		Migration:  true,
		Name:       volume.Name,
		Pool:       sourcePool,
		VolumeOnly: args.VolumeOnly,
	}

	// Push mode migration
	if args != nil && args.Mode == "push" {
		// Get target server connection information
		info, err := r.GetConnectionInfo()
		if err != nil {
			return nil, err
		}

		// Create the container
		req.Source.Type = "migration"
		req.Source.Mode = "push"

		// Send the request
		path := fmt.Sprintf("/storage-pools/%s/volumes/%s", url.QueryEscape(pool), url.QueryEscape(volume.Type))

		// Send the request
		op, _, err := r.queryOperation("POST", path, req, "")
		if err != nil {
			return nil, err
		}
		opAPI := op.Get()

		targetSecrets := map[string]string{}
		for k, v := range opAPI.Metadata {
			targetSecrets[k] = v.(string)
		}

		// Prepare the source request
		target := api.StorageVolumePostTarget{}
		target.Operation = opAPI.ID
		target.Websockets = targetSecrets
		target.Certificate = info.Certificate
		sourceReq.Target = &target

		return r.tryMigrateStoragePoolVolume(source, sourcePool, sourceReq, info.Addresses)
	}

	// Get source server connection information
	info, err := source.GetConnectionInfo()
	if err != nil {
		return nil, err
	}

	// Get secrets from source server
	op, err := source.MigrateStoragePoolVolume(sourcePool, sourceReq)
	if err != nil {
		return nil, err
	}
	opAPI := op.Get()

	// Prepare source server secrets for remote
	sourceSecrets := map[string]string{}
	for k, v := range opAPI.Metadata {
		sourceSecrets[k] = v.(string)
	}

	// Relay mode migration
	if args != nil && args.Mode == "relay" {
		// Push copy source fields
		req.Source.Type = "migration"
		req.Source.Mode = "push"

		// Send the request
		path := fmt.Sprintf("/storage-pools/%s/volumes/%s", url.QueryEscape(pool), url.QueryEscape(volume.Type))

		// Send the request
		targetOp, _, err := r.queryOperation("POST", path, req, "")
		if err != nil {
			return nil, err
		}
		targetOpAPI := targetOp.Get()

		// Extract the websockets
		targetSecrets := map[string]string{}
		for k, v := range targetOpAPI.Metadata {
			targetSecrets[k] = v.(string)
		}

		// Launch the relay
		err = r.proxyMigration(targetOp.(*operation), targetSecrets, source, op.(*operation), sourceSecrets)
		if err != nil {
			return nil, err
		}

		// Prepare a tracking operation
		rop := remoteOperation{
			targetOp: targetOp,
			chDone:   make(chan bool),
		}

		// Forward targetOp to remote op
		go func() {
			rop.err = rop.targetOp.Wait()
			close(rop.chDone)
		}()

		return &rop, nil
	}

	// Pull mode migration
	req.Source.Type = "migration"
	req.Source.Mode = "pull"
	req.Source.Operation = opAPI.ID
	req.Source.Websockets = sourceSecrets
	req.Source.Certificate = info.Certificate

	return r.tryCreateStoragePoolVolume(pool, req, info.Addresses)
}
func (r *ProtocolLXD) CopyStoragePoolVolume(pool string, source ContainerServer, sourcePool string, volume api.StorageVolume, args *StoragePoolVolumeCopyArgs) (RemoteOperation, error) {
	if !r.HasExtension("storage_api_local_volume_handling") {
		return nil, fmt.Errorf("The server is missing the required \"storage_api_local_volume_handling\" API extension")
	}

	if args != nil && args.VolumeOnly && !r.HasExtension("storage_api_volume_snapshots") {
		return nil, fmt.Errorf("The target server is missing the required \"storage_api_volume_snapshots\" API extension")
	}

	req := api.StorageVolumesPost{
		Name: args.Name,
		Type: volume.Type,
		Source: api.StorageVolumeSource{
			Name:       volume.Name,
			Type:       "copy",
			Pool:       sourcePool,
			VolumeOnly: args.VolumeOnly,
		},
	}
	req.Config = volume.Config
	req.Description = volume.Description

	if r == source {
		// Send the request
		op, _, err := r.queryOperation("POST", fmt.Sprintf("/storage-pools/%s/volumes/%s", url.QueryEscape(pool), url.QueryEscape(volume.Type)), req, "")
		if err != nil {
			return nil, err
		}

		rop := remoteOperation{
			targetOp: op,
			chDone:   make(chan bool),
		}

		// Forward targetOp to remote op
		go func() {
			rop.err = rop.targetOp.Wait()
			close(rop.chDone)
		}()

		return &rop, nil
	}

	if !r.HasExtension("storage_api_remote_volume_handling") {
		return nil, fmt.Errorf("The server is missing the required \"storage_api_remote_volume_handling\" API extension")
	}

	sourceReq := api.StorageVolumePost{
		Migration:  true,
		Name:       volume.Name,
		Pool:       sourcePool,
		VolumeOnly: args.VolumeOnly,
	}

	// Push mode migration
	if args != nil && args.Mode == "push" {
		// Get target server connection information
		info, err := r.GetConnectionInfo()
		if err != nil {
			return nil, err
		}

		// Create the container
		req.Source.Type = "migration"
		req.Source.Mode = "push"

		// Send the request
		path := fmt.Sprintf("/storage-pools/%s/volumes/%s", url.QueryEscape(pool), url.QueryEscape(volume.Type))

		// Send the request
		op, _, err := r.queryOperation("POST", path, req, "")
		if err != nil {
			return nil, err
		}
		opAPI := op.Get()

		targetSecrets := map[string]string{}
		for k, v := range opAPI.Metadata {
			targetSecrets[k] = v.(string)
		}

		// Prepare the source request
		target := api.StorageVolumePostTarget{}
		target.Operation = opAPI.ID
		target.Websockets = targetSecrets
		target.Certificate = info.Certificate
		sourceReq.Target = &target

		return r.tryMigrateStoragePoolVolume(source, sourcePool, sourceReq, info.Addresses)
	}

	// Get source server connection information
	info, err := source.GetConnectionInfo()
	if err != nil {
		return nil, err
	}

	// Get secrets from source server
	op, err := source.MigrateStoragePoolVolume(sourcePool, sourceReq)
	if err != nil {
		return nil, err
	}
	opAPI := op.Get()

	// Prepare source server secrets for remote
	sourceSecrets := map[string]string{}
	for k, v := range opAPI.Metadata {
		sourceSecrets[k] = v.(string)
	}

	// Relay mode migration
	if args != nil && args.Mode == "relay" {
		// Push copy source fields
		req.Source.Type = "migration"
		req.Source.Mode = "push"

		// Send the request
		path := fmt.Sprintf("/storage-pools/%s/volumes/%s", url.QueryEscape(pool), url.QueryEscape(volume.Type))

		// Send the request
		targetOp, _, err := r.queryOperation("POST", path, req, "")
		if err != nil {
			return nil, err
		}
		targetOpAPI := targetOp.Get()

		// Extract the websockets
		targetSecrets := map[string]string{}
		for k, v := range targetOpAPI.Metadata {
			targetSecrets[k] = v.(string)
		}

		// Launch the relay
		err = r.proxyMigration(targetOp.(*operation), targetSecrets, source, op.(*operation), sourceSecrets)
		if err != nil {
			return nil, err
		}

		// Prepare a tracking operation
		rop := remoteOperation{
			targetOp: targetOp,
			chDone:   make(chan bool),
		}

		// Forward targetOp to remote op
		go func() {
			rop.err = rop.targetOp.Wait()
			close(rop.chDone)
		}()

		return &rop, nil
	}

	// Pull mode migration
	req.Source.Type = "migration"
	req.Source.Mode = "pull"
	req.Source.Operation = opAPI.ID
	req.Source.Websockets = sourceSecrets
	req.Source.Certificate = info.Certificate

	return r.tryCreateStoragePoolVolume(pool, req, info.Addresses)
}
func ( r * ProtocolLXD ) CopyStoragePoolVolume ( pool string , source ContainerServer , sourcePool string , volume api . StorageVolume , args * StoragePoolVolumeCopyArgs ) ( RemoteOperation , error ) { if ! r . HasExtension ( " " ) { return nil , fmt . Errorf ( " \" \" " ) } if args != nil && args . VolumeOnly && ! r . HasExtension ( " " ) { return nil , fmt . Errorf ( " \" \" " ) } req := api . StorageVolumesPost { Name : args . Name , Type : volume . Type , Source : api . StorageVolumeSource { Name : volume . Name , Type : " " , Pool : sourcePool , VolumeOnly : args . VolumeOnly , } , } req . Config = volume . Config req . Description = volume . Description if r == source { // Send the request op , _ , err := r . queryOperation ( " " , fmt . Sprintf ( " " , url . QueryEscape ( pool ) , url . QueryEscape ( volume . Type ) ) , req , " " ) if err != nil { return nil , err } rop := remoteOperation { targetOp : op , chDone : make ( chan bool ) , } // Forward targetOp to remote op go func ( ) { rop . err = rop . targetOp . Wait ( ) close ( rop . chDone ) } ( ) return & rop , nil } if ! r . HasExtension ( " " ) { return nil , fmt . Errorf ( " \" \" " ) } sourceReq := api . StorageVolumePost { Migration : true , Name : volume . Name , Pool : sourcePool , VolumeOnly : args . VolumeOnly , } // Push mode migration if args != nil && args . Mode == " " { // Get target server connection information info , err := r . GetConnectionInfo ( ) if err != nil { return nil , err } // Create the container req . Source . Type = " " req . Source . Mode = " " // Send the request path := fmt . Sprintf ( " " , url . QueryEscape ( pool ) , url . QueryEscape ( volume . Type ) ) // Send the request op , _ , err := r . queryOperation ( " " , path , req , " " ) if err != nil { return nil , err } opAPI := op . Get ( ) targetSecrets := map [ string ] string { } for k , v := range opAPI . Metadata { targetSecrets [ k ] = v . ( string ) } // Prepare the source request target := api . StorageVolumePostTarget { } target . Operation = opAPI . ID target . Websockets = targetSecrets target . Certificate = info . Certificate sourceReq . Target = & target return r . tryMigrateStoragePoolVolume ( source , sourcePool , sourceReq , info . Addresses ) } // Get source server connection information info , err := source . GetConnectionInfo ( ) if err != nil { return nil , err } // Get secrets from source server op , err := source . MigrateStoragePoolVolume ( sourcePool , sourceReq ) if err != nil { return nil , err } opAPI := op . Get ( ) // Prepare source server secrets for remote sourceSecrets := map [ string ] string { } for k , v := range opAPI . Metadata { sourceSecrets [ k ] = v . ( string ) } // Relay mode migration if args != nil && args . Mode == " " { // Push copy source fields req . Source . Type = " " req . Source . Mode = " " // Send the request path := fmt . Sprintf ( " " , url . QueryEscape ( pool ) , url . QueryEscape ( volume . Type ) ) // Send the request targetOp , _ , err := r . queryOperation ( " " , path , req , " " ) if err != nil { return nil , err } targetOpAPI := targetOp . Get ( ) // Extract the websockets targetSecrets := map [ string ] string { } for k , v := range targetOpAPI . Metadata { targetSecrets [ k ] = v . ( string ) } // Launch the relay err = r . proxyMigration ( targetOp . ( * operation ) , targetSecrets , source , op . ( * operation ) , sourceSecrets ) if err != nil { return nil , err } // Prepare a tracking operation rop := remoteOperation { targetOp : targetOp , chDone : make ( chan bool ) , } // Forward targetOp to remote op go func ( ) { rop . err = rop . targetOp . Wait ( ) close ( rop . chDone ) } ( ) return & rop , nil } // Pull mode migration req . Source . Type = " " req . Source . Mode = " " req . Source . Operation = opAPI . ID req . Source . Websockets = sourceSecrets req . Source . Certificate = info . Certificate return r . tryCreateStoragePoolVolume ( pool , req , info . Addresses ) }
// CopyStoragePoolVolume copies an existing storage volume
CopyStoragePoolVolume copies an existing storage volume