| package stacks |
| |
| import ( |
| "errors" |
| |
| "github.com/racker/perigee" |
| "github.com/rackspace/gophercloud" |
| "github.com/rackspace/gophercloud/pagination" |
| ) |
| |
| type Rollback *bool |
| |
| var ( |
| disable = true |
| Disable Rollback = &disable |
| enable = false |
| Enable Rollback = &enable |
| ) |
| |
| // CreateOptsBuilder is the interface options structs have to satisfy in order |
| // to be used in the main Create operation in this package. Since many |
| // extensions decorate or modify the common logic, it is useful for them to |
| // satisfy a basic interface in order for them to be used. |
| type CreateOptsBuilder interface { |
| ToStackCreateMap() (map[string]interface{}, error) |
| } |
| |
| // CreateOpts is the common options struct used in this package's Create |
| // operation. |
| type CreateOpts struct { |
| // (REQUIRED) The name of the stack. It must start with an alphabetic character. |
| Name string |
| // (REQUIRED) The timeout for stack creation in minutes. |
| Timeout int |
| // (OPTIONAL; REQUIRED IF Template IS EMPTY) The URL of the template to instantiate. |
| // This value is ignored if Template is supplied inline. |
| TemplateURL string |
| // (OPTIONAL; REQUIRED IF TemplateURL IS EMPTY) A template to instantiate. The value |
| // is a stringified version of the JSON/YAML template. Since the template will likely |
| // be located in a file, one way to set this variable is by using ioutil.ReadFile: |
| // import "io/ioutil" |
| // var opts stacks.CreateOpts |
| // b, err := ioutil.ReadFile("path/to/you/template/file.json") |
| // if err != nil { |
| // // handle error... |
| // } |
| // opts.Template = string(b) |
| Template string |
| // (OPTIONAL) Enables or disables deletion of all stack resources when a stack |
| // creation fails. Default is true, meaning all resources are not deleted when |
| // stack creation fails. |
| DisableRollback *bool |
| // (OPTIONAL) A stringified JSON environment for the stack. |
| Environment string |
| // (OPTIONAL) A map that maps file names to file contents. It can also be used |
| // to pass provider template contents. Example: |
| // Files: `{"myfile": "#!/bin/bash\necho 'Hello world' > /root/testfile.txt"}` |
| Files map[string]interface{} |
| // (OPTIONAL) User-defined parameters to pass to the template. |
| Parameters map[string]string |
| } |
| |
| // ToStackCreateMap casts a CreateOpts struct to a map. |
| func (opts CreateOpts) ToStackCreateMap() (map[string]interface{}, error) { |
| s := make(map[string]interface{}) |
| |
| if opts.Name == "" { |
| return s, errors.New("Required field 'Name' not provided.") |
| } |
| s["stack_name"] = opts.Name |
| |
| if opts.Template != "" { |
| s["template"] = opts.Template |
| } else if opts.TemplateURL != "" { |
| s["template_url"] = opts.TemplateURL |
| } else { |
| return s, errors.New("Either Template or TemplateURL must be provided.") |
| } |
| |
| if opts.DisableRollback != nil { |
| s["disable_rollback"] = &opts.DisableRollback |
| } |
| |
| if opts.Environment != "" { |
| s["environment"] = opts.Environment |
| } |
| if opts.Files != nil { |
| s["files"] = opts.Files |
| } |
| if opts.Parameters != nil { |
| s["parameters"] = opts.Parameters |
| } |
| |
| if opts.Timeout == 0 { |
| return nil, errors.New("Required field 'Timeout' not provided.") |
| } |
| s["timeout_mins"] = opts.Timeout |
| |
| return s, nil |
| } |
| |
| // Create accepts a CreateOpts struct and creates a new stack using the values |
| // provided. |
| func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) CreateResult { |
| var res CreateResult |
| |
| reqBody, err := opts.ToStackCreateMap() |
| if err != nil { |
| res.Err = err |
| return res |
| } |
| |
| // Send request to API |
| _, res.Err = perigee.Request("POST", createURL(c), perigee.Options{ |
| MoreHeaders: c.AuthenticatedHeaders(), |
| ReqBody: &reqBody, |
| Results: &res.Body, |
| OkCodes: []int{201}, |
| }) |
| return res |
| } |
| |
| // AdoptOptsBuilder is the interface options structs have to satisfy in order |
| // to be used in the Adopt function in this package. Since many |
| // extensions decorate or modify the common logic, it is useful for them to |
| // satisfy a basic interface in order for them to be used. |
| type AdoptOptsBuilder interface { |
| ToStackAdoptMap() (map[string]interface{}, error) |
| } |
| |
| // AdoptOpts is the common options struct used in this package's Adopt |
| // operation. |
| type AdoptOpts struct { |
| // (REQUIRED) Existing resources data represented as a string to add to the |
| // new stack. Data returned by Abandon could be provided as AdoptsStackData. |
| AdoptStackData string |
| // (REQUIRED) The name of the stack. It must start with an alphabetic character. |
| Name string |
| // (REQUIRED) The timeout for stack creation in minutes. |
| Timeout int |
| // (OPTIONAL; REQUIRED IF Template IS EMPTY) The URL of the template to instantiate. |
| // This value is ignored if Template is supplied inline. |
| TemplateURL string |
| // (OPTIONAL; REQUIRED IF TemplateURL IS EMPTY) A template to instantiate. The value |
| // is a stringified version of the JSON/YAML template. Since the template will likely |
| // be located in a file, one way to set this variable is by using ioutil.ReadFile: |
| // import "io/ioutil" |
| // var opts stacks.CreateOpts |
| // b, err := ioutil.ReadFile("path/to/you/template/file.json") |
| // if err != nil { |
| // // handle error... |
| // } |
| // opts.Template = string(b) |
| Template string |
| // (OPTIONAL) Enables or disables deletion of all stack resources when a stack |
| // creation fails. Default is true, meaning all resources are not deleted when |
| // stack creation fails. |
| DisableRollback *bool |
| // (OPTIONAL) A stringified JSON environment for the stack. |
| Environment string |
| // (OPTIONAL) A map that maps file names to file contents. It can also be used |
| // to pass provider template contents. Example: |
| // Files: `{"myfile": "#!/bin/bash\necho 'Hello world' > /root/testfile.txt"}` |
| Files map[string]interface{} |
| // (OPTIONAL) User-defined parameters to pass to the template. |
| Parameters map[string]string |
| } |
| |
| // ToStackAdoptMap casts a CreateOpts struct to a map. |
| func (opts AdoptOpts) ToStackAdoptMap() (map[string]interface{}, error) { |
| s := make(map[string]interface{}) |
| |
| if opts.Name == "" { |
| return s, errors.New("Required field 'Name' not provided.") |
| } |
| s["stack_name"] = opts.Name |
| |
| if opts.Template != "" { |
| s["template"] = opts.Template |
| } else if opts.TemplateURL != "" { |
| s["template_url"] = opts.TemplateURL |
| } else { |
| return s, errors.New("Either Template or TemplateURL must be provided.") |
| } |
| |
| if opts.AdoptStackData == "" { |
| return s, errors.New("Required field 'AdoptStackData' not provided.") |
| } |
| s["adopt_stack_data"] = opts.AdoptStackData |
| |
| if opts.DisableRollback != nil { |
| s["disable_rollback"] = &opts.DisableRollback |
| } |
| |
| if opts.Environment != "" { |
| s["environment"] = opts.Environment |
| } |
| if opts.Files != nil { |
| s["files"] = opts.Files |
| } |
| if opts.Parameters != nil { |
| s["parameters"] = opts.Parameters |
| } |
| |
| if opts.Timeout == 0 { |
| return nil, errors.New("Required field 'Timeout' not provided.") |
| } |
| s["timeout_mins"] = opts.Timeout |
| |
| return map[string]interface{}{"stack": s}, nil |
| } |
| |
| // Adopt accepts an AdoptOpts struct and creates a new stack using the resources |
| // from another stack. |
| func Adopt(c *gophercloud.ServiceClient, opts AdoptOptsBuilder) AdoptResult { |
| var res AdoptResult |
| |
| reqBody, err := opts.ToStackAdoptMap() |
| if err != nil { |
| res.Err = err |
| return res |
| } |
| |
| // Send request to API |
| _, res.Err = perigee.Request("POST", adoptURL(c), perigee.Options{ |
| MoreHeaders: c.AuthenticatedHeaders(), |
| ReqBody: &reqBody, |
| Results: &res.Body, |
| OkCodes: []int{201}, |
| }) |
| return res |
| } |
| |
| // SortDir is a type for specifying in which direction to sort a list of stacks. |
| type SortDir string |
| |
| // SortKey is a type for specifying by which key to sort a list of stacks. |
| type SortKey string |
| |
| var ( |
| // SortAsc is used to sort a list of stacks in ascending order. |
| SortAsc SortDir = "asc" |
| // SortDesc is used to sort a list of stacks in descending order. |
| SortDesc SortDir = "desc" |
| // SortName is used to sort a list of stacks by name. |
| SortName SortKey = "name" |
| // SortStatus is used to sort a list of stacks by status. |
| SortStatus SortKey = "status" |
| // SortCreatedAt is used to sort a list of stacks by date created. |
| SortCreatedAt SortKey = "created_at" |
| // SortUpdatedAt is used to sort a list of stacks by date updated. |
| SortUpdatedAt SortKey = "updated_at" |
| ) |
| |
| // ListOptsBuilder allows extensions to add additional parameters to the |
| // List request. |
| type ListOptsBuilder interface { |
| ToStackListQuery() (string, error) |
| } |
| |
| // ListOpts allows the filtering and sorting of paginated collections through |
| // the API. Filtering is achieved by passing in struct field values that map to |
| // the network attributes you want to see returned. SortKey allows you to sort |
| // by a particular network attribute. SortDir sets the direction, and is either |
| // `asc' or `desc'. Marker and Limit are used for pagination. |
| type ListOpts struct { |
| Status string `q:"status"` |
| Name string `q:"name"` |
| Marker string `q:"marker"` |
| Limit int `q:"limit"` |
| SortKey SortKey `q:"sort_keys"` |
| SortDir SortDir `q:"sort_dir"` |
| } |
| |
| // ToStackListQuery formats a ListOpts into a query string. |
| func (opts ListOpts) ToStackListQuery() (string, error) { |
| q, err := gophercloud.BuildQueryString(opts) |
| if err != nil { |
| return "", err |
| } |
| return q.String(), nil |
| } |
| |
| // List returns a Pager which allows you to iterate over a collection of |
| // stacks. It accepts a ListOpts struct, which allows you to filter and sort |
| // the returned collection for greater efficiency. |
| func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager { |
| url := listURL(c) |
| if opts != nil { |
| query, err := opts.ToStackListQuery() |
| if err != nil { |
| return pagination.Pager{Err: err} |
| } |
| url += query |
| } |
| |
| createPage := func(r pagination.PageResult) pagination.Page { |
| return StackPage{pagination.SinglePageBase(r)} |
| } |
| return pagination.NewPager(c, url, createPage) |
| } |
| |
| // Get retreives a stack based on the stack name and stack ID. |
| func Get(c *gophercloud.ServiceClient, stackName, stackID string) GetResult { |
| var res GetResult |
| |
| // Send request to API |
| _, res.Err = perigee.Request("GET", getURL(c, stackName, stackID), perigee.Options{ |
| MoreHeaders: c.AuthenticatedHeaders(), |
| Results: &res.Body, |
| OkCodes: []int{200}, |
| }) |
| return res |
| } |
| |
| // UpdateOptsBuilder is the interface options structs have to satisfy in order |
| // to be used in the Update operation in this package. |
| type UpdateOptsBuilder interface { |
| ToStackUpdateMap() (map[string]interface{}, error) |
| } |
| |
| // UpdateOpts contains the common options struct used in this package's Update |
| // operation. |
| type UpdateOpts struct { |
| Environment string |
| Files map[string]interface{} |
| Parameters map[string]string |
| Template string |
| TemplateURL string |
| Timeout int |
| } |
| |
| // ToStackUpdateMap casts a CreateOpts struct to a map. |
| func (opts UpdateOpts) ToStackUpdateMap() (map[string]interface{}, error) { |
| s := make(map[string]interface{}) |
| |
| if opts.Template != "" { |
| s["template"] = opts.Template |
| } else if opts.TemplateURL != "" { |
| s["template_url"] = opts.TemplateURL |
| } else { |
| return s, errors.New("Either Template or TemplateURL must be provided.") |
| } |
| |
| if opts.Environment != "" { |
| s["environment"] = opts.Environment |
| } |
| |
| if opts.Files != nil { |
| s["files"] = opts.Files |
| } |
| |
| if opts.Parameters != nil { |
| s["parameters"] = opts.Parameters |
| } |
| |
| if opts.Timeout != 0 { |
| s["timeout_mins"] = opts.Timeout |
| } |
| |
| return s, nil |
| } |
| |
| // Update accepts an UpdateOpts struct and updates an existing stack using the values |
| // provided. |
| func Update(c *gophercloud.ServiceClient, stackName, stackID string, opts UpdateOptsBuilder) UpdateResult { |
| var res UpdateResult |
| |
| reqBody, err := opts.ToStackUpdateMap() |
| if err != nil { |
| res.Err = err |
| return res |
| } |
| |
| // Send request to API |
| _, res.Err = perigee.Request("PUT", updateURL(c, stackName, stackID), perigee.Options{ |
| MoreHeaders: c.AuthenticatedHeaders(), |
| ReqBody: &reqBody, |
| OkCodes: []int{202}, |
| }) |
| return res |
| } |
| |
| // Delete deletes a stack based on the stack name and stack ID. |
| func Delete(c *gophercloud.ServiceClient, stackName, stackID string) DeleteResult { |
| var res DeleteResult |
| |
| // Send request to API |
| _, res.Err = perigee.Request("DELETE", deleteURL(c, stackName, stackID), perigee.Options{ |
| MoreHeaders: c.AuthenticatedHeaders(), |
| OkCodes: []int{204}, |
| }) |
| return res |
| } |
| |
| // PreviewOptsBuilder is the interface options structs have to satisfy in order |
| // to be used in the Preview operation in this package. |
| type PreviewOptsBuilder interface { |
| ToStackPreviewMap() (map[string]interface{}, error) |
| } |
| |
| // PreviewOpts contains the common options struct used in this package's Preview |
| // operation. |
| type PreviewOpts struct { |
| DisableRollback *bool |
| Environment string |
| Files map[string]interface{} |
| Name string |
| Parameters map[string]string |
| Template string |
| TemplateURL string |
| Timeout int |
| } |
| |
| // ToStackPreviewMap casts a PreviewOpts struct to a map. |
| func (opts PreviewOpts) ToStackPreviewMap() (map[string]interface{}, error) { |
| s := make(map[string]interface{}) |
| |
| if opts.Name == "" { |
| return s, errors.New("Required field 'Name' not provided.") |
| } |
| s["stack_name"] = opts.Name |
| |
| if opts.Template != "" { |
| s["template"] = opts.Template |
| } else if opts.TemplateURL != "" { |
| s["template_url"] = opts.TemplateURL |
| } else { |
| return s, errors.New("Either Template or TemplateURL must be provided.") |
| } |
| |
| if opts.DisableRollback != nil { |
| s["disable_rollback"] = &opts.DisableRollback |
| } |
| |
| if opts.Environment != "" { |
| s["environment"] = opts.Environment |
| } |
| if opts.Files != nil { |
| s["files"] = opts.Files |
| } |
| if opts.Parameters != nil { |
| s["parameters"] = opts.Parameters |
| } |
| |
| if opts.Timeout != 0 { |
| s["timeout_mins"] = opts.Timeout |
| } |
| |
| return s, nil |
| } |
| |
| // Preview accepts a PreviewOptsBuilder interface and creates a preview of a stack using the values |
| // provided. |
| func Preview(c *gophercloud.ServiceClient, opts PreviewOptsBuilder) PreviewResult { |
| var res PreviewResult |
| |
| reqBody, err := opts.ToStackPreviewMap() |
| if err != nil { |
| res.Err = err |
| return res |
| } |
| |
| // Send request to API |
| _, res.Err = perigee.Request("POST", previewURL(c), perigee.Options{ |
| MoreHeaders: c.AuthenticatedHeaders(), |
| ReqBody: &reqBody, |
| Results: &res.Body, |
| OkCodes: []int{200}, |
| }) |
| return res |
| } |
| |
| // Abandon deletes the stack with the provided stackName and stackID, but leaves its |
| // resources intact, and returns data describing the stack and its resources. |
| func Abandon(c *gophercloud.ServiceClient, stackName, stackID string) AbandonResult { |
| var res AbandonResult |
| |
| // Send request to API |
| _, res.Err = perigee.Request("POST", abandonURL(c, stackName, stackID), perigee.Options{ |
| MoreHeaders: c.AuthenticatedHeaders(), |
| Results: &res.Body, |
| OkCodes: []int{200}, |
| }) |
| return res |
| } |