blob: dceff3d87eb7cedbba07795351900d8baf40e4ba [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 Perritt654fb0e2014-10-23 20:54:14 -05009)
10
Jon Perritt01686cd2014-10-24 14:10:16 -050011// SourceType represents the type of medium being used to create the volume.
12type SourceType string
13
14const (
15 Volume SourceType = "volume"
16 Snapshot SourceType = "snapshot"
17 Image SourceType = "image"
Joe Topjianecf63dd2015-12-12 20:33:50 +000018 Blank SourceType = "blank"
Jon Perritt01686cd2014-10-24 14:10:16 -050019)
20
Jon Perrittd9a4bf72014-10-23 23:44:04 -050021// BlockDevice is a structure with options for booting a server instance
22// from a volume. The volume may be created from an image, snapshot, or another
23// volume.
24type BlockDevice struct {
25 // BootIndex [optional] is the boot index. It defaults to 0.
Jon Perritt8dd49db2014-10-24 12:39:07 -050026 BootIndex int `json:"boot_index"`
Jon Perrittd9a4bf72014-10-23 23:44:04 -050027
28 // DeleteOnTermination [optional] specifies whether or not to delete the attached volume
29 // when the server is deleted. Defaults to `false`.
Jon Perritt8dd49db2014-10-24 12:39:07 -050030 DeleteOnTermination bool `json:"delete_on_termination"`
Jon Perrittd9a4bf72014-10-23 23:44:04 -050031
32 // DestinationType [optional] is the type that gets created. Possible values are "volume"
33 // and "local".
Jon Perritt8dd49db2014-10-24 12:39:07 -050034 DestinationType string `json:"destination_type"`
Jon Perrittd9a4bf72014-10-23 23:44:04 -050035
Joe Topjianecf63dd2015-12-12 20:33:50 +000036 // GuestFormat [optional] specifies the format of the block device.
37 GuestFormat string `json:"guest_format"`
38
Jon Perritt61710222014-10-24 13:01:31 -050039 // SourceType [required] must be one of: "volume", "snapshot", "image".
Jon Perritt01686cd2014-10-24 14:10:16 -050040 SourceType SourceType `json:"source_type"`
Jon Perrittd9a4bf72014-10-23 23:44:04 -050041
Jon Perritt61710222014-10-24 13:01:31 -050042 // UUID [required] is the unique identifier for the volume, snapshot, or image (see above)
Jon Perritt8dd49db2014-10-24 12:39:07 -050043 UUID string `json:"uuid"`
Jon Perrittd9a4bf72014-10-23 23:44:04 -050044
45 // VolumeSize [optional] is the size of the volume to create (in gigabytes).
Jon Perritt8dd49db2014-10-24 12:39:07 -050046 VolumeSize int `json:"volume_size"`
Jon Perrittd9a4bf72014-10-23 23:44:04 -050047}
48
49// CreateOptsExt is a structure that extends the server `CreateOpts` structure
50// by allowing for a block device mapping.
Jon Perritt654fb0e2014-10-23 20:54:14 -050051type CreateOptsExt struct {
52 servers.CreateOptsBuilder
Jon Perritt01686cd2014-10-24 14:10:16 -050053 BlockDevice []BlockDevice `json:"block_device_mapping_v2,omitempty"`
Jon Perritt654fb0e2014-10-23 20:54:14 -050054}
55
56// ToServerCreateMap adds the block device mapping option to the base server
57// creation options.
58func (opts CreateOptsExt) ToServerCreateMap() (map[string]interface{}, error) {
Jon Perritt8dd49db2014-10-24 12:39:07 -050059 base, err := opts.CreateOptsBuilder.ToServerCreateMap()
60 if err != nil {
61 return nil, err
62 }
63
Jon Perritt01686cd2014-10-24 14:10:16 -050064 if len(opts.BlockDevice) == 0 {
65 return nil, errors.New("Required fields UUID and SourceType not set.")
Jon Perritt4149d7c2014-10-23 21:23:46 -050066 }
Jon Perritt654fb0e2014-10-23 20:54:14 -050067
Jon Perritt4149d7c2014-10-23 21:23:46 -050068 serverMap := base["server"].(map[string]interface{})
Jon Perrittd9a4bf72014-10-23 23:44:04 -050069
Jon Perritt01686cd2014-10-24 14:10:16 -050070 blockDevice := make([]map[string]interface{}, len(opts.BlockDevice))
Jon Perrittd9a4bf72014-10-23 23:44:04 -050071
Jon Perritt01686cd2014-10-24 14:10:16 -050072 for i, bd := range opts.BlockDevice {
73 if string(bd.SourceType) == "" {
74 return nil, errors.New("SourceType must be one of: volume, image, snapshot.")
75 }
76
77 blockDevice[i] = make(map[string]interface{})
78
79 blockDevice[i]["source_type"] = bd.SourceType
80 blockDevice[i]["boot_index"] = strconv.Itoa(bd.BootIndex)
81 blockDevice[i]["delete_on_termination"] = strconv.FormatBool(bd.DeleteOnTermination)
82 blockDevice[i]["volume_size"] = strconv.Itoa(bd.VolumeSize)
83 if bd.UUID != "" {
84 blockDevice[i]["uuid"] = bd.UUID
85 }
86 if bd.DestinationType != "" {
87 blockDevice[i]["destination_type"] = bd.DestinationType
88 }
Joe Topjianecf63dd2015-12-12 20:33:50 +000089 if bd.GuestFormat != "" {
90 blockDevice[i]["guest_format"] = bd.GuestFormat
91 }
Jon Perritt01686cd2014-10-24 14:10:16 -050092
93 }
94 serverMap["block_device_mapping_v2"] = blockDevice
Jon Perritt654fb0e2014-10-23 20:54:14 -050095
Jon Perritt4149d7c2014-10-23 21:23:46 -050096 return base, nil
Jon Perritt654fb0e2014-10-23 20:54:14 -050097}
Jon Perrittd9a4bf72014-10-23 23:44:04 -050098
99// Create requests the creation of a server from the given block device mapping.
Jon Perritt01686cd2014-10-24 14:10:16 -0500100func Create(client *gophercloud.ServiceClient, opts servers.CreateOptsBuilder) servers.CreateResult {
101 var res servers.CreateResult
Jon Perrittd9a4bf72014-10-23 23:44:04 -0500102
103 reqBody, err := opts.ToServerCreateMap()
104 if err != nil {
105 res.Err = err
106 return res
107 }
108
Joe Topjian9d6e6a92015-10-31 23:39:22 +0000109 // Delete imageName and flavorName that come from ToServerCreateMap().
110 // As of Liberty, Boot From Volume is failing if they are passed.
111 delete(reqBody["server"].(map[string]interface{}), "imageName")
112 delete(reqBody["server"].(map[string]interface{}), "flavorName")
113
Jamie Hannaford6a3a78f2015-03-24 14:56:12 +0100114 _, res.Err = client.Post(createURL(client), reqBody, &res.Body, &gophercloud.RequestOpts{
115 OkCodes: []int{200, 202},
Jon Perrittd9a4bf72014-10-23 23:44:04 -0500116 })
117 return res
118}