blob: 5a976d11468d5b29085581df2f8f0295e4ff1654 [file] [log] [blame]
Jon Perritt654fb0e2014-10-23 20:54:14 -05001package bootfromvolume
2
3import (
Jon Perritt4149d7c2014-10-23 21:23:46 -05004 "errors"
Jon Perrittd9a4bf72014-10-23 23:44:04 -05005 "strconv"
Jon Perritt654fb0e2014-10-23 20:54:14 -05006
Jon Perrittd9a4bf72014-10-23 23:44:04 -05007 "github.com/rackspace/gophercloud"
Jon Perritt4149d7c2014-10-23 21:23:46 -05008 "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
Jon Perrittd9a4bf72014-10-23 23:44:04 -05009
10 "github.com/racker/perigee"
Jon Perritt654fb0e2014-10-23 20:54:14 -050011)
12
Jon Perritt01686cd2014-10-24 14:10:16 -050013// SourceType represents the type of medium being used to create the volume.
14type SourceType string
15
16const (
17 Volume SourceType = "volume"
18 Snapshot SourceType = "snapshot"
19 Image SourceType = "image"
20)
21
Jon Perrittd9a4bf72014-10-23 23:44:04 -050022// BlockDevice is a structure with options for booting a server instance
23// from a volume. The volume may be created from an image, snapshot, or another
24// volume.
25type BlockDevice struct {
26 // BootIndex [optional] is the boot index. It defaults to 0.
Jon Perritt8dd49db2014-10-24 12:39:07 -050027 BootIndex int `json:"boot_index"`
Jon Perrittd9a4bf72014-10-23 23:44:04 -050028
29 // DeleteOnTermination [optional] specifies whether or not to delete the attached volume
30 // when the server is deleted. Defaults to `false`.
Jon Perritt8dd49db2014-10-24 12:39:07 -050031 DeleteOnTermination bool `json:"delete_on_termination"`
Jon Perrittd9a4bf72014-10-23 23:44:04 -050032
33 // DestinationType [optional] is the type that gets created. Possible values are "volume"
34 // and "local".
Jon Perritt8dd49db2014-10-24 12:39:07 -050035 DestinationType string `json:"destination_type"`
Jon Perrittd9a4bf72014-10-23 23:44:04 -050036
Jon Perritt61710222014-10-24 13:01:31 -050037 // SourceType [required] must be one of: "volume", "snapshot", "image".
Jon Perritt01686cd2014-10-24 14:10:16 -050038 SourceType SourceType `json:"source_type"`
Jon Perrittd9a4bf72014-10-23 23:44:04 -050039
Jon Perritt61710222014-10-24 13:01:31 -050040 // UUID [required] is the unique identifier for the volume, snapshot, or image (see above)
Jon Perritt8dd49db2014-10-24 12:39:07 -050041 UUID string `json:"uuid"`
Jon Perrittd9a4bf72014-10-23 23:44:04 -050042
43 // VolumeSize [optional] is the size of the volume to create (in gigabytes).
Jon Perritt8dd49db2014-10-24 12:39:07 -050044 VolumeSize int `json:"volume_size"`
Jon Perrittd9a4bf72014-10-23 23:44:04 -050045}
46
47// CreateOptsExt is a structure that extends the server `CreateOpts` structure
48// by allowing for a block device mapping.
Jon Perritt654fb0e2014-10-23 20:54:14 -050049type CreateOptsExt struct {
50 servers.CreateOptsBuilder
Jon Perritt01686cd2014-10-24 14:10:16 -050051 BlockDevice []BlockDevice `json:"block_device_mapping_v2,omitempty"`
Jon Perritt654fb0e2014-10-23 20:54:14 -050052}
53
54// ToServerCreateMap adds the block device mapping option to the base server
55// creation options.
56func (opts CreateOptsExt) ToServerCreateMap() (map[string]interface{}, error) {
Jon Perritt8dd49db2014-10-24 12:39:07 -050057 base, err := opts.CreateOptsBuilder.ToServerCreateMap()
58 if err != nil {
59 return nil, err
60 }
61
Jon Perritt01686cd2014-10-24 14:10:16 -050062 if len(opts.BlockDevice) == 0 {
63 return nil, errors.New("Required fields UUID and SourceType not set.")
Jon Perritt4149d7c2014-10-23 21:23:46 -050064 }
Jon Perritt654fb0e2014-10-23 20:54:14 -050065
Jon Perritt4149d7c2014-10-23 21:23:46 -050066 serverMap := base["server"].(map[string]interface{})
Jon Perrittd9a4bf72014-10-23 23:44:04 -050067
Jon Perritt01686cd2014-10-24 14:10:16 -050068 blockDevice := make([]map[string]interface{}, len(opts.BlockDevice))
Jon Perrittd9a4bf72014-10-23 23:44:04 -050069
Jon Perritt01686cd2014-10-24 14:10:16 -050070 for i, bd := range opts.BlockDevice {
71 if string(bd.SourceType) == "" {
72 return nil, errors.New("SourceType must be one of: volume, image, snapshot.")
73 }
74
75 blockDevice[i] = make(map[string]interface{})
76
77 blockDevice[i]["source_type"] = bd.SourceType
78 blockDevice[i]["boot_index"] = strconv.Itoa(bd.BootIndex)
79 blockDevice[i]["delete_on_termination"] = strconv.FormatBool(bd.DeleteOnTermination)
80 blockDevice[i]["volume_size"] = strconv.Itoa(bd.VolumeSize)
81 if bd.UUID != "" {
82 blockDevice[i]["uuid"] = bd.UUID
83 }
84 if bd.DestinationType != "" {
85 blockDevice[i]["destination_type"] = bd.DestinationType
86 }
87
88 }
89 serverMap["block_device_mapping_v2"] = blockDevice
Jon Perritt654fb0e2014-10-23 20:54:14 -050090
Jon Perritt4149d7c2014-10-23 21:23:46 -050091 return base, nil
Jon Perritt654fb0e2014-10-23 20:54:14 -050092}
Jon Perrittd9a4bf72014-10-23 23:44:04 -050093
94// Create requests the creation of a server from the given block device mapping.
Jon Perritt01686cd2014-10-24 14:10:16 -050095func Create(client *gophercloud.ServiceClient, opts servers.CreateOptsBuilder) servers.CreateResult {
96 var res servers.CreateResult
Jon Perrittd9a4bf72014-10-23 23:44:04 -050097
98 reqBody, err := opts.ToServerCreateMap()
99 if err != nil {
100 res.Err = err
101 return res
102 }
103
104 _, res.Err = perigee.Request("POST", createURL(client), perigee.Options{
105 MoreHeaders: client.AuthenticatedHeaders(),
106 ReqBody: reqBody,
107 Results: &res.Body,
Jon Perritt8dd49db2014-10-24 12:39:07 -0500108 OkCodes: []int{200, 202},
Jon Perrittd9a4bf72014-10-23 23:44:04 -0500109 })
110 return res
111}