blob: abaff205729f49f580bb4ad46e0a91636163d80f [file] [log] [blame]
Pratik Mallya5fddb2a2015-09-14 14:04:49 -05001package stacks
2
3import (
Pratik Mallya5fddb2a2015-09-14 14:04:49 -05004 "fmt"
5 "strings"
6)
7
Pratik Mallya3de347f2015-09-22 12:25:59 -05008// Environment is a structure that represents stack environments
Pratik Mallya5fddb2a2015-09-14 14:04:49 -05009type Environment struct {
10 TE
11}
12
Pratik Mallya3de347f2015-09-22 12:25:59 -050013// EnvironmentSections is a map containing allowed sections in a stack environment file
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050014var EnvironmentSections = map[string]bool{
15 "parameters": true,
16 "parameter_defaults": true,
17 "resource_registry": true,
18}
19
Pratik Mallya3de347f2015-09-22 12:25:59 -050020// Validate validates the contents of the Environment
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050021func (e *Environment) Validate() error {
22 if e.Parsed == nil {
23 if err := e.Parse(); err != nil {
24 return err
25 }
26 }
Pratik Mallya3de347f2015-09-22 12:25:59 -050027 for key := range e.Parsed {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050028 if _, ok := EnvironmentSections[key]; !ok {
Pratik Mallya3de347f2015-09-22 12:25:59 -050029 return fmt.Errorf("Environment has wrong section: %s", key)
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050030 }
31 }
32 return nil
33}
34
Pratik Mallyabfc6eda2015-09-21 15:01:18 -050035// Parse environment file to resolve the URL's of the resources. This is done by
36// reading from the `Resource Registry` section, which is why the function is
37// named GetRRFileContents.
Pratik Mallyaa979f5b2015-09-22 03:10:55 -050038func (e *Environment) getRRFileContents(ignoreIf igFunc) error {
Pratik Mallyabfc6eda2015-09-21 15:01:18 -050039 // initialize environment if empty
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050040 if e.Files == nil {
41 e.Files = make(map[string]string)
42 }
43 if e.fileMaps == nil {
44 e.fileMaps = make(map[string]string)
45 }
Pratik Mallyabfc6eda2015-09-21 15:01:18 -050046
47 // get the resource registry
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050048 rr := e.Parsed["resource_registry"]
Pratik Mallyabfc6eda2015-09-21 15:01:18 -050049
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050050 // search the resource registry for URLs
51 switch rr.(type) {
Pratik Mallyabfc6eda2015-09-21 15:01:18 -050052 // process further only if the resource registry is a map
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050053 case map[string]interface{}, map[interface{}]interface{}:
Pratik Mallya3de347f2015-09-22 12:25:59 -050054 rrMap, err := toStringKeys(rr)
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050055 if err != nil {
56 return err
57 }
Pratik Mallyabfc6eda2015-09-21 15:01:18 -050058 // the resource registry might contain a base URL for the resource. If
59 // such a field is present, use it. Otherwise, use the default base URL.
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050060 var baseURL string
Pratik Mallya3de347f2015-09-22 12:25:59 -050061 if val, ok := rrMap["base_url"]; ok {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050062 baseURL = val.(string)
63 } else {
64 baseURL = e.baseURL
65 }
Pratik Mallyabfc6eda2015-09-21 15:01:18 -050066
67 // The contents of the resource may be located in a remote file, which
68 // will be a template. Instantiate a temporary template to manage the
69 // contents.
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050070 tempTemplate := new(Template)
71 tempTemplate.baseURL = baseURL
72 tempTemplate.client = e.client
73
Pratik Mallyae3086ae2015-09-21 15:25:16 -050074 // Fetch the contents of remote resource URL's
Pratik Mallyaa979f5b2015-09-22 03:10:55 -050075 if err = tempTemplate.getFileContents(rr, ignoreIf, false); err != nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050076 return err
77 }
Pratik Mallyae3086ae2015-09-21 15:25:16 -050078 // check the `resources` section (if it exists) for more URL's. Note that
79 // the previous call to GetFileContents was (deliberately) not recursive
80 // as we want more control over where to look for URL's
Pratik Mallya3de347f2015-09-22 12:25:59 -050081 if val, ok := rrMap["resources"]; ok {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050082 switch val.(type) {
Pratik Mallyabfc6eda2015-09-21 15:01:18 -050083 // process further only if the contents are a map
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050084 case map[string]interface{}, map[interface{}]interface{}:
Pratik Mallya3de347f2015-09-22 12:25:59 -050085 resourcesMap, err := toStringKeys(val)
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050086 if err != nil {
87 return err
88 }
Pratik Mallya3de347f2015-09-22 12:25:59 -050089 for _, v := range resourcesMap {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050090 switch v.(type) {
91 case map[string]interface{}, map[interface{}]interface{}:
Pratik Mallya3de347f2015-09-22 12:25:59 -050092 resourceMap, err := toStringKeys(v)
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050093 if err != nil {
94 return err
95 }
96 var resourceBaseURL string
97 // if base_url for the resource type is defined, use it
Pratik Mallya3de347f2015-09-22 12:25:59 -050098 if val, ok := resourceMap["base_url"]; ok {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050099 resourceBaseURL = val.(string)
100 } else {
101 resourceBaseURL = baseURL
102 }
103 tempTemplate.baseURL = resourceBaseURL
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500104 if err := tempTemplate.getFileContents(v, ignoreIf, false); err != nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500105 return err
106 }
107 }
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500108 }
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500109 }
110 }
Pratik Mallyabfc6eda2015-09-21 15:01:18 -0500111 // if the resource registry contained any URL's, store them. This can
112 // then be passed as parameter to api calls to Heat api.
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500113 e.Files = tempTemplate.Files
114 return nil
115 default:
116 return nil
117 }
118}
119
120// function to choose keys whose values are other environment files
121func ignoreIfEnvironment(key string, value interface{}) bool {
122 // base_url and hooks refer to components which cannot have urls
123 if key == "base_url" || key == "hooks" {
124 return true
125 }
126 // if value is not string, it cannot be a URL
127 valueString, ok := value.(string)
128 if !ok {
129 return true
130 }
131 // if value contains `::`, it must be a reference to another resource type
132 // e.g. OS::Nova::Server : Rackspace::Cloud::Server
133 if strings.Contains(valueString, "::") {
134 return true
135 }
136 return false
137}