Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 

2268 рядки
72 KiB

  1. //
  2. // goamz - Go packages to interact with the Amazon Web Services.
  3. //
  4. // https://wiki.ubuntu.com/goamz
  5. //
  6. // Copyright (c) 2011 Canonical Ltd.
  7. //
  8. // Written by Gustavo Niemeyer <gustavo.niemeyer@canonical.com>
  9. //
  10. package ec2
  11. import (
  12. "crypto/rand"
  13. "encoding/hex"
  14. "encoding/xml"
  15. "fmt"
  16. "log"
  17. "net/http"
  18. "net/http/httputil"
  19. "net/url"
  20. "sort"
  21. "strconv"
  22. "strings"
  23. "time"
  24. "github.com/goamz/goamz/aws"
  25. )
  26. const debug = false
  27. // The EC2 type encapsulates operations with a specific EC2 region.
  28. type EC2 struct {
  29. aws.Auth
  30. aws.Region
  31. httpClient *http.Client
  32. private byte // Reserve the right of using private data.
  33. }
  34. // NewWithClient creates a new EC2 with a custom http client
  35. func NewWithClient(auth aws.Auth, region aws.Region, client *http.Client) *EC2 {
  36. return &EC2{auth, region, client, 0}
  37. }
  38. // New creates a new EC2.
  39. func New(auth aws.Auth, region aws.Region) *EC2 {
  40. return NewWithClient(auth, region, aws.RetryingClient)
  41. }
  42. // ----------------------------------------------------------------------------
  43. // Filtering helper.
  44. // Filter builds filtering parameters to be used in an EC2 query which supports
  45. // filtering. For example:
  46. //
  47. // filter := NewFilter()
  48. // filter.Add("architecture", "i386")
  49. // filter.Add("launch-index", "0")
  50. // resp, err := ec2.Instances(nil, filter)
  51. //
  52. type Filter struct {
  53. m map[string][]string
  54. }
  55. // NewFilter creates a new Filter.
  56. func NewFilter() *Filter {
  57. return &Filter{make(map[string][]string)}
  58. }
  59. // Add appends a filtering parameter with the given name and value(s).
  60. func (f *Filter) Add(name string, value ...string) {
  61. f.m[name] = append(f.m[name], value...)
  62. }
  63. func (f *Filter) addParams(params map[string]string) {
  64. if f != nil {
  65. a := make([]string, len(f.m))
  66. i := 0
  67. for k := range f.m {
  68. a[i] = k
  69. i++
  70. }
  71. sort.StringSlice(a).Sort()
  72. for i, k := range a {
  73. prefix := "Filter." + strconv.Itoa(i+1)
  74. params[prefix+".Name"] = k
  75. for j, v := range f.m[k] {
  76. params[prefix+".Value."+strconv.Itoa(j+1)] = v
  77. }
  78. }
  79. }
  80. }
  81. // ----------------------------------------------------------------------------
  82. // Request dispatching logic.
  83. // Error encapsulates an error returned by EC2.
  84. //
  85. // See http://goo.gl/VZGuC for more details.
  86. type Error struct {
  87. // HTTP status code (200, 403, ...)
  88. StatusCode int
  89. // EC2 error code ("UnsupportedOperation", ...)
  90. Code string
  91. // The human-oriented error message
  92. Message string
  93. RequestId string `xml:"RequestID"`
  94. }
  95. func (err *Error) Error() string {
  96. if err.Code == "" {
  97. return err.Message
  98. }
  99. return fmt.Sprintf("%s (%s)", err.Message, err.Code)
  100. }
  101. // For now a single error inst is being exposed. In the future it may be useful
  102. // to provide access to all of them, but rather than doing it as an array/slice,
  103. // use a *next pointer, so that it's backward compatible and it continues to be
  104. // easy to handle the first error, which is what most people will want.
  105. type xmlErrors struct {
  106. RequestId string `xml:"RequestID"`
  107. Errors []Error `xml:"Errors>Error"`
  108. }
  109. var timeNow = time.Now
  110. func (ec2 *EC2) query(params map[string]string, resp interface{}) error {
  111. params["Version"] = "2014-02-01"
  112. params["Timestamp"] = timeNow().In(time.UTC).Format(time.RFC3339)
  113. endpoint, err := url.Parse(ec2.Region.EC2Endpoint)
  114. if err != nil {
  115. return err
  116. }
  117. if endpoint.Path == "" {
  118. endpoint.Path = "/"
  119. }
  120. sign(ec2.Auth, "GET", endpoint.Path, params, endpoint.Host)
  121. endpoint.RawQuery = multimap(params).Encode()
  122. if debug {
  123. log.Printf("get { %v } -> {\n", endpoint.String())
  124. }
  125. r, err := ec2.httpClient.Get(endpoint.String())
  126. if err != nil {
  127. return err
  128. }
  129. defer r.Body.Close()
  130. if debug {
  131. dump, _ := httputil.DumpResponse(r, true)
  132. log.Printf("response:\n")
  133. log.Printf("%v\n}\n", string(dump))
  134. }
  135. if r.StatusCode != 200 {
  136. return buildError(r)
  137. }
  138. err = xml.NewDecoder(r.Body).Decode(resp)
  139. return err
  140. }
  141. func multimap(p map[string]string) url.Values {
  142. q := make(url.Values, len(p))
  143. for k, v := range p {
  144. q[k] = []string{v}
  145. }
  146. return q
  147. }
  148. func buildError(r *http.Response) error {
  149. errors := xmlErrors{}
  150. xml.NewDecoder(r.Body).Decode(&errors)
  151. var err Error
  152. if len(errors.Errors) > 0 {
  153. err = errors.Errors[0]
  154. }
  155. err.RequestId = errors.RequestId
  156. err.StatusCode = r.StatusCode
  157. if err.Message == "" {
  158. err.Message = r.Status
  159. }
  160. return &err
  161. }
  162. func makeParams(action string) map[string]string {
  163. params := make(map[string]string)
  164. params["Action"] = action
  165. return params
  166. }
  167. func addParamsList(params map[string]string, label string, ids []string) {
  168. for i, id := range ids {
  169. params[label+"."+strconv.Itoa(i+1)] = id
  170. }
  171. }
  172. func addBlockDeviceParams(prename string, params map[string]string, blockdevices []BlockDeviceMapping) {
  173. for i, k := range blockdevices {
  174. // Fixup index since Amazon counts these from 1
  175. prefix := prename + "BlockDeviceMapping." + strconv.Itoa(i+1) + "."
  176. if k.DeviceName != "" {
  177. params[prefix+"DeviceName"] = k.DeviceName
  178. }
  179. if k.VirtualName != "" {
  180. params[prefix+"VirtualName"] = k.VirtualName
  181. }
  182. if k.SnapshotId != "" {
  183. params[prefix+"Ebs.SnapshotId"] = k.SnapshotId
  184. }
  185. if k.VolumeType != "" {
  186. params[prefix+"Ebs.VolumeType"] = k.VolumeType
  187. }
  188. if k.IOPS != 0 {
  189. params[prefix+"Ebs.Iops"] = strconv.FormatInt(k.IOPS, 10)
  190. }
  191. if k.VolumeSize != 0 {
  192. params[prefix+"Ebs.VolumeSize"] = strconv.FormatInt(k.VolumeSize, 10)
  193. }
  194. if k.DeleteOnTermination {
  195. params[prefix+"Ebs.DeleteOnTermination"] = "true"
  196. }
  197. if k.NoDevice {
  198. params[prefix+"NoDevice"] = "true"
  199. }
  200. }
  201. }
  202. // ----------------------------------------------------------------------------
  203. // Instance management functions and types.
  204. // RunInstancesOptions encapsulates options for the respective request in EC2.
  205. //
  206. // See http://goo.gl/Mcm3b for more details.
  207. type RunInstancesOptions struct {
  208. ImageId string
  209. MinCount int
  210. MaxCount int
  211. KeyName string
  212. InstanceType string
  213. SecurityGroups []SecurityGroup
  214. KernelId string
  215. RamdiskId string
  216. UserData []byte
  217. AvailabilityZone string
  218. PlacementGroupName string
  219. Tenancy string
  220. Monitoring bool
  221. SubnetId string
  222. DisableAPITermination bool
  223. ShutdownBehavior string
  224. PrivateIPAddress string
  225. IamInstanceProfile IamInstanceProfile
  226. BlockDevices []BlockDeviceMapping
  227. EbsOptimized bool
  228. AssociatePublicIpAddress bool
  229. }
  230. // Response to a RunInstances request.
  231. //
  232. // See http://goo.gl/Mcm3b for more details.
  233. type RunInstancesResp struct {
  234. RequestId string `xml:"requestId"`
  235. ReservationId string `xml:"reservationId"`
  236. OwnerId string `xml:"ownerId"`
  237. SecurityGroups []SecurityGroup `xml:"groupSet>item"`
  238. Instances []Instance `xml:"instancesSet>item"`
  239. }
  240. // Instance encapsulates a running instance in EC2.
  241. //
  242. // See http://goo.gl/OCH8a for more details.
  243. type Instance struct {
  244. // General instance information
  245. InstanceId string `xml:"instanceId"` // The ID of the instance launched
  246. InstanceType string `xml:"instanceType"` // The instance type eg. m1.small | m1.medium | m1.large etc
  247. AvailabilityZone string `xml:"placement>availabilityZone"` // The Availability Zone the instance is located in
  248. Tags []Tag `xml:"tagSet>item"` // Any tags assigned to the resource
  249. State InstanceState `xml:"instanceState"` // The current state of the instance
  250. Reason string `xml:"reason"` // The reason for the most recent state transition. This might be an empty string
  251. StateReason InstanceStateReason `xml:"stateReason"` // The reason for the most recent state transition
  252. ImageId string `xml:"imageId"` // The ID of the AMI used to launch the instance
  253. KeyName string `xml:"keyName"` // The key pair name, if this instance was launched with an associated key pair
  254. Monitoring string `xml:"monitoring>state"` // Valid values: disabled | enabled | pending
  255. IamInstanceProfile IamInstanceProfile `xml:"iamInstanceProfile"` // The IAM instance profile associated with the instance
  256. LaunchTime string `xml:"launchTime"` // The time the instance was launched
  257. OwnerId string // This isn't currently returned in the response, and is taken from the parent reservation
  258. // More specific information
  259. Architecture string `xml:"architecture"` // Valid values: i386 | x86_64
  260. Hypervisor string `xml:"hypervisor"` // Valid values: ovm | xen
  261. KernelId string `xml:"kernelId"` // The kernel associated with this instance
  262. RamDiskId string `xml:"ramdiskId"` // The RAM disk associated with this instance
  263. Platform string `xml:"platform"` // The value is Windows for Windows AMIs; otherwise blank
  264. VirtualizationType string `xml:"virtualizationType"` // Valid values: paravirtual | hvm
  265. AMILaunchIndex int `xml:"amiLaunchIndex"` // The AMI launch index, which can be used to find this instance in the launch group
  266. PlacementGroupName string `xml:"placement>groupName"` // The name of the placement group the instance is in (for cluster compute instances)
  267. Tenancy string `xml:"placement>tenancy"` // (VPC only) Valid values: default | dedicated
  268. InstanceLifecycle string `xml:"instanceLifecycle"` // Spot instance? Valid values: "spot" or blank
  269. SpotInstanceRequestId string `xml:"spotInstanceRequestId"` // The ID of the Spot Instance request
  270. ClientToken string `xml:"clientToken"` // The idempotency token you provided when you launched the instance
  271. ProductCodes []ProductCode `xml:"productCodes>item"` // The product codes attached to this instance
  272. // Storage
  273. RootDeviceType string `xml:"rootDeviceType"` // Valid values: ebs | instance-store
  274. RootDeviceName string `xml:"rootDeviceName"` // The root device name (for example, /dev/sda1)
  275. BlockDevices []BlockDevice `xml:"blockDeviceMapping>item"` // Any block device mapping entries for the instance
  276. EbsOptimized bool `xml:"ebsOptimized"` // Indicates whether the instance is optimized for Amazon EBS I/O
  277. // Network
  278. DNSName string `xml:"dnsName"` // The public DNS name assigned to the instance. This element remains empty until the instance enters the running state
  279. PrivateDNSName string `xml:"privateDnsName"` // The private DNS name assigned to the instance. This DNS name can only be used inside the Amazon EC2 network. This element remains empty until the instance enters the running state
  280. IPAddress string `xml:"ipAddress"` // The public IP address assigned to the instance
  281. PrivateIPAddress string `xml:"privateIpAddress"` // The private IP address assigned to the instance
  282. SubnetId string `xml:"subnetId"` // The ID of the subnet in which the instance is running
  283. VpcId string `xml:"vpcId"` // The ID of the VPC in which the instance is running
  284. SecurityGroups []SecurityGroup `xml:"groupSet>item"` // A list of the security groups for the instance
  285. // Advanced Networking
  286. NetworkInterfaces []InstanceNetworkInterface `xml:"networkInterfaceSet>item"` // (VPC) One or more network interfaces for the instance
  287. SourceDestCheck bool `xml:"sourceDestCheck"` // Controls whether source/destination checking is enabled on the instance
  288. SriovNetSupport string `xml:"sriovNetSupport"` // Specifies whether enhanced networking is enabled. Valid values: simple
  289. }
  290. // isSpotInstance returns if the instance is a spot instance
  291. func (i Instance) IsSpotInstance() bool {
  292. if i.InstanceLifecycle == "spot" {
  293. return true
  294. }
  295. return false
  296. }
  297. type BlockDevice struct {
  298. DeviceName string `xml:"deviceName"`
  299. EBS EBS `xml:"ebs"`
  300. }
  301. type EBS struct {
  302. VolumeId string `xml:"volumeId"`
  303. Status string `xml:"status"`
  304. AttachTime string `xml:"attachTime"`
  305. DeleteOnTermination bool `xml:"deleteOnTermination"`
  306. }
  307. // ProductCode represents a product code
  308. // See http://goo.gl/hswmQm for more details.
  309. type ProductCode struct {
  310. ProductCode string `xml:"productCode"` // The product code
  311. Type string `xml:"type"` // Valid values: devpay | marketplace
  312. }
  313. // InstanceNetworkInterface represents a network interface attached to an instance
  314. // See http://goo.gl/9eW02N for more details.
  315. type InstanceNetworkInterface struct {
  316. Id string `xml:"networkInterfaceId"`
  317. Description string `xml:"description"`
  318. SubnetId string `xml:"subnetId"`
  319. VpcId string `xml:"vpcId"`
  320. OwnerId string `xml:"ownerId"` // The ID of the AWS account that created the network interface.
  321. Status string `xml:"status"` // Valid values: available | attaching | in-use | detaching
  322. MacAddress string `xml:"macAddress"`
  323. PrivateIPAddress string `xml:"privateIpAddress"`
  324. PrivateDNSName string `xml:"privateDnsName"`
  325. SourceDestCheck bool `xml:"sourceDestCheck"`
  326. SecurityGroups []SecurityGroup `xml:"groupSet>item"`
  327. Attachment InstanceNetworkInterfaceAttachment `xml:"attachment"`
  328. Association InstanceNetworkInterfaceAssociation `xml:"association"`
  329. PrivateIPAddresses []InstancePrivateIpAddress `xml:"privateIpAddressesSet>item"`
  330. }
  331. // InstanceNetworkInterfaceAttachment describes a network interface attachment to an instance
  332. // See http://goo.gl/0ql0Cg for more details
  333. type InstanceNetworkInterfaceAttachment struct {
  334. AttachmentID string `xml:"attachmentID"` // The ID of the network interface attachment.
  335. DeviceIndex int32 `xml:"deviceIndex"` // The index of the device on the instance for the network interface attachment.
  336. Status string `xml:"status"` // Valid values: attaching | attached | detaching | detached
  337. AttachTime string `xml:"attachTime"` // Time attached, as a Datetime
  338. DeleteOnTermination bool `xml:"deleteOnTermination"` // Indicates whether the network interface is deleted when the instance is terminated.
  339. }
  340. // Describes association information for an Elastic IP address.
  341. // See http://goo.gl/YCDdMe for more details
  342. type InstanceNetworkInterfaceAssociation struct {
  343. PublicIP string `xml:"publicIp"` // The address of the Elastic IP address bound to the network interface
  344. PublicDNSName string `xml:"publicDnsName"` // The public DNS name
  345. IPOwnerId string `xml:"ipOwnerId"` // The ID of the owner of the Elastic IP address
  346. }
  347. // InstancePrivateIpAddress describes a private IP address
  348. // See http://goo.gl/irN646 for more details
  349. type InstancePrivateIpAddress struct {
  350. PrivateIPAddress string `xml:"privateIpAddress"` // The private IP address of the network interface
  351. PrivateDNSName string `xml:"privateDnsName"` // The private DNS name
  352. Primary bool `xml:"primary"` // Indicates whether this IP address is the primary private IP address of the network interface
  353. Association InstanceNetworkInterfaceAssociation `xml:"association"` // The association information for an Elastic IP address for the network interface
  354. }
  355. // IamInstanceProfile
  356. // See http://goo.gl/PjyijL for more details
  357. type IamInstanceProfile struct {
  358. ARN string `xml:"arn"`
  359. Id string `xml:"id"`
  360. Name string `xml:"name"`
  361. }
  362. // RunInstances starts new instances in EC2.
  363. // If options.MinCount and options.MaxCount are both zero, a single instance
  364. // will be started; otherwise if options.MaxCount is zero, options.MinCount
  365. // will be used instead.
  366. //
  367. // See http://goo.gl/Mcm3b for more details.
  368. func (ec2 *EC2) RunInstances(options *RunInstancesOptions) (resp *RunInstancesResp, err error) {
  369. params := makeParams("RunInstances")
  370. params["ImageId"] = options.ImageId
  371. params["InstanceType"] = options.InstanceType
  372. var min, max int
  373. if options.MinCount == 0 && options.MaxCount == 0 {
  374. min = 1
  375. max = 1
  376. } else if options.MaxCount == 0 {
  377. min = options.MinCount
  378. max = min
  379. } else {
  380. min = options.MinCount
  381. max = options.MaxCount
  382. }
  383. params["MinCount"] = strconv.Itoa(min)
  384. params["MaxCount"] = strconv.Itoa(max)
  385. token, err := clientToken()
  386. if err != nil {
  387. return nil, err
  388. }
  389. params["ClientToken"] = token
  390. if options.KeyName != "" {
  391. params["KeyName"] = options.KeyName
  392. }
  393. if options.KernelId != "" {
  394. params["KernelId"] = options.KernelId
  395. }
  396. if options.RamdiskId != "" {
  397. params["RamdiskId"] = options.RamdiskId
  398. }
  399. if options.UserData != nil {
  400. userData := make([]byte, b64.EncodedLen(len(options.UserData)))
  401. b64.Encode(userData, options.UserData)
  402. params["UserData"] = string(userData)
  403. }
  404. if options.AvailabilityZone != "" {
  405. params["Placement.AvailabilityZone"] = options.AvailabilityZone
  406. }
  407. if options.PlacementGroupName != "" {
  408. params["Placement.GroupName"] = options.PlacementGroupName
  409. }
  410. if options.Tenancy != "" {
  411. params["Placement.Tenancy"] = options.Tenancy
  412. }
  413. if options.Monitoring {
  414. params["Monitoring.Enabled"] = "true"
  415. }
  416. if options.SubnetId != "" && options.AssociatePublicIpAddress {
  417. // If we have a non-default VPC / Subnet specified, we can flag
  418. // AssociatePublicIpAddress to get a Public IP assigned. By default these are not provided.
  419. // You cannot specify both SubnetId and the NetworkInterface.0.* parameters though, otherwise
  420. // you get: Network interfaces and an instance-level subnet ID may not be specified on the same request
  421. // You also need to attach Security Groups to the NetworkInterface instead of the instance,
  422. // to avoid: Network interfaces and an instance-level security groups may not be specified on
  423. // the same request
  424. params["NetworkInterface.0.DeviceIndex"] = "0"
  425. params["NetworkInterface.0.AssociatePublicIpAddress"] = "true"
  426. params["NetworkInterface.0.SubnetId"] = options.SubnetId
  427. i := 1
  428. for _, g := range options.SecurityGroups {
  429. // We only have SecurityGroupId's on NetworkInterface's, no SecurityGroup params.
  430. if g.Id != "" {
  431. params["NetworkInterface.0.SecurityGroupId."+strconv.Itoa(i)] = g.Id
  432. i++
  433. }
  434. }
  435. } else {
  436. if options.SubnetId != "" {
  437. params["SubnetId"] = options.SubnetId
  438. }
  439. i, j := 1, 1
  440. for _, g := range options.SecurityGroups {
  441. if g.Id != "" {
  442. params["SecurityGroupId."+strconv.Itoa(i)] = g.Id
  443. i++
  444. } else {
  445. params["SecurityGroup."+strconv.Itoa(j)] = g.Name
  446. j++
  447. }
  448. }
  449. }
  450. if options.IamInstanceProfile.ARN != "" {
  451. params["IamInstanceProfile.Arn"] = options.IamInstanceProfile.ARN
  452. }
  453. if options.IamInstanceProfile.Name != "" {
  454. params["IamInstanceProfile.Name"] = options.IamInstanceProfile.Name
  455. }
  456. if options.DisableAPITermination {
  457. params["DisableApiTermination"] = "true"
  458. }
  459. if options.ShutdownBehavior != "" {
  460. params["InstanceInitiatedShutdownBehavior"] = options.ShutdownBehavior
  461. }
  462. if options.PrivateIPAddress != "" {
  463. params["PrivateIpAddress"] = options.PrivateIPAddress
  464. }
  465. if options.EbsOptimized {
  466. params["EbsOptimized"] = "true"
  467. }
  468. addBlockDeviceParams("", params, options.BlockDevices)
  469. resp = &RunInstancesResp{}
  470. err = ec2.query(params, resp)
  471. if err != nil {
  472. return nil, err
  473. }
  474. return
  475. }
  476. func clientToken() (string, error) {
  477. // Maximum EC2 client token size is 64 bytes.
  478. // Each byte expands to two when hex encoded.
  479. buf := make([]byte, 32)
  480. _, err := rand.Read(buf)
  481. if err != nil {
  482. return "", err
  483. }
  484. return hex.EncodeToString(buf), nil
  485. }
  486. // ----------------------------------------------------------------------------
  487. // Spot Instance management functions and types.
  488. // The RequestSpotInstances type encapsulates options for the respective request in EC2.
  489. //
  490. // See http://goo.gl/GRZgCD for more details.
  491. type RequestSpotInstances struct {
  492. SpotPrice string
  493. InstanceCount int
  494. Type string
  495. ImageId string
  496. KeyName string
  497. InstanceType string
  498. SecurityGroups []SecurityGroup
  499. IamInstanceProfile string
  500. KernelId string
  501. RamdiskId string
  502. UserData []byte
  503. AvailZone string
  504. PlacementGroupName string
  505. Monitoring bool
  506. SubnetId string
  507. AssociatePublicIpAddress bool
  508. PrivateIPAddress string
  509. BlockDevices []BlockDeviceMapping
  510. }
  511. type SpotInstanceSpec struct {
  512. ImageId string
  513. KeyName string
  514. InstanceType string
  515. SecurityGroups []SecurityGroup
  516. IamInstanceProfile string
  517. KernelId string
  518. RamdiskId string
  519. UserData []byte
  520. AvailZone string
  521. PlacementGroupName string
  522. Monitoring bool
  523. SubnetId string
  524. AssociatePublicIpAddress bool
  525. PrivateIPAddress string
  526. BlockDevices []BlockDeviceMapping
  527. }
  528. type SpotLaunchSpec struct {
  529. ImageId string `xml:"imageId"`
  530. KeyName string `xml:"keyName"`
  531. InstanceType string `xml:"instanceType"`
  532. SecurityGroups []SecurityGroup `xml:"groupSet>item"`
  533. IamInstanceProfile string `xml:"iamInstanceProfile"`
  534. KernelId string `xml:"kernelId"`
  535. RamdiskId string `xml:"ramdiskId"`
  536. PlacementGroupName string `xml:"placement>groupName"`
  537. Monitoring bool `xml:"monitoring>enabled"`
  538. SubnetId string `xml:"subnetId"`
  539. BlockDevices []BlockDeviceMapping `xml:"blockDeviceMapping>item"`
  540. }
  541. type SpotRequestResult struct {
  542. SpotRequestId string `xml:"spotInstanceRequestId"`
  543. SpotPrice string `xml:"spotPrice"`
  544. Type string `xml:"type"`
  545. AvailZone string `xml:"launchedAvailabilityZone"`
  546. InstanceId string `xml:"instanceId"`
  547. State string `xml:"state"`
  548. SpotLaunchSpec SpotLaunchSpec `xml:"launchSpecification"`
  549. CreateTime string `xml:"createTime"`
  550. Tags []Tag `xml:"tagSet>item"`
  551. }
  552. // Response to a RequestSpotInstances request.
  553. //
  554. // See http://goo.gl/GRZgCD for more details.
  555. type RequestSpotInstancesResp struct {
  556. RequestId string `xml:"requestId"`
  557. SpotRequestResults []SpotRequestResult `xml:"spotInstanceRequestSet>item"`
  558. }
  559. // RequestSpotInstances requests a new spot instances in EC2.
  560. func (ec2 *EC2) RequestSpotInstances(options *RequestSpotInstances) (resp *RequestSpotInstancesResp, err error) {
  561. params := makeParams("RequestSpotInstances")
  562. prefix := "LaunchSpecification" + "."
  563. params["SpotPrice"] = options.SpotPrice
  564. params[prefix+"ImageId"] = options.ImageId
  565. params[prefix+"InstanceType"] = options.InstanceType
  566. if options.InstanceCount != 0 {
  567. params["InstanceCount"] = strconv.Itoa(options.InstanceCount)
  568. }
  569. if options.KeyName != "" {
  570. params[prefix+"KeyName"] = options.KeyName
  571. }
  572. if options.KernelId != "" {
  573. params[prefix+"KernelId"] = options.KernelId
  574. }
  575. if options.RamdiskId != "" {
  576. params[prefix+"RamdiskId"] = options.RamdiskId
  577. }
  578. if options.UserData != nil {
  579. userData := make([]byte, b64.EncodedLen(len(options.UserData)))
  580. b64.Encode(userData, options.UserData)
  581. params[prefix+"UserData"] = string(userData)
  582. }
  583. if options.AvailZone != "" {
  584. params[prefix+"Placement.AvailabilityZone"] = options.AvailZone
  585. }
  586. if options.PlacementGroupName != "" {
  587. params[prefix+"Placement.GroupName"] = options.PlacementGroupName
  588. }
  589. if options.Monitoring {
  590. params[prefix+"Monitoring.Enabled"] = "true"
  591. }
  592. if options.SubnetId != "" && options.AssociatePublicIpAddress {
  593. // If we have a non-default VPC / Subnet specified, we can flag
  594. // AssociatePublicIpAddress to get a Public IP assigned. By default these are not provided.
  595. // You cannot specify both SubnetId and the NetworkInterface.0.* parameters though, otherwise
  596. // you get: Network interfaces and an instance-level subnet ID may not be specified on the same request
  597. // You also need to attach Security Groups to the NetworkInterface instead of the instance,
  598. // to avoid: Network interfaces and an instance-level security groups may not be specified on
  599. // the same request
  600. params[prefix+"NetworkInterface.0.DeviceIndex"] = "0"
  601. params[prefix+"NetworkInterface.0.AssociatePublicIpAddress"] = "true"
  602. params[prefix+"NetworkInterface.0.SubnetId"] = options.SubnetId
  603. i := 1
  604. for _, g := range options.SecurityGroups {
  605. // We only have SecurityGroupId's on NetworkInterface's, no SecurityGroup params.
  606. if g.Id != "" {
  607. params[prefix+"NetworkInterface.0.SecurityGroupId."+strconv.Itoa(i)] = g.Id
  608. i++
  609. }
  610. }
  611. } else {
  612. if options.SubnetId != "" {
  613. params[prefix+"SubnetId"] = options.SubnetId
  614. }
  615. i, j := 1, 1
  616. for _, g := range options.SecurityGroups {
  617. if g.Id != "" {
  618. params[prefix+"SecurityGroupId."+strconv.Itoa(i)] = g.Id
  619. i++
  620. } else {
  621. params[prefix+"SecurityGroup."+strconv.Itoa(j)] = g.Name
  622. j++
  623. }
  624. }
  625. }
  626. if options.IamInstanceProfile != "" {
  627. params[prefix+"IamInstanceProfile.Name"] = options.IamInstanceProfile
  628. }
  629. if options.PrivateIPAddress != "" {
  630. params[prefix+"PrivateIpAddress"] = options.PrivateIPAddress
  631. }
  632. addBlockDeviceParams(prefix, params, options.BlockDevices)
  633. resp = &RequestSpotInstancesResp{}
  634. err = ec2.query(params, resp)
  635. if err != nil {
  636. return nil, err
  637. }
  638. return
  639. }
  640. // Response to a DescribeSpotInstanceRequests request.
  641. //
  642. // See http://goo.gl/KsKJJk for more details.
  643. type SpotRequestsResp struct {
  644. RequestId string `xml:"requestId"`
  645. SpotRequestResults []SpotRequestResult `xml:"spotInstanceRequestSet>item"`
  646. }
  647. // DescribeSpotInstanceRequests returns details about spot requests in EC2. Both parameters
  648. // are optional, and if provided will limit the spot requests returned to those
  649. // matching the given spot request ids or filtering rules.
  650. //
  651. // See http://goo.gl/KsKJJk for more details.
  652. func (ec2 *EC2) DescribeSpotRequests(spotrequestIds []string, filter *Filter) (resp *SpotRequestsResp, err error) {
  653. params := makeParams("DescribeSpotInstanceRequests")
  654. addParamsList(params, "SpotInstanceRequestId", spotrequestIds)
  655. filter.addParams(params)
  656. resp = &SpotRequestsResp{}
  657. err = ec2.query(params, resp)
  658. if err != nil {
  659. return nil, err
  660. }
  661. return
  662. }
  663. // Response to a CancelSpotInstanceRequests request.
  664. //
  665. // See http://goo.gl/3BKHj for more details.
  666. type CancelSpotRequestResult struct {
  667. SpotRequestId string `xml:"spotInstanceRequestId"`
  668. State string `xml:"state"`
  669. }
  670. type CancelSpotRequestsResp struct {
  671. RequestId string `xml:"requestId"`
  672. CancelSpotRequestResults []CancelSpotRequestResult `xml:"spotInstanceRequestSet>item"`
  673. }
  674. // CancelSpotRequests requests the cancellation of spot requests when the given ids.
  675. //
  676. // See http://goo.gl/3BKHj for more details.
  677. func (ec2 *EC2) CancelSpotRequests(spotrequestIds []string) (resp *CancelSpotRequestsResp, err error) {
  678. params := makeParams("CancelSpotInstanceRequests")
  679. addParamsList(params, "SpotInstanceRequestId", spotrequestIds)
  680. resp = &CancelSpotRequestsResp{}
  681. err = ec2.query(params, resp)
  682. if err != nil {
  683. return nil, err
  684. }
  685. return
  686. }
  687. // Response to a TerminateInstances request.
  688. //
  689. // See http://goo.gl/3BKHj for more details.
  690. type TerminateInstancesResp struct {
  691. RequestId string `xml:"requestId"`
  692. StateChanges []InstanceStateChange `xml:"instancesSet>item"`
  693. }
  694. // InstanceState encapsulates the state of an instance in EC2.
  695. //
  696. // See http://goo.gl/y3ZBq for more details.
  697. type InstanceState struct {
  698. Code int `xml:"code"` // Watch out, bits 15-8 have unpublished meaning.
  699. Name string `xml:"name"`
  700. }
  701. // InstanceStateChange informs of the previous and current states
  702. // for an instance when a state change is requested.
  703. type InstanceStateChange struct {
  704. InstanceId string `xml:"instanceId"`
  705. CurrentState InstanceState `xml:"currentState"`
  706. PreviousState InstanceState `xml:"previousState"`
  707. }
  708. // InstanceStateReason describes a state change for an instance in EC2
  709. //
  710. // See http://goo.gl/KZkbXi for more details
  711. type InstanceStateReason struct {
  712. Code string `xml:"code"`
  713. Message string `xml:"message"`
  714. }
  715. // TerminateInstances requests the termination of instances when the given ids.
  716. //
  717. // See http://goo.gl/3BKHj for more details.
  718. func (ec2 *EC2) TerminateInstances(instIds []string) (resp *TerminateInstancesResp, err error) {
  719. params := makeParams("TerminateInstances")
  720. addParamsList(params, "InstanceId", instIds)
  721. resp = &TerminateInstancesResp{}
  722. err = ec2.query(params, resp)
  723. if err != nil {
  724. return nil, err
  725. }
  726. return
  727. }
  728. // Response to a DescribeInstances request.
  729. //
  730. // See http://goo.gl/mLbmw for more details.
  731. type DescribeInstancesResp struct {
  732. RequestId string `xml:"requestId"`
  733. Reservations []Reservation `xml:"reservationSet>item"`
  734. }
  735. // Reservation represents details about a reservation in EC2.
  736. //
  737. // See http://goo.gl/0ItPT for more details.
  738. type Reservation struct {
  739. ReservationId string `xml:"reservationId"`
  740. OwnerId string `xml:"ownerId"`
  741. RequesterId string `xml:"requesterId"`
  742. SecurityGroups []SecurityGroup `xml:"groupSet>item"`
  743. Instances []Instance `xml:"instancesSet>item"`
  744. }
  745. // Instances returns details about instances in EC2. Both parameters
  746. // are optional, and if provided will limit the instances returned to those
  747. // matching the given instance ids or filtering rules.
  748. //
  749. // See http://goo.gl/4No7c for more details.
  750. func (ec2 *EC2) DescribeInstances(instIds []string, filter *Filter) (resp *DescribeInstancesResp, err error) {
  751. params := makeParams("DescribeInstances")
  752. addParamsList(params, "InstanceId", instIds)
  753. filter.addParams(params)
  754. resp = &DescribeInstancesResp{}
  755. err = ec2.query(params, resp)
  756. if err != nil {
  757. return nil, err
  758. }
  759. // Add additional parameters to instances which aren't available in the response
  760. for i, rsv := range resp.Reservations {
  761. ownerId := rsv.OwnerId
  762. for j, inst := range rsv.Instances {
  763. inst.OwnerId = ownerId
  764. resp.Reservations[i].Instances[j] = inst
  765. }
  766. }
  767. return
  768. }
  769. // DescribeInstanceStatusOptions encapsulates the query parameters for the corresponding action.
  770. //
  771. // See http:////goo.gl/2FBTdS for more details.
  772. type DescribeInstanceStatusOptions struct {
  773. InstanceIds []string // If non-empty, limit the query to this subset of instances. Maximum length of 100.
  774. IncludeAllInstances bool // If true, describe all instances, instead of just running instances (the default).
  775. MaxResults int // Maximum number of results to return. Minimum of 5. Maximum of 1000.
  776. NextToken string // The token for the next set of items to return. (You received this token from a prior call.)
  777. }
  778. // Response to a DescribeInstanceStatus request.
  779. //
  780. // See http://goo.gl/2FBTdS for more details.
  781. type DescribeInstanceStatusResp struct {
  782. RequestId string `xml:"requestId"`
  783. InstanceStatusSet []InstanceStatusItem `xml:"instanceStatusSet>item"`
  784. NextToken string `xml:"nextToken"`
  785. }
  786. // InstanceStatusItem describes the instance status, cause, details, and potential actions to take in response.
  787. //
  788. // See http://goo.gl/oImFZZ for more details.
  789. type InstanceStatusItem struct {
  790. InstanceId string `xml:"instanceId"`
  791. AvailabilityZone string `xml:"availabilityZone"`
  792. Events []InstanceStatusEvent `xml:"eventsSet>item"` // Extra information regarding events associated with the instance.
  793. InstanceState InstanceState `xml:"instanceState"` // The intended state of the instance. Calls to DescribeInstanceStatus require that an instance be in the running state.
  794. SystemStatus InstanceStatus `xml:"systemStatus"`
  795. InstanceStatus InstanceStatus `xml:"instanceStatus"`
  796. }
  797. // InstanceStatusEvent describes an instance event.
  798. //
  799. // See http://goo.gl/PXsDTn for more details.
  800. type InstanceStatusEvent struct {
  801. Code string `xml:"code"` // The associated code of the event.
  802. Description string `xml:"description"` // A description of the event.
  803. NotBefore string `xml:"notBefore"` // The earliest scheduled start time for the event.
  804. NotAfter string `xml:"notAfter"` // The latest scheduled end time for the event.
  805. }
  806. // InstanceStatus describes the status of an instance with details.
  807. //
  808. // See http://goo.gl/eFch4S for more details.
  809. type InstanceStatus struct {
  810. Status string `xml:"status"` // The instance status.
  811. Details InstanceStatusDetails `xml:"details"` // The system instance health or application instance health.
  812. }
  813. // InstanceStatusDetails describes the instance status with the cause and more detail.
  814. //
  815. // See http://goo.gl/3qoMC4 for more details.
  816. type InstanceStatusDetails struct {
  817. Name string `xml:"name"` // The type of instance status.
  818. Status string `xml:"status"` // The status.
  819. ImpairedSince string `xml:"impairedSince"` // The time when a status check failed. For an instance that was launched and impaired, this is the time when the instance was launched.
  820. }
  821. // DescribeInstanceStatus returns instance status information about instances in EC2.
  822. // instIds and filter are optional, and if provided will limit the instances returned to those
  823. // matching the given instance ids or filtering rules.
  824. // all determines whether to report all matching instances or only those in the running state
  825. //
  826. // See http://goo.gl/2FBTdS for more details.
  827. func (ec2 *EC2) DescribeInstanceStatus(options *DescribeInstanceStatusOptions, filter *Filter) (resp *DescribeInstanceStatusResp, err error) {
  828. params := makeParams("DescribeInstanceStatus")
  829. if len(options.InstanceIds) > 0 {
  830. addParamsList(params, "InstanceId", options.InstanceIds)
  831. }
  832. if options.IncludeAllInstances {
  833. params["IncludeAllInstances"] = "true"
  834. }
  835. if options.MaxResults != 0 {
  836. params["MaxResults"] = strconv.Itoa(options.MaxResults)
  837. }
  838. if options.NextToken != "" {
  839. params["NextToken"] = options.NextToken
  840. }
  841. filter.addParams(params)
  842. resp = &DescribeInstanceStatusResp{}
  843. err = ec2.query(params, resp)
  844. if err != nil {
  845. return nil, err
  846. }
  847. return
  848. }
  849. // ----------------------------------------------------------------------------
  850. // KeyPair management functions and types.
  851. type CreateKeyPairResp struct {
  852. RequestId string `xml:"requestId"`
  853. KeyName string `xml:"keyName"`
  854. KeyFingerprint string `xml:"keyFingerprint"`
  855. KeyMaterial string `xml:"keyMaterial"`
  856. }
  857. // CreateKeyPair creates a new key pair and returns the private key contents.
  858. //
  859. // See http://goo.gl/0S6hV
  860. func (ec2 *EC2) CreateKeyPair(keyName string) (resp *CreateKeyPairResp, err error) {
  861. params := makeParams("CreateKeyPair")
  862. params["KeyName"] = keyName
  863. resp = &CreateKeyPairResp{}
  864. err = ec2.query(params, resp)
  865. if err == nil {
  866. resp.KeyFingerprint = strings.TrimSpace(resp.KeyFingerprint)
  867. }
  868. return
  869. }
  870. // DeleteKeyPair deletes a key pair.
  871. //
  872. // See http://goo.gl/0bqok
  873. func (ec2 *EC2) DeleteKeyPair(name string) (resp *SimpleResp, err error) {
  874. params := makeParams("DeleteKeyPair")
  875. params["KeyName"] = name
  876. resp = &SimpleResp{}
  877. err = ec2.query(params, resp)
  878. return
  879. }
  880. type ImportKeyPairOptions struct {
  881. KeyName string
  882. PublicKeyMaterial string
  883. }
  884. type ImportKeyPairResp struct {
  885. RequestId string `xml:"requestId"`
  886. KeyName string `xml:"keyName"`
  887. KeyFingerprint string `xml:"keyFingerprint"`
  888. }
  889. // ImportKeyPair import a key pair.
  890. //
  891. // See http://goo.gl/xpTccS
  892. func (ec2 *EC2) ImportKeyPair(options *ImportKeyPairOptions) (resp *ImportKeyPairResp, err error) {
  893. params := makeParams("ImportKeyPair")
  894. params["KeyName"] = options.KeyName
  895. params["PublicKeyMaterial"] = options.PublicKeyMaterial
  896. resp = &ImportKeyPairResp{}
  897. err = ec2.query(params, resp)
  898. return
  899. }
  900. // ResourceTag represents key-value metadata used to classify and organize
  901. // EC2 instances.
  902. //
  903. // See http://goo.gl/bncl3 for more details
  904. type Tag struct {
  905. Key string `xml:"key"`
  906. Value string `xml:"value"`
  907. }
  908. // CreateTags adds or overwrites one or more tags for the specified taggable resources.
  909. // For a list of tagable resources, see: http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Using_Tags.html
  910. //
  911. // See http://goo.gl/Vmkqc for more details
  912. func (ec2 *EC2) CreateTags(resourceIds []string, tags []Tag) (resp *SimpleResp, err error) {
  913. params := makeParams("CreateTags")
  914. addParamsList(params, "ResourceId", resourceIds)
  915. for j, tag := range tags {
  916. params["Tag."+strconv.Itoa(j+1)+".Key"] = tag.Key
  917. params["Tag."+strconv.Itoa(j+1)+".Value"] = tag.Value
  918. }
  919. resp = &SimpleResp{}
  920. err = ec2.query(params, resp)
  921. if err != nil {
  922. return nil, err
  923. }
  924. return resp, nil
  925. }
  926. // Response to a StartInstances request.
  927. //
  928. // See http://goo.gl/awKeF for more details.
  929. type StartInstanceResp struct {
  930. RequestId string `xml:"requestId"`
  931. StateChanges []InstanceStateChange `xml:"instancesSet>item"`
  932. }
  933. // Response to a StopInstances request.
  934. //
  935. // See http://goo.gl/436dJ for more details.
  936. type StopInstanceResp struct {
  937. RequestId string `xml:"requestId"`
  938. StateChanges []InstanceStateChange `xml:"instancesSet>item"`
  939. }
  940. // StartInstances starts an Amazon EBS-backed AMI that you've previously stopped.
  941. //
  942. // See http://goo.gl/awKeF for more details.
  943. func (ec2 *EC2) StartInstances(ids ...string) (resp *StartInstanceResp, err error) {
  944. params := makeParams("StartInstances")
  945. addParamsList(params, "InstanceId", ids)
  946. resp = &StartInstanceResp{}
  947. err = ec2.query(params, resp)
  948. if err != nil {
  949. return nil, err
  950. }
  951. return resp, nil
  952. }
  953. // StopInstances requests stopping one or more Amazon EBS-backed instances.
  954. //
  955. // See http://goo.gl/436dJ for more details.
  956. func (ec2 *EC2) StopInstances(ids ...string) (resp *StopInstanceResp, err error) {
  957. params := makeParams("StopInstances")
  958. addParamsList(params, "InstanceId", ids)
  959. resp = &StopInstanceResp{}
  960. err = ec2.query(params, resp)
  961. if err != nil {
  962. return nil, err
  963. }
  964. return resp, nil
  965. }
  966. // RebootInstance requests a reboot of one or more instances. This operation is asynchronous;
  967. // it only queues a request to reboot the specified instance(s). The operation will succeed
  968. // if the instances are valid and belong to you.
  969. //
  970. // Requests to reboot terminated instances are ignored.
  971. //
  972. // See http://goo.gl/baoUf for more details.
  973. func (ec2 *EC2) RebootInstances(ids ...string) (resp *SimpleResp, err error) {
  974. params := makeParams("RebootInstances")
  975. addParamsList(params, "InstanceId", ids)
  976. resp = &SimpleResp{}
  977. err = ec2.query(params, resp)
  978. if err != nil {
  979. return nil, err
  980. }
  981. return resp, nil
  982. }
  983. // The ModifyInstanceAttribute request parameters.
  984. type ModifyInstance struct {
  985. InstanceType string
  986. BlockDevices []BlockDeviceMapping
  987. DisableAPITermination bool
  988. EbsOptimized bool
  989. SecurityGroups []SecurityGroup
  990. ShutdownBehavior string
  991. KernelId string
  992. RamdiskId string
  993. SourceDestCheck bool
  994. SriovNetSupport bool
  995. UserData []byte
  996. }
  997. // Response to a ModifyInstanceAttribute request.
  998. //
  999. // http://goo.gl/icuXh5 for more details.
  1000. type ModifyInstanceResp struct {
  1001. RequestId string `xml:"requestId"`
  1002. Return bool `xml:"return"`
  1003. }
  1004. // ModifyImageAttribute modifies the specified attribute of the specified instance.
  1005. // You can specify only one attribute at a time. To modify some attributes, the
  1006. // instance must be stopped.
  1007. //
  1008. // See http://goo.gl/icuXh5 for more details.
  1009. func (ec2 *EC2) ModifyInstance(instId string, options *ModifyInstance) (resp *ModifyInstanceResp, err error) {
  1010. params := makeParams("ModifyInstanceAttribute")
  1011. params["InstanceId"] = instId
  1012. addBlockDeviceParams("", params, options.BlockDevices)
  1013. if options.InstanceType != "" {
  1014. params["InstanceType.Value"] = options.InstanceType
  1015. }
  1016. if options.DisableAPITermination {
  1017. params["DisableApiTermination.Value"] = "true"
  1018. }
  1019. if options.EbsOptimized {
  1020. params["EbsOptimized"] = "true"
  1021. }
  1022. if options.ShutdownBehavior != "" {
  1023. params["InstanceInitiatedShutdownBehavior.Value"] = options.ShutdownBehavior
  1024. }
  1025. if options.KernelId != "" {
  1026. params["Kernel.Value"] = options.KernelId
  1027. }
  1028. if options.RamdiskId != "" {
  1029. params["Ramdisk.Value"] = options.RamdiskId
  1030. }
  1031. if options.SourceDestCheck {
  1032. params["SourceDestCheck.Value"] = "true"
  1033. }
  1034. if options.SriovNetSupport {
  1035. params["SriovNetSupport.Value"] = "simple"
  1036. }
  1037. if options.UserData != nil {
  1038. userData := make([]byte, b64.EncodedLen(len(options.UserData)))
  1039. b64.Encode(userData, options.UserData)
  1040. params["UserData"] = string(userData)
  1041. }
  1042. i := 1
  1043. for _, g := range options.SecurityGroups {
  1044. if g.Id != "" {
  1045. params["GroupId."+strconv.Itoa(i)] = g.Id
  1046. i++
  1047. }
  1048. }
  1049. resp = &ModifyInstanceResp{}
  1050. err = ec2.query(params, resp)
  1051. if err != nil {
  1052. resp = nil
  1053. }
  1054. return
  1055. }
  1056. // Reserved Instances
  1057. // Structures
  1058. // DescribeReservedInstancesResponse structure returned from a DescribeReservedInstances request.
  1059. //
  1060. // See
  1061. type DescribeReservedInstancesResponse struct {
  1062. RequestId string `xml:"requestId"`
  1063. ReservedInstances []ReservedInstancesResponseItem `xml:"reservedInstancesSet>item"`
  1064. }
  1065. //
  1066. //
  1067. // See
  1068. type ReservedInstancesResponseItem struct {
  1069. ReservedInstanceId string `xml:"reservedInstancesId"`
  1070. InstanceType string `xml:"instanceType"`
  1071. AvailabilityZone string `xml:"availabilityZone"`
  1072. Start string `xml:"start"`
  1073. Duration uint64 `xml:"duration"`
  1074. End string `xml:"end"`
  1075. FixedPrice float32 `xml:"fixedPrice"`
  1076. UsagePrice float32 `xml:"usagePrice"`
  1077. InstanceCount int `xml:"instanceCount"`
  1078. ProductDescription string `xml:"productDescription"`
  1079. State string `xml:"state"`
  1080. Tags []Tag `xml:"tagSet->item"`
  1081. InstanceTenancy string `xml:"instanceTenancy"`
  1082. CurrencyCode string `xml:"currencyCode"`
  1083. OfferingType string `xml:"offeringType"`
  1084. RecurringCharges []RecurringCharge `xml:"recurringCharges>item"`
  1085. }
  1086. //
  1087. //
  1088. // See
  1089. type RecurringCharge struct {
  1090. Frequency string `xml:"frequency"`
  1091. Amount float32 `xml:"amount"`
  1092. }
  1093. // functions
  1094. // DescribeReservedInstances
  1095. //
  1096. // See
  1097. func (ec2 *EC2) DescribeReservedInstances(instIds []string, filter *Filter) (resp *DescribeReservedInstancesResponse, err error) {
  1098. params := makeParams("DescribeReservedInstances")
  1099. for i, id := range instIds {
  1100. params["ReservedInstancesId."+strconv.Itoa(i+1)] = id
  1101. }
  1102. filter.addParams(params)
  1103. resp = &DescribeReservedInstancesResponse{}
  1104. err = ec2.query(params, resp)
  1105. if err != nil {
  1106. return nil, err
  1107. }
  1108. return resp, nil
  1109. }
  1110. // ----------------------------------------------------------------------------
  1111. // Image and snapshot management functions and types.
  1112. // The CreateImage request parameters.
  1113. //
  1114. // See http://goo.gl/cxU41 for more details.
  1115. type CreateImage struct {
  1116. InstanceId string
  1117. Name string
  1118. Description string
  1119. NoReboot bool
  1120. BlockDevices []BlockDeviceMapping
  1121. }
  1122. // Response to a CreateImage request.
  1123. //
  1124. // See http://goo.gl/cxU41 for more details.
  1125. type CreateImageResp struct {
  1126. RequestId string `xml:"requestId"`
  1127. ImageId string `xml:"imageId"`
  1128. }
  1129. // Response to a DescribeImages request.
  1130. //
  1131. // See http://goo.gl/hLnyg for more details.
  1132. type ImagesResp struct {
  1133. RequestId string `xml:"requestId"`
  1134. Images []Image `xml:"imagesSet>item"`
  1135. }
  1136. // Response to a DescribeImageAttribute request.
  1137. //
  1138. // See http://goo.gl/bHO3zT for more details.
  1139. type ImageAttributeResp struct {
  1140. RequestId string `xml:"requestId"`
  1141. ImageId string `xml:"imageId"`
  1142. Kernel string `xml:"kernel>value"`
  1143. RamDisk string `xml:"ramdisk>value"`
  1144. Description string `xml:"description>value"`
  1145. Group string `xml:"launchPermission>item>group"`
  1146. UserIds []string `xml:"launchPermission>item>userId"`
  1147. ProductCodes []string `xml:"productCodes>item>productCode"`
  1148. BlockDevices []BlockDeviceMapping `xml:"blockDeviceMapping>item"`
  1149. }
  1150. // The RegisterImage request parameters.
  1151. type RegisterImage struct {
  1152. ImageLocation string
  1153. Name string
  1154. Description string
  1155. Architecture string
  1156. KernelId string
  1157. RamdiskId string
  1158. RootDeviceName string
  1159. VirtType string
  1160. BlockDevices []BlockDeviceMapping
  1161. }
  1162. // Response to a RegisterImage request.
  1163. type RegisterImageResp struct {
  1164. RequestId string `xml:"requestId"`
  1165. ImageId string `xml:"imageId"`
  1166. }
  1167. // Response to a DegisterImage request.
  1168. //
  1169. // See http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-DeregisterImage.html
  1170. type DeregisterImageResp struct {
  1171. RequestId string `xml:"requestId"`
  1172. Return bool `xml:"return"`
  1173. }
  1174. // BlockDeviceMapping represents the association of a block device with an image.
  1175. //
  1176. // See http://goo.gl/wnDBf for more details.
  1177. type BlockDeviceMapping struct {
  1178. DeviceName string `xml:"deviceName"`
  1179. VirtualName string `xml:"virtualName"`
  1180. SnapshotId string `xml:"ebs>snapshotId"`
  1181. VolumeType string `xml:"ebs>volumeType"`
  1182. VolumeSize int64 `xml:"ebs>volumeSize"`
  1183. DeleteOnTermination bool `xml:"ebs>deleteOnTermination"`
  1184. NoDevice bool `xml:"noDevice"`
  1185. // The number of I/O operations per second (IOPS) that the volume supports.
  1186. IOPS int64 `xml:"ebs>iops"`
  1187. }
  1188. // Image represents details about an image.
  1189. //
  1190. // See http://goo.gl/iSqJG for more details.
  1191. type Image struct {
  1192. Id string `xml:"imageId"`
  1193. Name string `xml:"name"`
  1194. Description string `xml:"description"`
  1195. Type string `xml:"imageType"`
  1196. State string `xml:"imageState"`
  1197. Location string `xml:"imageLocation"`
  1198. Public bool `xml:"isPublic"`
  1199. Architecture string `xml:"architecture"`
  1200. Platform string `xml:"platform"`
  1201. ProductCodes []string `xml:"productCode>item>productCode"`
  1202. KernelId string `xml:"kernelId"`
  1203. RamdiskId string `xml:"ramdiskId"`
  1204. StateReason string `xml:"stateReason"`
  1205. OwnerId string `xml:"imageOwnerId"`
  1206. OwnerAlias string `xml:"imageOwnerAlias"`
  1207. RootDeviceType string `xml:"rootDeviceType"`
  1208. RootDeviceName string `xml:"rootDeviceName"`
  1209. VirtualizationType string `xml:"virtualizationType"`
  1210. Hypervisor string `xml:"hypervisor"`
  1211. BlockDevices []BlockDeviceMapping `xml:"blockDeviceMapping>item"`
  1212. Tags []Tag `xml:"tagSet>item"`
  1213. }
  1214. // The ModifyImageAttribute request parameters.
  1215. type ModifyImageAttribute struct {
  1216. AddUsers []string
  1217. RemoveUsers []string
  1218. AddGroups []string
  1219. RemoveGroups []string
  1220. ProductCodes []string
  1221. Description string
  1222. }
  1223. // The CopyImage request parameters.
  1224. //
  1225. // See http://goo.gl/hQwPCK for more details.
  1226. type CopyImage struct {
  1227. SourceRegion string
  1228. SourceImageId string
  1229. Name string
  1230. Description string
  1231. ClientToken string
  1232. }
  1233. // Response to a CopyImage request.
  1234. //
  1235. // See http://goo.gl/hQwPCK for more details.
  1236. type CopyImageResp struct {
  1237. RequestId string `xml:"requestId"`
  1238. ImageId string `xml:"imageId"`
  1239. }
  1240. // Creates an Amazon EBS-backed AMI from an Amazon EBS-backed instance
  1241. // that is either running or stopped.
  1242. //
  1243. // See http://goo.gl/cxU41 for more details.
  1244. func (ec2 *EC2) CreateImage(options *CreateImage) (resp *CreateImageResp, err error) {
  1245. params := makeParams("CreateImage")
  1246. params["InstanceId"] = options.InstanceId
  1247. params["Name"] = options.Name
  1248. if options.Description != "" {
  1249. params["Description"] = options.Description
  1250. }
  1251. if options.NoReboot {
  1252. params["NoReboot"] = "true"
  1253. }
  1254. addBlockDeviceParams("", params, options.BlockDevices)
  1255. resp = &CreateImageResp{}
  1256. err = ec2.query(params, resp)
  1257. if err != nil {
  1258. return nil, err
  1259. }
  1260. return
  1261. }
  1262. // Images returns details about available images.
  1263. // The ids and filter parameters, if provided, will limit the images returned.
  1264. // For example, to get all the private images associated with this account set
  1265. // the boolean filter "is-public" to 0.
  1266. // For list of filters: http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeImages.html
  1267. //
  1268. // Note: calling this function with nil ids and filter parameters will result in
  1269. // a very large number of images being returned.
  1270. //
  1271. // See http://goo.gl/SRBhW for more details.
  1272. func (ec2 *EC2) Images(ids []string, filter *Filter) (resp *ImagesResp, err error) {
  1273. params := makeParams("DescribeImages")
  1274. for i, id := range ids {
  1275. params["ImageId."+strconv.Itoa(i+1)] = id
  1276. }
  1277. filter.addParams(params)
  1278. resp = &ImagesResp{}
  1279. err = ec2.query(params, resp)
  1280. if err != nil {
  1281. return nil, err
  1282. }
  1283. return
  1284. }
  1285. // ImagesByOwners returns details about available images.
  1286. // The ids, owners, and filter parameters, if provided, will limit the images returned.
  1287. // For example, to get all the private images associated with this account set
  1288. // the boolean filter "is-public" to 0.
  1289. // For list of filters: http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeImages.html
  1290. //
  1291. // Note: calling this function with nil ids and filter parameters will result in
  1292. // a very large number of images being returned.
  1293. //
  1294. // See http://goo.gl/SRBhW for more details.
  1295. func (ec2 *EC2) ImagesByOwners(ids []string, owners []string, filter *Filter) (resp *ImagesResp, err error) {
  1296. params := makeParams("DescribeImages")
  1297. for i, id := range ids {
  1298. params["ImageId."+strconv.Itoa(i+1)] = id
  1299. }
  1300. for i, owner := range owners {
  1301. params[fmt.Sprintf("Owner.%d", i+1)] = owner
  1302. }
  1303. filter.addParams(params)
  1304. resp = &ImagesResp{}
  1305. err = ec2.query(params, resp)
  1306. if err != nil {
  1307. return nil, err
  1308. }
  1309. return
  1310. }
  1311. // ImageAttribute describes an attribute of an AMI.
  1312. // You can specify only one attribute at a time.
  1313. // Valid attributes are:
  1314. // description | kernel | ramdisk | launchPermission | productCodes | blockDeviceMapping
  1315. //
  1316. // See http://goo.gl/bHO3zT for more details.
  1317. func (ec2 *EC2) ImageAttribute(imageId, attribute string) (resp *ImageAttributeResp, err error) {
  1318. params := makeParams("DescribeImageAttribute")
  1319. params["ImageId"] = imageId
  1320. params["Attribute"] = attribute
  1321. resp = &ImageAttributeResp{}
  1322. err = ec2.query(params, resp)
  1323. if err != nil {
  1324. return nil, err
  1325. }
  1326. return
  1327. }
  1328. // ModifyImageAttribute sets attributes for an image.
  1329. //
  1330. // See http://goo.gl/YUjO4G for more details.
  1331. func (ec2 *EC2) ModifyImageAttribute(imageId string, options *ModifyImageAttribute) (resp *SimpleResp, err error) {
  1332. params := makeParams("ModifyImageAttribute")
  1333. params["ImageId"] = imageId
  1334. if options.Description != "" {
  1335. params["Description.Value"] = options.Description
  1336. }
  1337. if options.AddUsers != nil {
  1338. for i, user := range options.AddUsers {
  1339. p := fmt.Sprintf("LaunchPermission.Add.%d.UserId", i+1)
  1340. params[p] = user
  1341. }
  1342. }
  1343. if options.RemoveUsers != nil {
  1344. for i, user := range options.RemoveUsers {
  1345. p := fmt.Sprintf("LaunchPermission.Remove.%d.UserId", i+1)
  1346. params[p] = user
  1347. }
  1348. }
  1349. if options.AddGroups != nil {
  1350. for i, group := range options.AddGroups {
  1351. p := fmt.Sprintf("LaunchPermission.Add.%d.Group", i+1)
  1352. params[p] = group
  1353. }
  1354. }
  1355. if options.RemoveGroups != nil {
  1356. for i, group := range options.RemoveGroups {
  1357. p := fmt.Sprintf("LaunchPermission.Remove.%d.Group", i+1)
  1358. params[p] = group
  1359. }
  1360. }
  1361. if options.ProductCodes != nil {
  1362. addParamsList(params, "ProductCode", options.ProductCodes)
  1363. }
  1364. resp = &SimpleResp{}
  1365. err = ec2.query(params, resp)
  1366. if err != nil {
  1367. resp = nil
  1368. }
  1369. return
  1370. }
  1371. // Registers a new AMI with EC2.
  1372. //
  1373. // See: http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-RegisterImage.html
  1374. func (ec2 *EC2) RegisterImage(options *RegisterImage) (resp *RegisterImageResp, err error) {
  1375. params := makeParams("RegisterImage")
  1376. params["Name"] = options.Name
  1377. if options.ImageLocation != "" {
  1378. params["ImageLocation"] = options.ImageLocation
  1379. }
  1380. if options.Description != "" {
  1381. params["Description"] = options.Description
  1382. }
  1383. if options.Architecture != "" {
  1384. params["Architecture"] = options.Architecture
  1385. }
  1386. if options.KernelId != "" {
  1387. params["KernelId"] = options.KernelId
  1388. }
  1389. if options.RamdiskId != "" {
  1390. params["RamdiskId"] = options.RamdiskId
  1391. }
  1392. if options.RootDeviceName != "" {
  1393. params["RootDeviceName"] = options.RootDeviceName
  1394. }
  1395. if options.VirtType != "" {
  1396. params["VirtualizationType"] = options.VirtType
  1397. }
  1398. addBlockDeviceParams("", params, options.BlockDevices)
  1399. resp = &RegisterImageResp{}
  1400. err = ec2.query(params, resp)
  1401. if err != nil {
  1402. return nil, err
  1403. }
  1404. return
  1405. }
  1406. // Degisters an image. Note that this does not delete the backing stores of the AMI.
  1407. //
  1408. // See http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-DeregisterImage.html
  1409. func (ec2 *EC2) DeregisterImage(imageId string) (resp *DeregisterImageResp, err error) {
  1410. params := makeParams("DeregisterImage")
  1411. params["ImageId"] = imageId
  1412. resp = &DeregisterImageResp{}
  1413. err = ec2.query(params, resp)
  1414. if err != nil {
  1415. return nil, err
  1416. }
  1417. return
  1418. }
  1419. // Copy and Image from one region to another.
  1420. //
  1421. // See http://goo.gl/hQwPCK for more details.
  1422. func (ec2 *EC2) CopyImage(options *CopyImage) (resp *CopyImageResp, err error) {
  1423. params := makeParams("CopyImage")
  1424. if options.SourceRegion != "" {
  1425. params["SourceRegion"] = options.SourceRegion
  1426. }
  1427. if options.SourceImageId != "" {
  1428. params["SourceImageId"] = options.SourceImageId
  1429. }
  1430. if options.Name != "" {
  1431. params["Name"] = options.Name
  1432. }
  1433. if options.Description != "" {
  1434. params["Description"] = options.Description
  1435. }
  1436. if options.ClientToken != "" {
  1437. params["ClientToken"] = options.ClientToken
  1438. }
  1439. resp = &CopyImageResp{}
  1440. err = ec2.query(params, resp)
  1441. if err != nil {
  1442. return nil, err
  1443. }
  1444. return
  1445. }
  1446. // Response to a CreateSnapshot request.
  1447. //
  1448. // See http://goo.gl/ttcda for more details.
  1449. type CreateSnapshotResp struct {
  1450. RequestId string `xml:"requestId"`
  1451. Snapshot
  1452. }
  1453. // CreateSnapshot creates a volume snapshot and stores it in S3.
  1454. //
  1455. // See http://goo.gl/ttcda for more details.
  1456. func (ec2 *EC2) CreateSnapshot(volumeId, description string) (resp *CreateSnapshotResp, err error) {
  1457. params := makeParams("CreateSnapshot")
  1458. params["VolumeId"] = volumeId
  1459. params["Description"] = description
  1460. resp = &CreateSnapshotResp{}
  1461. err = ec2.query(params, resp)
  1462. if err != nil {
  1463. return nil, err
  1464. }
  1465. return
  1466. }
  1467. // DeleteSnapshots deletes the volume snapshots with the given ids.
  1468. //
  1469. // Note: If you make periodic snapshots of a volume, the snapshots are
  1470. // incremental so that only the blocks on the device that have changed
  1471. // since your last snapshot are incrementally saved in the new snapshot.
  1472. // Even though snapshots are saved incrementally, the snapshot deletion
  1473. // process is designed so that you need to retain only the most recent
  1474. // snapshot in order to restore the volume.
  1475. //
  1476. // See http://goo.gl/vwU1y for more details.
  1477. func (ec2 *EC2) DeleteSnapshots(ids []string) (resp *SimpleResp, err error) {
  1478. params := makeParams("DeleteSnapshot")
  1479. for i, id := range ids {
  1480. params["SnapshotId."+strconv.Itoa(i+1)] = id
  1481. }
  1482. resp = &SimpleResp{}
  1483. err = ec2.query(params, resp)
  1484. if err != nil {
  1485. return nil, err
  1486. }
  1487. return
  1488. }
  1489. // Response to a DescribeSnapshots request.
  1490. //
  1491. // See http://goo.gl/nClDT for more details.
  1492. type SnapshotsResp struct {
  1493. RequestId string `xml:"requestId"`
  1494. Snapshots []Snapshot `xml:"snapshotSet>item"`
  1495. }
  1496. // Snapshot represents details about a volume snapshot.
  1497. //
  1498. // See http://goo.gl/nkovs for more details.
  1499. type Snapshot struct {
  1500. Id string `xml:"snapshotId"`
  1501. VolumeId string `xml:"volumeId"`
  1502. VolumeSize string `xml:"volumeSize"`
  1503. Status string `xml:"status"`
  1504. StartTime string `xml:"startTime"`
  1505. Description string `xml:"description"`
  1506. Progress string `xml:"progress"`
  1507. OwnerId string `xml:"ownerId"`
  1508. OwnerAlias string `xml:"ownerAlias"`
  1509. Tags []Tag `xml:"tagSet>item"`
  1510. }
  1511. // Snapshots returns details about volume snapshots available to the user.
  1512. // The ids and filter parameters, if provided, limit the snapshots returned.
  1513. //
  1514. // See http://goo.gl/ogJL4 for more details.
  1515. func (ec2 *EC2) Snapshots(ids []string, filter *Filter) (resp *SnapshotsResp, err error) {
  1516. params := makeParams("DescribeSnapshots")
  1517. for i, id := range ids {
  1518. params["SnapshotId."+strconv.Itoa(i+1)] = id
  1519. }
  1520. filter.addParams(params)
  1521. resp = &SnapshotsResp{}
  1522. err = ec2.query(params, resp)
  1523. if err != nil {
  1524. return nil, err
  1525. }
  1526. return
  1527. }
  1528. // ----------------------------------------------------------------------------
  1529. // Volume management
  1530. // The CreateVolume request parameters
  1531. //
  1532. // See http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-CreateVolume.html
  1533. type CreateVolume struct {
  1534. AvailZone string
  1535. Size int64
  1536. SnapshotId string
  1537. VolumeType string
  1538. IOPS int64
  1539. }
  1540. // Response to an AttachVolume request
  1541. type AttachVolumeResp struct {
  1542. RequestId string `xml:"requestId"`
  1543. VolumeId string `xml:"volumeId"`
  1544. InstanceId string `xml:"instanceId"`
  1545. Device string `xml:"device"`
  1546. Status string `xml:"status"`
  1547. AttachTime string `xml:"attachTime"`
  1548. }
  1549. // Response to a CreateVolume request
  1550. type CreateVolumeResp struct {
  1551. RequestId string `xml:"requestId"`
  1552. VolumeId string `xml:"volumeId"`
  1553. Size int64 `xml:"size"`
  1554. SnapshotId string `xml:"snapshotId"`
  1555. AvailZone string `xml:"availabilityZone"`
  1556. Status string `xml:"status"`
  1557. CreateTime string `xml:"createTime"`
  1558. VolumeType string `xml:"volumeType"`
  1559. IOPS int64 `xml:"iops"`
  1560. }
  1561. // Volume is a single volume.
  1562. type Volume struct {
  1563. VolumeId string `xml:"volumeId"`
  1564. Size string `xml:"size"`
  1565. SnapshotId string `xml:"snapshotId"`
  1566. AvailZone string `xml:"availabilityZone"`
  1567. Status string `xml:"status"`
  1568. Attachments []VolumeAttachment `xml:"attachmentSet>item"`
  1569. VolumeType string `xml:"volumeType"`
  1570. IOPS int64 `xml:"iops"`
  1571. Tags []Tag `xml:"tagSet>item"`
  1572. }
  1573. type VolumeAttachment struct {
  1574. VolumeId string `xml:"volumeId"`
  1575. InstanceId string `xml:"instanceId"`
  1576. Device string `xml:"device"`
  1577. Status string `xml:"status"`
  1578. }
  1579. // Response to a DescribeVolumes request
  1580. type VolumesResp struct {
  1581. RequestId string `xml:"requestId"`
  1582. Volumes []Volume `xml:"volumeSet>item"`
  1583. }
  1584. // Attach a volume.
  1585. func (ec2 *EC2) AttachVolume(volumeId string, instanceId string, device string) (resp *AttachVolumeResp, err error) {
  1586. params := makeParams("AttachVolume")
  1587. params["VolumeId"] = volumeId
  1588. params["InstanceId"] = instanceId
  1589. params["Device"] = device
  1590. resp = &AttachVolumeResp{}
  1591. err = ec2.query(params, resp)
  1592. if err != nil {
  1593. return nil, err
  1594. }
  1595. return resp, nil
  1596. }
  1597. // Create a new volume.
  1598. func (ec2 *EC2) CreateVolume(options *CreateVolume) (resp *CreateVolumeResp, err error) {
  1599. params := makeParams("CreateVolume")
  1600. params["AvailabilityZone"] = options.AvailZone
  1601. if options.Size > 0 {
  1602. params["Size"] = strconv.FormatInt(options.Size, 10)
  1603. }
  1604. if options.SnapshotId != "" {
  1605. params["SnapshotId"] = options.SnapshotId
  1606. }
  1607. if options.VolumeType != "" {
  1608. params["VolumeType"] = options.VolumeType
  1609. }
  1610. if options.IOPS > 0 {
  1611. params["Iops"] = strconv.FormatInt(options.IOPS, 10)
  1612. }
  1613. resp = &CreateVolumeResp{}
  1614. err = ec2.query(params, resp)
  1615. if err != nil {
  1616. return nil, err
  1617. }
  1618. return resp, nil
  1619. }
  1620. // Delete an EBS volume.
  1621. func (ec2 *EC2) DeleteVolume(id string) (resp *SimpleResp, err error) {
  1622. params := makeParams("DeleteVolume")
  1623. params["VolumeId"] = id
  1624. resp = &SimpleResp{}
  1625. err = ec2.query(params, resp)
  1626. if err != nil {
  1627. return nil, err
  1628. }
  1629. return
  1630. }
  1631. // Detaches an EBS volume.
  1632. func (ec2 *EC2) DetachVolume(id string) (resp *SimpleResp, err error) {
  1633. params := makeParams("DetachVolume")
  1634. params["VolumeId"] = id
  1635. resp = &SimpleResp{}
  1636. err = ec2.query(params, resp)
  1637. if err != nil {
  1638. return nil, err
  1639. }
  1640. return
  1641. }
  1642. // Finds or lists all volumes.
  1643. func (ec2 *EC2) Volumes(volIds []string, filter *Filter) (resp *VolumesResp, err error) {
  1644. params := makeParams("DescribeVolumes")
  1645. addParamsList(params, "VolumeId", volIds)
  1646. filter.addParams(params)
  1647. resp = &VolumesResp{}
  1648. err = ec2.query(params, resp)
  1649. if err != nil {
  1650. return nil, err
  1651. }
  1652. return
  1653. }
  1654. // ----------------------------------------------------------------------------
  1655. // Security group management functions and types.
  1656. // SimpleResp represents a response to an EC2 request which on success will
  1657. // return no other information besides a request id.
  1658. type SimpleResp struct {
  1659. XMLName xml.Name
  1660. RequestId string `xml:"requestId"`
  1661. }
  1662. // CreateSecurityGroupResp represents a response to a CreateSecurityGroup request.
  1663. type CreateSecurityGroupResp struct {
  1664. SecurityGroup
  1665. RequestId string `xml:"requestId"`
  1666. }
  1667. // CreateSecurityGroup run a CreateSecurityGroup request in EC2, with the provided
  1668. // name and description.
  1669. //
  1670. // See http://goo.gl/Eo7Yl for more details.
  1671. func (ec2 *EC2) CreateSecurityGroup(group SecurityGroup) (resp *CreateSecurityGroupResp, err error) {
  1672. params := makeParams("CreateSecurityGroup")
  1673. params["GroupName"] = group.Name
  1674. params["GroupDescription"] = group.Description
  1675. if group.VpcId != "" {
  1676. params["VpcId"] = group.VpcId
  1677. }
  1678. resp = &CreateSecurityGroupResp{}
  1679. err = ec2.query(params, resp)
  1680. if err != nil {
  1681. return nil, err
  1682. }
  1683. resp.Name = group.Name
  1684. return resp, nil
  1685. }
  1686. // SecurityGroupsResp represents a response to a DescribeSecurityGroups
  1687. // request in EC2.
  1688. //
  1689. // See http://goo.gl/k12Uy for more details.
  1690. type SecurityGroupsResp struct {
  1691. RequestId string `xml:"requestId"`
  1692. Groups []SecurityGroupInfo `xml:"securityGroupInfo>item"`
  1693. }
  1694. // SecurityGroup encapsulates details for a security group in EC2.
  1695. //
  1696. // See http://goo.gl/CIdyP for more details.
  1697. type SecurityGroupInfo struct {
  1698. SecurityGroup
  1699. OwnerId string `xml:"ownerId"`
  1700. Description string `xml:"groupDescription"`
  1701. IPPerms []IPPerm `xml:"ipPermissions>item"`
  1702. IPPermsEgress []IPPerm `xml:"ipPermissionsEgress>item"`
  1703. }
  1704. // IPPerm represents an allowance within an EC2 security group.
  1705. //
  1706. // See http://goo.gl/4oTxv for more details.
  1707. type IPPerm struct {
  1708. Protocol string `xml:"ipProtocol"`
  1709. FromPort int `xml:"fromPort"`
  1710. ToPort int `xml:"toPort"`
  1711. SourceIPs []string `xml:"ipRanges>item>cidrIp"`
  1712. SourceGroups []UserSecurityGroup `xml:"groups>item"`
  1713. }
  1714. // UserSecurityGroup holds a security group and the owner
  1715. // of that group.
  1716. type UserSecurityGroup struct {
  1717. Id string `xml:"groupId"`
  1718. Name string `xml:"groupName"`
  1719. OwnerId string `xml:"userId"`
  1720. }
  1721. // SecurityGroup represents an EC2 security group.
  1722. // If SecurityGroup is used as a parameter, then one of Id or Name
  1723. // may be empty. If both are set, then Id is used.
  1724. type SecurityGroup struct {
  1725. Id string `xml:"groupId"`
  1726. Name string `xml:"groupName"`
  1727. Description string `xml:"groupDescription"`
  1728. VpcId string `xml:"vpcId"`
  1729. }
  1730. // SecurityGroupNames is a convenience function that
  1731. // returns a slice of security groups with the given names.
  1732. func SecurityGroupNames(names ...string) []SecurityGroup {
  1733. g := make([]SecurityGroup, len(names))
  1734. for i, name := range names {
  1735. g[i] = SecurityGroup{Name: name}
  1736. }
  1737. return g
  1738. }
  1739. // SecurityGroupNames is a convenience function that
  1740. // returns a slice of security groups with the given ids.
  1741. func SecurityGroupIds(ids ...string) []SecurityGroup {
  1742. g := make([]SecurityGroup, len(ids))
  1743. for i, id := range ids {
  1744. g[i] = SecurityGroup{Id: id}
  1745. }
  1746. return g
  1747. }
  1748. // SecurityGroups returns details about security groups in EC2. Both parameters
  1749. // are optional, and if provided will limit the security groups returned to those
  1750. // matching the given groups or filtering rules.
  1751. //
  1752. // See http://goo.gl/k12Uy for more details.
  1753. func (ec2 *EC2) SecurityGroups(groups []SecurityGroup, filter *Filter) (resp *SecurityGroupsResp, err error) {
  1754. params := makeParams("DescribeSecurityGroups")
  1755. i, j := 1, 1
  1756. for _, g := range groups {
  1757. if g.Id != "" {
  1758. params["GroupId."+strconv.Itoa(i)] = g.Id
  1759. i++
  1760. } else {
  1761. params["GroupName."+strconv.Itoa(j)] = g.Name
  1762. j++
  1763. }
  1764. }
  1765. filter.addParams(params)
  1766. resp = &SecurityGroupsResp{}
  1767. err = ec2.query(params, resp)
  1768. if err != nil {
  1769. return nil, err
  1770. }
  1771. return resp, nil
  1772. }
  1773. // DeleteSecurityGroup removes the given security group in EC2.
  1774. //
  1775. // See http://goo.gl/QJJDO for more details.
  1776. func (ec2 *EC2) DeleteSecurityGroup(group SecurityGroup) (resp *SimpleResp, err error) {
  1777. params := makeParams("DeleteSecurityGroup")
  1778. if group.Id != "" {
  1779. params["GroupId"] = group.Id
  1780. } else {
  1781. params["GroupName"] = group.Name
  1782. }
  1783. resp = &SimpleResp{}
  1784. err = ec2.query(params, resp)
  1785. if err != nil {
  1786. return nil, err
  1787. }
  1788. return resp, nil
  1789. }
  1790. // AuthorizeSecurityGroup creates an allowance for clients matching the provided
  1791. // rules to access instances within the given security group.
  1792. //
  1793. // See http://goo.gl/u2sDJ for more details.
  1794. func (ec2 *EC2) AuthorizeSecurityGroup(group SecurityGroup, perms []IPPerm) (resp *SimpleResp, err error) {
  1795. return ec2.authOrRevoke("AuthorizeSecurityGroupIngress", group, perms)
  1796. }
  1797. // RevokeSecurityGroup revokes permissions from a group.
  1798. //
  1799. // See http://goo.gl/ZgdxA for more details.
  1800. func (ec2 *EC2) RevokeSecurityGroup(group SecurityGroup, perms []IPPerm) (resp *SimpleResp, err error) {
  1801. return ec2.authOrRevoke("RevokeSecurityGroupIngress", group, perms)
  1802. }
  1803. // AuthorizeSecurityGroupEgress creates an allowance for instances within the
  1804. // given security group to access servers matching the provided rules.
  1805. //
  1806. // See http://goo.gl/R91LXY for more details.
  1807. func (ec2 *EC2) AuthorizeSecurityGroupEgress(group SecurityGroup, perms []IPPerm) (resp *SimpleResp, err error) {
  1808. return ec2.authOrRevoke("AuthorizeSecurityGroupEgress", group, perms)
  1809. }
  1810. // RevokeSecurityGroupEgress revokes egress permissions from a group
  1811. //
  1812. // see http://goo.gl/Zv4wh8
  1813. func (ec2 *EC2) RevokeSecurityGroupEgress(group SecurityGroup, perms []IPPerm) (resp *SimpleResp, err error) {
  1814. return ec2.authOrRevoke("RevokeSecurityGroupEgress", group, perms)
  1815. }
  1816. func (ec2 *EC2) authOrRevoke(op string, group SecurityGroup, perms []IPPerm) (resp *SimpleResp, err error) {
  1817. params := makeParams(op)
  1818. if group.Id != "" {
  1819. params["GroupId"] = group.Id
  1820. } else {
  1821. params["GroupName"] = group.Name
  1822. }
  1823. for i, perm := range perms {
  1824. prefix := "IpPermissions." + strconv.Itoa(i+1)
  1825. params[prefix+".IpProtocol"] = perm.Protocol
  1826. params[prefix+".FromPort"] = strconv.Itoa(perm.FromPort)
  1827. params[prefix+".ToPort"] = strconv.Itoa(perm.ToPort)
  1828. for j, ip := range perm.SourceIPs {
  1829. params[prefix+".IpRanges."+strconv.Itoa(j+1)+".CidrIp"] = ip
  1830. }
  1831. for j, g := range perm.SourceGroups {
  1832. subprefix := prefix + ".Groups." + strconv.Itoa(j+1)
  1833. if g.OwnerId != "" {
  1834. params[subprefix+".UserId"] = g.OwnerId
  1835. }
  1836. if g.Id != "" {
  1837. params[subprefix+".GroupId"] = g.Id
  1838. } else {
  1839. params[subprefix+".GroupName"] = g.Name
  1840. }
  1841. }
  1842. }
  1843. resp = &SimpleResp{}
  1844. err = ec2.query(params, resp)
  1845. if err != nil {
  1846. return nil, err
  1847. }
  1848. return resp, nil
  1849. }
  1850. // ----------------------------------------------------------------------------
  1851. // Elastic IP management functions and types.
  1852. // Response to a DescribeAddresses request.
  1853. //
  1854. // See http://goo.gl/zW7J4p for more details.
  1855. type DescribeAddressesResp struct {
  1856. RequestId string `xml:"requestId"`
  1857. Addresses []Address `xml:"addressesSet>item"`
  1858. }
  1859. // Address represents an Elastic IP Address
  1860. // See http://goo.gl/uxCjp7 for more details
  1861. type Address struct {
  1862. PublicIp string `xml:"publicIp"`
  1863. AllocationId string `xml:"allocationId"`
  1864. Domain string `xml:"domain"`
  1865. InstanceId string `xml:"instanceId"`
  1866. AssociationId string `xml:"associationId"`
  1867. NetworkInterfaceId string `xml:"networkInterfaceId"`
  1868. NetworkInterfaceOwnerId string `xml:"networkInterfaceOwnerId"`
  1869. PrivateIpAddress string `xml:"privateIpAddress"`
  1870. }
  1871. // DescribeAddresses returns details about one or more
  1872. // Elastic IP Addresses. Returned addresses can be
  1873. // filtered by Public IP, Allocation ID or multiple filters
  1874. //
  1875. // See http://goo.gl/zW7J4p for more details.
  1876. func (ec2 *EC2) DescribeAddresses(publicIps []string, allocationIds []string, filter *Filter) (resp *DescribeAddressesResp, err error) {
  1877. params := makeParams("DescribeAddresses")
  1878. addParamsList(params, "PublicIp", publicIps)
  1879. addParamsList(params, "AllocationId", allocationIds)
  1880. filter.addParams(params)
  1881. resp = &DescribeAddressesResp{}
  1882. err = ec2.query(params, resp)
  1883. if err != nil {
  1884. return nil, err
  1885. }
  1886. return
  1887. }
  1888. // AllocateAddressOptions are request parameters for allocating an Elastic IP Address
  1889. //
  1890. // See http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-AllocateAddress.html
  1891. type AllocateAddressOptions struct {
  1892. Domain string
  1893. }
  1894. // Response to an AllocateAddress request
  1895. //
  1896. // See http://goo.gl/aLPmbm for more details
  1897. type AllocateAddressResp struct {
  1898. RequestId string `xml:"requestId"`
  1899. PublicIp string `xml:"publicIp"`
  1900. Domain string `xml:"domain"`
  1901. AllocationId string `xml:"allocationId"`
  1902. }
  1903. // Allocates a new Elastic IP address.
  1904. // The domain parameter is optional and is used for provisioning an ip address
  1905. // in EC2 or in VPC respectively
  1906. //
  1907. // See http://goo.gl/aLPmbm for more details
  1908. func (ec2 *EC2) AllocateAddress(options *AllocateAddressOptions) (resp *AllocateAddressResp, err error) {
  1909. params := makeParams("AllocateAddress")
  1910. params["Domain"] = options.Domain
  1911. resp = &AllocateAddressResp{}
  1912. err = ec2.query(params, resp)
  1913. if err != nil {
  1914. return nil, err
  1915. }
  1916. return resp, nil
  1917. }
  1918. // Response to a ReleaseAddress request
  1919. //
  1920. // See http://goo.gl/Ciw2Z8 for more details
  1921. type ReleaseAddressResp struct {
  1922. RequestId string `xml:"requestId"`
  1923. Return bool `xml:"return"`
  1924. }
  1925. // Release existing elastic ip address from the account
  1926. // PublicIp = Required for EC2
  1927. // AllocationId = Required for VPC
  1928. //
  1929. // See http://goo.gl/Ciw2Z8 for more details
  1930. func (ec2 *EC2) ReleaseAddress(publicIp, allocationId string) (resp *ReleaseAddressResp, err error) {
  1931. params := makeParams("ReleaseAddress")
  1932. if publicIp != "" {
  1933. params["PublicIp"] = publicIp
  1934. }
  1935. if allocationId != "" {
  1936. params["AllocationId"] = allocationId
  1937. }
  1938. resp = &ReleaseAddressResp{}
  1939. err = ec2.query(params, resp)
  1940. if err != nil {
  1941. return nil, err
  1942. }
  1943. return resp, nil
  1944. }
  1945. // Options set for AssociateAddress
  1946. //
  1947. // See http://goo.gl/hhj4z7 for more details
  1948. type AssociateAddressOptions struct {
  1949. PublicIp string
  1950. InstanceId string
  1951. AllocationId string
  1952. NetworkInterfaceId string
  1953. PrivateIpAddress string
  1954. AllowReassociation bool
  1955. }
  1956. // Response to an AssociateAddress request
  1957. //
  1958. // See http://goo.gl/hhj4z7 for more details
  1959. type AssociateAddressResp struct {
  1960. RequestId string `xml:"requestId"`
  1961. Return bool `xml:"return"`
  1962. AssociationId string `xml:"associationId"`
  1963. }
  1964. // Associate an Elastic ip address to an instance id or a network interface
  1965. //
  1966. // See http://goo.gl/hhj4z7 for more details
  1967. func (ec2 *EC2) AssociateAddress(options *AssociateAddressOptions) (resp *AssociateAddressResp, err error) {
  1968. params := makeParams("AssociateAddress")
  1969. params["InstanceId"] = options.InstanceId
  1970. if options.PublicIp != "" {
  1971. params["PublicIp"] = options.PublicIp
  1972. }
  1973. if options.AllocationId != "" {
  1974. params["AllocationId"] = options.AllocationId
  1975. }
  1976. if options.NetworkInterfaceId != "" {
  1977. params["NetworkInterfaceId"] = options.NetworkInterfaceId
  1978. }
  1979. if options.PrivateIpAddress != "" {
  1980. params["PrivateIpAddress"] = options.PrivateIpAddress
  1981. }
  1982. if options.AllowReassociation {
  1983. params["AllowReassociation"] = "true"
  1984. }
  1985. resp = &AssociateAddressResp{}
  1986. err = ec2.query(params, resp)
  1987. if err != nil {
  1988. return nil, err
  1989. }
  1990. return resp, nil
  1991. }
  1992. // Response to a Disassociate Address request
  1993. //
  1994. // See http://goo.gl/Dapkuzfor more details
  1995. type DisassociateAddressResp struct {
  1996. RequestId string `xml:"requestId"`
  1997. Return bool `xml:"return"`
  1998. }
  1999. // Disassociate an elastic ip address from an instance
  2000. // PublicIp - Required for EC2
  2001. // AssociationId - Required for VPC
  2002. // See http://goo.gl/Dapkuz for more details
  2003. func (ec2 *EC2) DisassociateAddress(publicIp, associationId string) (resp *DisassociateAddressResp, err error) {
  2004. params := makeParams("DisassociateAddress")
  2005. if publicIp != "" {
  2006. params["PublicIp"] = publicIp
  2007. }
  2008. if associationId != "" {
  2009. params["AssociationId"] = associationId
  2010. }
  2011. resp = &DisassociateAddressResp{}
  2012. err = ec2.query(params, resp)
  2013. if err != nil {
  2014. return nil, err
  2015. }
  2016. return resp, nil
  2017. }