You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: volume.go
    path of file: ./repos/juju/cmd/juju/storage
    
    the code of the file until where you have to start completion: // Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package storage

import (
	"fmt"

	"github.com/juju/cmd/v3"
	"github.com/juju/errors"
	"github.com/juju/names/v5"

	"github.com/juju/juju/cmd/juju/common"
	"github.com/juju/juju/core/status"
	"github.com/juju/juju/rpc/params"
)

// VolumeInfo defines the serialization behaviour for storage volume.
type VolumeInfo struct {
	// from params.Volume. This is provider-supplied unique volume ID.
	ProviderVolumeId string `yaml:"provider-id,omitempty" json:"provider-id,omitempty"`

	// Storage is the ID of the storage instance that the volume is
	// assigned to, if any.
	Storage string `yaml:"storage,omitempty" json:"storage,omitempty"`

	// Attachments is the set of entities attached to the volume.
	Attachments *VolumeAttachment
    
func createVolumeInfo(details params.VolumeDetails) (names.VolumeTag, VolumeInfo, error) {
	volumeTag, err := names.ParseVolumeTag(details.VolumeTag)
	if err != nil {
		return names.VolumeTag{}, VolumeInfo{}, errors.Trace(err)
	}

	var info VolumeInfo
	info.ProviderVolumeId = details.Info.VolumeId
	info.HardwareId = details.Info.HardwareId
	info.WWN = details.Info.WWN
	info.Pool = details.Info.Pool
	info.Size = details.Info.Size
	info.Persistent = details.Info.Persistent
	info.Life = string(details.Life)
	info.Status = EntityStatus{
		details.Status.Status,
		details.Status.Info,
		// TODO(axw) we should support formatting as ISO time
		common.FormatTime(details.Status.Since, false),
	}

	attachmentsFromDetails := func(
		in map[string]params.VolumeAttachmentDetails,
		out map[string]VolumeAttachment,
	) error {
		for tag, attachment := range in {
			id, err := idFromTag(tag)
			if err != nil {
				return errors.Trace(err)
			}
			out[id] = VolumeAttachment{
				attachment.DeviceName,
				attachment.DeviceLink,
				attachment.BusAddress,
				attachment.ReadOnly,
				string(attachment.Life),
			}
		}
		return nil
	}

	if len(details.MachineAttachments) > 0 {
		machineAttachments := make(map[string]VolumeAttachment)
		if err := attachmentsFromDetails(details.MachineAttachments, machineAttachments); err != nil {
			return names.VolumeTag{}, VolumeInfo{}, errors.Trace(err)
		}
		info.Attachments = &VolumeAttachments{
			Machines: machineAttachments,
		}
	}

	if len(details.UnitAttachments) > 0 {
		unitAttachments := make(map[string]VolumeAttachment)
		if err := attachmentsFromDetails(details.UnitAttachments, unitAttachments); err != nil {
			return names.VolumeTag{}, VolumeInfo{}, errors.Trace(err)
		}
		if info.Attachments == nil {
			info.Attachments = &VolumeAttachments{}
		}
		info.Attachments.Containers = unitAttachments
	}

	if details.Storage != nil {
		storageTag, storageInfo, err := createStorageInfo(*details.Storage)
		if err != nil {
			return names.VolumeTag{}, VolumeInfo{}, errors.Trace(err)
		}
		info.Storage = storageTag.Id()
		if storageInfo.Attachments != nil {
			if info.Attachments == nil {
				info.Attachments = &VolumeAttachments{}
			}
			info.Attachments.Units = storageInfo.Attachments.Units
		}
	}

	return volumeTag, info, nil
}