1package bootfromvolume
2
3import (
4	"github.com/gophercloud/gophercloud"
5	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
6)
7
8type (
9	// DestinationType represents the type of medium being used as the
10	// destination of the bootable device.
11	DestinationType string
12
13	// SourceType represents the type of medium being used as the source of the
14	// bootable device.
15	SourceType string
16)
17
18const (
19	// DestinationLocal DestinationType is for using an ephemeral disk as the
20	// destination.
21	DestinationLocal DestinationType = "local"
22
23	// DestinationVolume DestinationType is for using a volume as the destination.
24	DestinationVolume DestinationType = "volume"
25
26	// SourceBlank SourceType is for a "blank" or empty source.
27	SourceBlank SourceType = "blank"
28
29	// SourceImage SourceType is for using images as the source of a block device.
30	SourceImage SourceType = "image"
31
32	// SourceSnapshot SourceType is for using a volume snapshot as the source of
33	// a block device.
34	SourceSnapshot SourceType = "snapshot"
35
36	// SourceVolume SourceType is for using a volume as the source of block
37	// device.
38	SourceVolume SourceType = "volume"
39)
40
41// BlockDevice is a structure with options for creating block devices in a
42// server. The block device may be created from an image, snapshot, new volume,
43// or existing volume. The destination may be a new volume, existing volume
44// which will be attached to the instance, ephemeral disk, or boot device.
45type BlockDevice struct {
46	// SourceType must be one of: "volume", "snapshot", "image", or "blank".
47	SourceType SourceType `json:"source_type" required:"true"`
48
49	// UUID is the unique identifier for the existing volume, snapshot, or
50	// image (see above).
51	UUID string `json:"uuid,omitempty"`
52
53	// BootIndex is the boot index. It defaults to 0.
54	BootIndex int `json:"boot_index"`
55
56	// DeleteOnTermination specifies whether or not to delete the attached volume
57	// when the server is deleted. Defaults to `false`.
58	DeleteOnTermination bool `json:"delete_on_termination"`
59
60	// DestinationType is the type that gets created. Possible values are "volume"
61	// and "local".
62	DestinationType DestinationType `json:"destination_type,omitempty"`
63
64	// GuestFormat specifies the format of the block device.
65	GuestFormat string `json:"guest_format,omitempty"`
66
67	// VolumeSize is the size of the volume to create (in gigabytes). This can be
68	// omitted for existing volumes.
69	VolumeSize int `json:"volume_size,omitempty"`
70
71	// DeviceType specifies the device type of the block devices.
72	// Examples of this are disk, cdrom, floppy, lun, etc.
73	DeviceType string `json:"device_type,omitempty"`
74
75	// DiskBus is the bus type of the block devices.
76	// Examples of this are ide, usb, virtio, scsi, etc.
77	DiskBus string `json:"disk_bus,omitempty"`
78}
79
80// CreateOptsExt is a structure that extends the server `CreateOpts` structure
81// by allowing for a block device mapping.
82type CreateOptsExt struct {
83	servers.CreateOptsBuilder
84	BlockDevice []BlockDevice `json:"block_device_mapping_v2,omitempty"`
85}
86
87// ToServerCreateMap adds the block device mapping option to the base server
88// creation options.
89func (opts CreateOptsExt) ToServerCreateMap() (map[string]interface{}, error) {
90	base, err := opts.CreateOptsBuilder.ToServerCreateMap()
91	if err != nil {
92		return nil, err
93	}
94
95	if len(opts.BlockDevice) == 0 {
96		err := gophercloud.ErrMissingInput{}
97		err.Argument = "bootfromvolume.CreateOptsExt.BlockDevice"
98		return nil, err
99	}
100
101	serverMap := base["server"].(map[string]interface{})
102
103	blockDevice := make([]map[string]interface{}, len(opts.BlockDevice))
104
105	for i, bd := range opts.BlockDevice {
106		b, err := gophercloud.BuildRequestBody(bd, "")
107		if err != nil {
108			return nil, err
109		}
110		blockDevice[i] = b
111	}
112	serverMap["block_device_mapping_v2"] = blockDevice
113
114	return base, nil
115}
116
117// Create requests the creation of a server from the given block device mapping.
118func Create(client *gophercloud.ServiceClient, opts servers.CreateOptsBuilder) (r servers.CreateResult) {
119	b, err := opts.ToServerCreateMap()
120	if err != nil {
121		r.Err = err
122		return
123	}
124	_, r.Err = client.Post(createURL(client), b, &r.Body, &gophercloud.RequestOpts{
125		OkCodes: []int{200, 202},
126	})
127	return
128}
129