You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

838 lines
26 KiB

  1. //
  2. // cloudformation: This package provides types and functions to interact with the AWS CloudFormation API
  3. //
  4. // Depends on https://github.com/goamz/goamz
  5. //
  6. package cloudformation
  7. import (
  8. "encoding/xml"
  9. "fmt"
  10. "log"
  11. "net/http"
  12. "net/http/httputil"
  13. "net/url"
  14. "strconv"
  15. "strings"
  16. "time"
  17. "github.com/goamz/goamz/aws"
  18. )
  19. // The CloudFormation type encapsulates operations within a specific EC2 region.
  20. type CloudFormation struct {
  21. aws.Auth
  22. aws.Region
  23. }
  24. // New creates a new CloudFormation Client.
  25. func New(auth aws.Auth, region aws.Region) *CloudFormation {
  26. return &CloudFormation{auth, region}
  27. }
  28. const debug = false
  29. // ----------------------------------------------------------------------------
  30. // Request dispatching logic.
  31. // Error encapsulates an error returned by the AWS CloudFormation API.
  32. //
  33. // See http://goo.gl/zDZbuQ for more details.
  34. type Error struct {
  35. // HTTP status code (200, 403, ...)
  36. StatusCode int
  37. // Error type
  38. Type string `xml:"Type"`
  39. // CloudFormation error code
  40. Code string `xml:"Code"`
  41. // The human-oriented error message
  42. Message string `xml:"Message"`
  43. RequestId string `xml:"RequestID"`
  44. }
  45. func (err *Error) Error() string {
  46. if err.Code == "" {
  47. return err.Message
  48. }
  49. return fmt.Sprintf("%s (%s)", err.Message, err.Code)
  50. }
  51. type xmlErrors struct {
  52. RequestId string `xml:"RequestId"`
  53. Errors []Error `xml:"Error"`
  54. }
  55. func (c *CloudFormation) query(params map[string]string, resp interface{}) error {
  56. params["Version"] = "2010-05-15"
  57. data := strings.NewReader(multimap(params).Encode())
  58. hreq, err := http.NewRequest("POST", c.Region.CloudFormationEndpoint+"/", data)
  59. if err != nil {
  60. return err
  61. }
  62. hreq.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
  63. token := c.Auth.Token()
  64. if token != "" {
  65. hreq.Header.Set("X-Amz-Security-Token", token)
  66. }
  67. signer := aws.NewV4Signer(c.Auth, "cloudformation", c.Region)
  68. signer.Sign(hreq)
  69. if debug {
  70. log.Printf("%v -> {\n", hreq)
  71. }
  72. r, err := http.DefaultClient.Do(hreq)
  73. if err != nil {
  74. log.Printf("Error calling Amazon")
  75. return err
  76. }
  77. defer r.Body.Close()
  78. if debug {
  79. dump, _ := httputil.DumpResponse(r, true)
  80. log.Printf("response:\n")
  81. log.Printf("%v\n}\n", string(dump))
  82. }
  83. if r.StatusCode != 200 {
  84. return buildError(r)
  85. }
  86. err = xml.NewDecoder(r.Body).Decode(resp)
  87. return err
  88. }
  89. func buildError(r *http.Response) error {
  90. var (
  91. err Error
  92. errors xmlErrors
  93. )
  94. xml.NewDecoder(r.Body).Decode(&errors)
  95. if len(errors.Errors) > 0 {
  96. err = errors.Errors[0]
  97. }
  98. err.RequestId = errors.RequestId
  99. err.StatusCode = r.StatusCode
  100. if err.Message == "" {
  101. err.Message = r.Status
  102. }
  103. return &err
  104. }
  105. func makeParams(action string) map[string]string {
  106. params := make(map[string]string)
  107. params["Action"] = action
  108. return params
  109. }
  110. func multimap(p map[string]string) url.Values {
  111. q := make(url.Values, len(p))
  112. for k, v := range p {
  113. q[k] = []string{v}
  114. }
  115. return q
  116. }
  117. // addParamsList adds params in the form of param.member.N to the params map
  118. func addParamsList(params map[string]string, label string, ids []string) {
  119. for i, id := range ids {
  120. params[label+"."+strconv.Itoa(i+1)] = id
  121. }
  122. }
  123. // -----------------------------------------------------------------------
  124. // API Supported Types and Methods
  125. // SimpleResp is the basic response from most actions.
  126. type SimpleResp struct {
  127. XMLName xml.Name
  128. RequestId string `xml:"ResponseMetadata>RequestId"`
  129. }
  130. // CancelUpdateStack cancels an update on the specified stack.
  131. // If the call completes successfully, the stack will roll back the update and revert
  132. // to the previous stack configuration.
  133. //
  134. // See http://goo.gl/ZE6fOa for more details
  135. func (c *CloudFormation) CancelUpdateStack(stackName string) (resp *SimpleResp, err error) {
  136. params := makeParams("CancelUpdateStack")
  137. params["StackName"] = stackName
  138. resp = new(SimpleResp)
  139. if err := c.query(params, resp); err != nil {
  140. return nil, err
  141. }
  142. return resp, nil
  143. }
  144. // Parameter encapsulates the cloudstack paramter data type
  145. //
  146. // See http://goo.gl/2rg9eG for more details
  147. type Parameter struct {
  148. ParameterKey string `xml:"ParameterKey"`
  149. ParameterValue string `xml:"ParameterValue"`
  150. UsePreviousValue bool `xml:"UsePreviousValue"`
  151. }
  152. type Tag struct {
  153. Key string `xml:"Key"`
  154. Value string `xml:"Value"`
  155. }
  156. // CreateStackParams wraps CreateStack request options
  157. //
  158. // See http://goo.gl/yDZYuV for more information
  159. type CreateStackParams struct {
  160. Capabilities []string
  161. DisableRollback bool
  162. NotificationARNs []string
  163. OnFailure string
  164. Parameters []Parameter
  165. StackName string
  166. StackPolicyBody string
  167. StackPolicyURL string
  168. Tags []Tag
  169. TemplateBody string
  170. TemplateURL string
  171. TimeoutInMinutes int
  172. }
  173. // CreateStackResponse wraps a CreateStack call response
  174. //
  175. // See http://goo.gl/yDZYuV for more details
  176. type CreateStackResponse struct {
  177. StackId string `xml:"CreateStackResult>StackId"`
  178. RequestId string `xml:"ResponseMetadata>RequestId"`
  179. }
  180. // CreateStack creates a stack as specified in the template. After the call completes successfully,
  181. // the stack creation starts.
  182. //
  183. // Required params: StackName
  184. //
  185. // See http://goo.gl/yDZYuV for more details
  186. func (c *CloudFormation) CreateStack(options *CreateStackParams) (
  187. resp *CreateStackResponse, err error) {
  188. params := makeParams("CreateStack")
  189. params["StackName"] = options.StackName
  190. if options.DisableRollback {
  191. params["DisableRollback"] = strconv.FormatBool(options.DisableRollback)
  192. }
  193. if options.OnFailure != "" {
  194. params["OnFailure"] = options.OnFailure
  195. }
  196. if options.StackPolicyBody != "" {
  197. params["StackPolicyBody"] = options.StackPolicyBody
  198. }
  199. if options.StackPolicyURL != "" {
  200. params["StackPolicyURL"] = options.StackPolicyURL
  201. }
  202. if options.TemplateBody != "" {
  203. params["TemplateBody"] = options.TemplateBody
  204. }
  205. if options.TemplateURL != "" {
  206. params["TemplateURL"] = options.TemplateURL
  207. }
  208. if options.TimeoutInMinutes != 0 {
  209. params["TimeoutInMinutes"] = strconv.Itoa(options.TimeoutInMinutes)
  210. }
  211. if len(options.Capabilities) > 0 {
  212. addParamsList(params, "Capabilities.member", options.Capabilities)
  213. }
  214. if len(options.NotificationARNs) > 0 {
  215. addParamsList(params, "NotificationARNs.member", options.NotificationARNs)
  216. }
  217. // Add any parameters
  218. for i, t := range options.Parameters {
  219. key := "Parameters.member.%d.%s"
  220. index := i + 1
  221. params[fmt.Sprintf(key, index, "ParameterKey")] = t.ParameterKey
  222. params[fmt.Sprintf(key, index, "ParameterValue")] = t.ParameterValue
  223. params[fmt.Sprintf(key, index, "UsePreviousValue")] = strconv.FormatBool(t.UsePreviousValue)
  224. }
  225. // Add any tags
  226. for i, t := range options.Tags {
  227. key := "Tags.member.%d.%s"
  228. index := i + 1
  229. params[fmt.Sprintf(key, index, "Key")] = t.Key
  230. params[fmt.Sprintf(key, index, "Value")] = t.Value
  231. }
  232. resp = new(CreateStackResponse)
  233. if err := c.query(params, resp); err != nil {
  234. return nil, err
  235. }
  236. return resp, nil
  237. }
  238. // DeleteStack deletes a specified stack.
  239. // Once the call completes successfully, stack deletion starts.
  240. //
  241. // See http://goo.gl/CVMpxC for more details
  242. func (c *CloudFormation) DeleteStack(stackName string) (resp *SimpleResp, err error) {
  243. params := makeParams("DeleteStack")
  244. params["StackName"] = stackName
  245. resp = new(SimpleResp)
  246. if err := c.query(params, resp); err != nil {
  247. return nil, err
  248. }
  249. return resp, nil
  250. }
  251. // StackEvent encapsulates the StackEvent data type
  252. //
  253. // See http://goo.gl/EHwiMf for more details
  254. type StackEvent struct {
  255. EventId string `xml:"EventId"`
  256. LogicalResourceId string `xml:"LogicalResourceId"`
  257. PhysicalResourceId string `xml:"PhysicalResourceId"`
  258. ResourceProperties string `xml:"ResourceProperties"`
  259. ResourceStatus string `xml:"ResourceStatus"`
  260. ResourceStatusReason string `xml:"ResourceStatusReason"`
  261. ResourceType string `xml:"ResourceType"`
  262. StackId string `xml:"StackId"`
  263. StackName string `xml:"StackName"`
  264. Timestamp time.Time `xml:"Timestamp"`
  265. }
  266. // DescribeStackEventsResponse wraps a response returned by DescribeStackEvents request
  267. //
  268. // See http://goo.gl/zqj4Bz for more details
  269. type DescribeStackEventsResponse struct {
  270. NextToken string `xml:"DescribeStackEventsResult>NextToken"`
  271. StackEvents []StackEvent `xml:"DescribeStackEventsResult>StackEvents>member"`
  272. RequestId string `xml:"ResponseMetadata>RequestId"`
  273. }
  274. // DescribeStackEvents returns all stack related events for a specified stack.
  275. //
  276. // See http://goo.gl/zqj4Bz for more details
  277. func (c *CloudFormation) DescribeStackEvents(stackName string, nextToken string) (
  278. resp *DescribeStackEventsResponse, err error) {
  279. params := makeParams("DescribeStackEvents")
  280. if stackName != "" {
  281. params["StackName"] = stackName
  282. }
  283. if nextToken != "" {
  284. params["NextToken"] = nextToken
  285. }
  286. resp = new(DescribeStackEventsResponse)
  287. if err := c.query(params, resp); err != nil {
  288. return nil, err
  289. }
  290. return resp, nil
  291. }
  292. // StackResourceDetail encapsulates the StackResourceDetail data type
  293. //
  294. // See http://goo.gl/flce6I for more details
  295. type StackResourceDetail struct {
  296. Description string `xml:"Description"`
  297. LastUpdatedTimestamp time.Time `xml:"LastUpdatedTimestamp"`
  298. LogicalResourceId string `xml:"LogicalResourceId"`
  299. Metadata string `xml:"Metadata"`
  300. PhysicalResourceId string `xml:"PhysicalResourceId"`
  301. ResourceStatus string `xml:"ResourceStatus"`
  302. ResourceStatusReason string `xml:"ResourceStatusReason"`
  303. ResourceType string `xml:"ResourceType"`
  304. StackId string `xml:"StackId"`
  305. StackName string `xml:"StackName"`
  306. }
  307. // DescribeStackResourceResponse wraps a response returned by DescribeStackResource request
  308. //
  309. // See http://goo.gl/6pfPFs for more details
  310. type DescribeStackResourceResponse struct {
  311. StackResourceDetail StackResourceDetail `xml:"DescribeStackResourceResult>StackResourceDetail"`
  312. RequestId string `xml:"ResponseMetadata>RequestId"`
  313. }
  314. // DescribeStackResource returns a description of the specified resource in the specified stack.
  315. // For deleted stacks, DescribeStackResource returns resource information
  316. // for up to 90 days after the stack has been deleted.
  317. //
  318. // Required params: stackName, logicalResourceId
  319. //
  320. // See http://goo.gl/6pfPFs for more details
  321. func (c *CloudFormation) DescribeStackResource(stackName string, logicalResourceId string) (
  322. resp *DescribeStackResourceResponse, err error) {
  323. params := makeParams("DescribeStackResource")
  324. params["StackName"] = stackName
  325. params["LogicalResourceId"] = logicalResourceId
  326. resp = new(DescribeStackResourceResponse)
  327. if err := c.query(params, resp); err != nil {
  328. return nil, err
  329. }
  330. return resp, nil
  331. }
  332. // StackResource encapsulates the StackResource data type
  333. //
  334. // See http://goo.gl/j4eli5 for more details
  335. type StackResource struct {
  336. Description string `xml:"Description"`
  337. LogicalResourceId string `xml:"LogicalResourceId"`
  338. PhysicalResourceId string `xml:"PhysicalResourceId"`
  339. ResourceStatus string `xml:"ResourceStatus"`
  340. ResourceStatusReason string `xml:"ResourceStatusReason"`
  341. ResourceType string `xml:"ResourceType"`
  342. StackId string `xml:"StackId"`
  343. StackName string `xml:"StackName"`
  344. Timestamp time.Time `xml:"Timestamp"`
  345. }
  346. // DescribeStackResourcesResponse wraps a response returned by DescribeStackResources request
  347. //
  348. // See http://goo.gl/YnY5rs for more details
  349. type DescribeStackResourcesResponse struct {
  350. StackResources []StackResource `xml:"DescribeStackResourcesResult>StackResources>member"`
  351. RequestId string `xml:"ResponseMetadata>RequestId"`
  352. }
  353. // DescribeStackResources returns AWS resource descriptions for running and deleted stacks.
  354. // If stackName is specified, all the associated resources that are part of the stack are returned.
  355. // If physicalResourceId is specified, the associated resources of the stack that the resource
  356. // belongs to are returned.
  357. //
  358. // Only the first 100 resources will be returned. If your stack has more resources than this,
  359. // you should use ListStackResources instead.
  360. //
  361. // See http://goo.gl/YnY5rs for more details
  362. func (c *CloudFormation) DescribeStackResources(stackName, physicalResourceId, logicalResourceId string) (
  363. resp *DescribeStackResourcesResponse, err error) {
  364. params := makeParams("DescribeStackResources")
  365. if stackName != "" {
  366. params["StackName"] = stackName
  367. }
  368. if physicalResourceId != "" {
  369. params["PhysicalResourceId"] = physicalResourceId
  370. }
  371. if logicalResourceId != "" {
  372. params["LogicalResourceId"] = logicalResourceId
  373. }
  374. resp = new(DescribeStackResourcesResponse)
  375. if err := c.query(params, resp); err != nil {
  376. return nil, err
  377. }
  378. return resp, nil
  379. }
  380. // Output encapsulates the Output AWS data type
  381. //
  382. // See http://goo.gl/UOn7q6 for more information
  383. type Output struct {
  384. Description string `xml:"Description"`
  385. OutputKey string `xml:"OutputKey"`
  386. OutputValue string `xml:"OutputValue"`
  387. }
  388. // Stack encapsulates the Stack AWS data type
  389. //
  390. // See http://goo.gl/yDZYuV for more information
  391. type Stack struct {
  392. Capabilities []string `xml:"Capabilities>member"`
  393. CreationTime time.Time `xml:"CreationTime"`
  394. Description string `xml:"Description"`
  395. DisableRollback bool `xml:"DisableRollback"`
  396. LastUpdatedTime time.Time `xml:"LastUpdatedTime"`
  397. NotificationARNs []string `xml:"NotificationARNs>member"`
  398. Outputs []Output `xml:"Outputs>member"`
  399. Parameters []Parameter `xml:"Parameters>member"`
  400. StackId string `xml:"StackId"`
  401. StackName string `xml:"StackName"`
  402. StackStatus string `xml:"StackStatus"`
  403. StackStatusReason string `xml:"StackStatusReason"`
  404. Tags []Tag `xml:"Tags>member"`
  405. TimeoutInMinutes int `xml:"TimeoutInMinutes"`
  406. }
  407. // DescribeStacksResponse wraps a response returned by DescribeStacks request
  408. //
  409. // See http://goo.gl/UOLsXD for more information
  410. type DescribeStacksResponse struct {
  411. NextToken string `xml:"DescribeStacksResult>NextToken"`
  412. Stacks []Stack `xml:"DescribeStacksResult>Stacks>member"`
  413. RequestId string `xml:"ResponseMetadata>RequestId"`
  414. }
  415. // DescribeStacks returns the description for the specified stack;
  416. // If no stack name was specified, then it returns the description for all the stacks created.
  417. //
  418. // See http://goo.gl/UOLsXD for more information
  419. func (c *CloudFormation) DescribeStacks(stackName string, nextToken string) (
  420. resp *DescribeStacksResponse, err error) {
  421. params := makeParams("DescribeStacks")
  422. if stackName != "" {
  423. params["StackName"] = stackName
  424. }
  425. if nextToken != "" {
  426. params["NextToken"] = nextToken
  427. }
  428. resp = new(DescribeStacksResponse)
  429. if err := c.query(params, resp); err != nil {
  430. return nil, err
  431. }
  432. return resp, nil
  433. }
  434. // EstimateTemplateCostResponse wraps a response returned by EstimateTemplateCost request
  435. //
  436. // See http://goo.gl/PD9hle for more information
  437. type EstimateTemplateCostResponse struct {
  438. Url string `xml:"EstimateTemplateCostResult>Url"`
  439. RequestId string `xml:"ResponseMetadata>RequestId"`
  440. }
  441. // EstimateTemplateCost returns the estimated monthly cost of a template.
  442. // The return value is an AWS Simple Monthly Calculator URL with a query string that describes
  443. // the resources required to run the template.
  444. //
  445. // See http://goo.gl/PD9hle for more information
  446. func (c *CloudFormation) EstimateTemplateCost(parameters []Parameter, templateBody, templateUrl string) (
  447. resp *EstimateTemplateCostResponse, err error) {
  448. params := makeParams("EstimateTemplateCost")
  449. if templateBody != "" {
  450. params["TemplateBody"] = templateBody
  451. }
  452. if templateUrl != "" {
  453. params["TemplateURL"] = templateUrl
  454. }
  455. // Add any parameters
  456. for i, t := range parameters {
  457. key := "Parameters.member.%d.%s"
  458. index := i + 1
  459. params[fmt.Sprintf(key, index, "ParameterKey")] = t.ParameterKey
  460. params[fmt.Sprintf(key, index, "ParameterValue")] = t.ParameterValue
  461. params[fmt.Sprintf(key, index, "UsePreviousValue")] = strconv.FormatBool(t.UsePreviousValue)
  462. }
  463. resp = new(EstimateTemplateCostResponse)
  464. if err := c.query(params, resp); err != nil {
  465. return nil, err
  466. }
  467. return resp, nil
  468. }
  469. // GetStackPolicyResponse wraps a response returned by GetStackPolicy request
  470. //
  471. // See http://goo.gl/iZFSgy for more information
  472. type GetStackPolicyResponse struct {
  473. StackPolicyBody string `xml:"GetStackPolicyResult>StackPolicyBody"`
  474. RequestId string `xml:"ResponseMetadata>RequestId"`
  475. }
  476. // GetStackPolicy returns the stack policy for a specified stack. If a stack doesn't have a policy,
  477. // a null value is returned.
  478. //
  479. // See http://goo.gl/iZFSgy for more information
  480. func (c *CloudFormation) GetStackPolicy(stackName string) (
  481. resp *GetStackPolicyResponse, err error) {
  482. params := makeParams("GetStackPolicy")
  483. params["StackName"] = stackName
  484. resp = new(GetStackPolicyResponse)
  485. if err := c.query(params, resp); err != nil {
  486. return nil, err
  487. }
  488. return resp, nil
  489. }
  490. // GetTemplateResponse wraps a response returned by GetTemplate request
  491. //
  492. // See http://goo.gl/GU59CB for more information
  493. type GetTemplateResponse struct {
  494. TemplateBody string `xml:"GetTemplateResult>TemplateBody"`
  495. RequestId string `xml:"ResponseMetadata>RequestId"`
  496. }
  497. // GetTemplate returns the template body for a specified stack.
  498. // You can get the template for running or deleted stacks
  499. //
  500. // Required Params: StackName - The name or the unique identifier associated with the stack,
  501. // which are not always interchangeable:
  502. // Running stacks: You can specify either the stack's name or its unique stack ID.
  503. // Deleted stacks: You must specify the unique stack ID.
  504. //
  505. // See http://goo.gl/GU59CB for more information
  506. func (c *CloudFormation) GetTemplate(stackName string) (
  507. resp *GetTemplateResponse, err error) {
  508. params := makeParams("GetTemplate")
  509. params["StackName"] = stackName
  510. resp = new(GetTemplateResponse)
  511. if err := c.query(params, resp); err != nil {
  512. return nil, err
  513. }
  514. return resp, nil
  515. }
  516. // StackResourceSummary encapsulates the StackResourceSummary data type
  517. //
  518. // See http://goo.gl/Af0vcm for more details
  519. type StackResourceSummary struct {
  520. LastUpdatedTimestamp time.Time `xml:"LastUpdatedTimestamp"`
  521. LogicalResourceId string `xml:"LogicalResourceId"`
  522. PhysicalResourceId string `xml:"PhysicalResourceId"`
  523. ResourceStatus string `xml:"ResourceStatus"`
  524. ResourceStatusReason string `xml:"ResourceStatusReason"`
  525. ResourceType string `xml:"ResourceType"`
  526. }
  527. // ListStackResourcesResponse wraps a response returned by ListStackResources request
  528. //
  529. // See http://goo.gl/JUCgLf for more details
  530. type ListStackResourcesResponse struct {
  531. NextToken string `xml:"ListStackResourcesResult>NextToken"`
  532. StackResourceSummaries []StackResourceSummary `xml:"ListStackResourcesResult>StackResourceSummaries>member"`
  533. RequestId string `xml:"ResponseMetadata>RequestId"`
  534. }
  535. // ListStackResources returns descriptions of all resources of the specified stack.
  536. // For deleted stacks, ListStackResources returns resource information for up to 90 days
  537. // after the stack has been deleted.
  538. //
  539. // Required Params: stackName - the name or the unique identifier associated with the stack,
  540. // which are not always interchangeable:
  541. // Running stacks: You can specify either the stack's name or its unique stack ID.
  542. // Deleted stacks: You must specify the unique stack ID.
  543. //
  544. // See http://goo.gl/JUCgLf for more details
  545. func (c *CloudFormation) ListStackResources(stackName, nextToken string) (
  546. resp *ListStackResourcesResponse, err error) {
  547. params := makeParams("ListStackResources")
  548. params["StackName"] = stackName
  549. if nextToken != "" {
  550. params["NextToken"] = nextToken
  551. }
  552. resp = new(ListStackResourcesResponse)
  553. if err := c.query(params, resp); err != nil {
  554. return nil, err
  555. }
  556. return resp, nil
  557. }
  558. // StackSummary encapsulates the StackSummary data type
  559. //
  560. // See http://goo.gl/35j3wf for more details
  561. type StackSummary struct {
  562. CreationTime time.Time `xml:"CreationTime"`
  563. DeletionTime time.Time `xml:"DeletionTime"`
  564. LastUpdatedTime time.Time `xml:"LastUpdatedTime"`
  565. StackId string `xml:"StackId"`
  566. StackName string `xml:"StackName"`
  567. StackStatus string `xml:"StackStatus"`
  568. StackStatusReason string `xml:"StackStatusReason"`
  569. TemplateDescription string `xml:"TemplateDescription"`
  570. }
  571. // ListStacksResponse wraps a response returned by ListStacks request
  572. //
  573. // See http://goo.gl/UWi6nm for more details
  574. type ListStacksResponse struct {
  575. NextToken string `xml:"ListStacksResult>NextToken"`
  576. StackSummaries []StackSummary `xml:"ListStacksResult>StackSummaries>member"`
  577. RequestId string `xml:"ResponseMetadata>RequestId"`
  578. }
  579. // ListStacks Returns the summary information for stacks whose status matches the specified StackStatusFilter.
  580. // Summary information for stacks that have been deleted is kept for 90 days after the stack is deleted.
  581. // If no StackStatusFilter is specified, summary information for all stacks is returned
  582. // (including existing stacks and stacks that have been deleted).
  583. //
  584. // See http://goo.gl/UWi6nm for more details
  585. func (c *CloudFormation) ListStacks(stackStatusFilters []string, nextToken string) (
  586. resp *ListStacksResponse, err error) {
  587. params := makeParams("ListStacks")
  588. if nextToken != "" {
  589. params["NextToken"] = nextToken
  590. }
  591. if len(stackStatusFilters) > 0 {
  592. addParamsList(params, "StackStatusFilter.member", stackStatusFilters)
  593. }
  594. resp = new(ListStacksResponse)
  595. if err := c.query(params, resp); err != nil {
  596. return nil, err
  597. }
  598. return resp, nil
  599. }
  600. // SetStackPolicy sets a stack policy for a specified stack.
  601. //
  602. // Required Params: stackName
  603. //
  604. // See http://goo.gl/iY9ohu for more information
  605. func (c *CloudFormation) SetStackPolicy(stackName, stackPolicyBody, stackPolicyUrl string) (
  606. resp *SimpleResp, err error) {
  607. params := makeParams("SetStackPolicy")
  608. params["StackName"] = stackName
  609. if stackPolicyBody != "" {
  610. params["StackPolicyBody"] = stackPolicyBody
  611. }
  612. if stackPolicyUrl != "" {
  613. params["StackPolicyURL"] = stackPolicyUrl
  614. }
  615. resp = new(SimpleResp)
  616. if err := c.query(params, resp); err != nil {
  617. return nil, err
  618. }
  619. return resp, nil
  620. }
  621. // UpdateStackParams wraps UpdateStack request options
  622. //
  623. // See http://goo.gl/LvkhZq for more information
  624. type UpdateStackParams struct {
  625. Capabilities []string
  626. NotificationARNs []string
  627. Parameters []Parameter
  628. StackName string
  629. StackPolicyBody string
  630. StackPolicyDuringUpdateBody string
  631. StackPolicyDuringUpdateURL string
  632. StackPolicyURL string
  633. TemplateBody string
  634. TemplateURL string
  635. UsePreviousTemplate bool
  636. }
  637. // UpdateStackResponse wraps the UpdateStack call response
  638. //
  639. // See http://goo.gl/LvkhZq for more information
  640. type UpdateStackResponse struct {
  641. StackId string `xml:"UpdateStackResult>StackId"`
  642. RequestId string `xml:"ResponseMetadata>RequestId"`
  643. }
  644. // UpdateStack updates a stack as specified in the template.
  645. // After the call completes successfully, the stack update starts.
  646. // You can check the status of the stack via the DescribeStacks action.
  647. //
  648. // Required Params: options.StackName
  649. //
  650. // See http://goo.gl/LvkhZq for more information
  651. func (c *CloudFormation) UpdateStack(options *UpdateStackParams) (
  652. resp *UpdateStackResponse, err error) {
  653. params := makeParams("UpdateStack")
  654. params["StackName"] = options.StackName
  655. if options.StackPolicyBody != "" {
  656. params["StackPolicyBody"] = options.StackPolicyBody
  657. }
  658. if options.StackPolicyDuringUpdateBody != "" {
  659. params["StackPolicyDuringUpdateBody"] = options.StackPolicyDuringUpdateBody
  660. }
  661. if options.StackPolicyDuringUpdateURL != "" {
  662. params["StackPolicyDuringUpdateURL"] = options.StackPolicyDuringUpdateURL
  663. }
  664. if options.StackPolicyURL != "" {
  665. params["StackPolicyURL"] = options.StackPolicyURL
  666. }
  667. if options.TemplateBody != "" {
  668. params["TemplateBody"] = options.TemplateBody
  669. }
  670. if options.TemplateURL != "" {
  671. params["TemplateURL"] = options.TemplateURL
  672. }
  673. if options.UsePreviousTemplate {
  674. params["UsePreviousTemplate"] = strconv.FormatBool(options.UsePreviousTemplate)
  675. }
  676. if len(options.Capabilities) > 0 {
  677. addParamsList(params, "Capabilities.member", options.Capabilities)
  678. }
  679. if len(options.NotificationARNs) > 0 {
  680. addParamsList(params, "NotificationARNs.member", options.NotificationARNs)
  681. }
  682. // Add any parameters
  683. for i, t := range options.Parameters {
  684. key := "Parameters.member.%d.%s"
  685. index := i + 1
  686. params[fmt.Sprintf(key, index, "ParameterKey")] = t.ParameterKey
  687. params[fmt.Sprintf(key, index, "ParameterValue")] = t.ParameterValue
  688. params[fmt.Sprintf(key, index, "UsePreviousValue")] = strconv.FormatBool(t.UsePreviousValue)
  689. }
  690. resp = new(UpdateStackResponse)
  691. if err := c.query(params, resp); err != nil {
  692. return nil, err
  693. }
  694. return resp, nil
  695. }
  696. // TemplateParameter encapsulates the AWS TemplateParameter data type
  697. //
  698. // See http://goo.gl/OBhNzk for more information
  699. type TemplateParameter struct {
  700. DefaultValue string `xml:"DefaultValue"`
  701. Description string `xml:Description"`
  702. NoEcho bool `xml:NoEcho"`
  703. ParameterKey string `xml:ParameterKey"`
  704. }
  705. // ValidateTemplateResponse wraps the ValidateTemplate call response
  706. //
  707. // See http://goo.gl/OBhNzk for more information
  708. type ValidateTemplateResponse struct {
  709. Capabilities []string `xml:"ValidateTemplateResult>Capabilities>member"`
  710. CapabilitiesReason string `xml:"ValidateTemplateResult>CapabilitiesReason"`
  711. Description string `xml:"ValidateTemplateResult>Description"`
  712. Parameters []TemplateParameter `xml:"ValidateTemplateResult>Parameters>member"`
  713. RequestId string `xml:"ResponseMetadata>RequestId"`
  714. }
  715. // ValidateTemplate validates a specified template.
  716. //
  717. // See http://goo.gl/OBhNzk for more information
  718. func (c *CloudFormation) ValidateTemplate(templateBody, templateUrl string) (
  719. resp *ValidateTemplateResponse, err error) {
  720. params := makeParams("ValidateTemplate")
  721. if templateBody != "" {
  722. params["TemplateBody"] = templateBody
  723. }
  724. if templateUrl != "" {
  725. params["TemplateURL"] = templateUrl
  726. }
  727. resp = new(ValidateTemplateResponse)
  728. if err := c.query(params, resp); err != nil {
  729. return nil, err
  730. }
  731. return resp, nil
  732. }