blob: 86989186fa1a062e20f5efa905411e1847ede82f [file] [log] [blame]
Pratik Mallya5fddb2a2015-09-14 14:04:49 -05001package stacks
2
Jon Perrittfea90732016-03-15 02:57:05 -05003import "strings"
Pratik Mallya5fddb2a2015-09-14 14:04:49 -05004
Pratik Mallya3de347f2015-09-22 12:25:59 -05005// Environment is a structure that represents stack environments
Pratik Mallya5fddb2a2015-09-14 14:04:49 -05006type Environment struct {
7 TE
8}
9
Pratik Mallya3de347f2015-09-22 12:25:59 -050010// EnvironmentSections is a map containing allowed sections in a stack environment file
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050011var EnvironmentSections = map[string]bool{
12 "parameters": true,
13 "parameter_defaults": true,
14 "resource_registry": true,
15}
16
Pratik Mallya3de347f2015-09-22 12:25:59 -050017// Validate validates the contents of the Environment
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050018func (e *Environment) Validate() error {
19 if e.Parsed == nil {
20 if err := e.Parse(); err != nil {
21 return err
22 }
23 }
Pratik Mallya3de347f2015-09-22 12:25:59 -050024 for key := range e.Parsed {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050025 if _, ok := EnvironmentSections[key]; !ok {
Jon Perrittfea90732016-03-15 02:57:05 -050026 return ErrInvalidEnvironment{Section: key}
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050027 }
28 }
29 return nil
30}
31
Pratik Mallyabfc6eda2015-09-21 15:01:18 -050032// Parse environment file to resolve the URL's of the resources. This is done by
33// reading from the `Resource Registry` section, which is why the function is
34// named GetRRFileContents.
Pratik Mallyaa979f5b2015-09-22 03:10:55 -050035func (e *Environment) getRRFileContents(ignoreIf igFunc) error {
Pratik Mallyabfc6eda2015-09-21 15:01:18 -050036 // initialize environment if empty
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050037 if e.Files == nil {
38 e.Files = make(map[string]string)
39 }
40 if e.fileMaps == nil {
41 e.fileMaps = make(map[string]string)
42 }
Pratik Mallyabfc6eda2015-09-21 15:01:18 -050043
44 // get the resource registry
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050045 rr := e.Parsed["resource_registry"]
Pratik Mallyabfc6eda2015-09-21 15:01:18 -050046
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050047 // search the resource registry for URLs
48 switch rr.(type) {
Pratik Mallyabfc6eda2015-09-21 15:01:18 -050049 // process further only if the resource registry is a map
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050050 case map[string]interface{}, map[interface{}]interface{}:
Pratik Mallya3de347f2015-09-22 12:25:59 -050051 rrMap, err := toStringKeys(rr)
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050052 if err != nil {
53 return err
54 }
Pratik Mallyabfc6eda2015-09-21 15:01:18 -050055 // the resource registry might contain a base URL for the resource. If
56 // such a field is present, use it. Otherwise, use the default base URL.
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050057 var baseURL string
Pratik Mallya3de347f2015-09-22 12:25:59 -050058 if val, ok := rrMap["base_url"]; ok {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050059 baseURL = val.(string)
60 } else {
61 baseURL = e.baseURL
62 }
Pratik Mallyabfc6eda2015-09-21 15:01:18 -050063
64 // The contents of the resource may be located in a remote file, which
65 // will be a template. Instantiate a temporary template to manage the
66 // contents.
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050067 tempTemplate := new(Template)
68 tempTemplate.baseURL = baseURL
69 tempTemplate.client = e.client
70
Pratik Mallyae3086ae2015-09-21 15:25:16 -050071 // Fetch the contents of remote resource URL's
Pratik Mallyaa979f5b2015-09-22 03:10:55 -050072 if err = tempTemplate.getFileContents(rr, ignoreIf, false); err != nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050073 return err
74 }
Pratik Mallyae3086ae2015-09-21 15:25:16 -050075 // check the `resources` section (if it exists) for more URL's. Note that
76 // the previous call to GetFileContents was (deliberately) not recursive
77 // as we want more control over where to look for URL's
Pratik Mallya3de347f2015-09-22 12:25:59 -050078 if val, ok := rrMap["resources"]; ok {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050079 switch val.(type) {
Pratik Mallyabfc6eda2015-09-21 15:01:18 -050080 // process further only if the contents are a map
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050081 case map[string]interface{}, map[interface{}]interface{}:
Pratik Mallya3de347f2015-09-22 12:25:59 -050082 resourcesMap, err := toStringKeys(val)
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050083 if err != nil {
84 return err
85 }
Pratik Mallya3de347f2015-09-22 12:25:59 -050086 for _, v := range resourcesMap {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050087 switch v.(type) {
88 case map[string]interface{}, map[interface{}]interface{}:
Pratik Mallya3de347f2015-09-22 12:25:59 -050089 resourceMap, err := toStringKeys(v)
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050090 if err != nil {
91 return err
92 }
93 var resourceBaseURL string
94 // if base_url for the resource type is defined, use it
Pratik Mallya3de347f2015-09-22 12:25:59 -050095 if val, ok := resourceMap["base_url"]; ok {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -050096 resourceBaseURL = val.(string)
97 } else {
98 resourceBaseURL = baseURL
99 }
100 tempTemplate.baseURL = resourceBaseURL
Pratik Mallyaa979f5b2015-09-22 03:10:55 -0500101 if err := tempTemplate.getFileContents(v, ignoreIf, false); err != nil {
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500102 return err
103 }
104 }
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500105 }
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500106 }
107 }
Pratik Mallyabfc6eda2015-09-21 15:01:18 -0500108 // if the resource registry contained any URL's, store them. This can
109 // then be passed as parameter to api calls to Heat api.
Pratik Mallya5fddb2a2015-09-14 14:04:49 -0500110 e.Files = tempTemplate.Files
111 return nil
112 default:
113 return nil
114 }
115}
116
117// function to choose keys whose values are other environment files
118func ignoreIfEnvironment(key string, value interface{}) bool {
119 // base_url and hooks refer to components which cannot have urls
120 if key == "base_url" || key == "hooks" {
121 return true
122 }
123 // if value is not string, it cannot be a URL
124 valueString, ok := value.(string)
125 if !ok {
126 return true
127 }
128 // if value contains `::`, it must be a reference to another resource type
129 // e.g. OS::Nova::Server : Rackspace::Cloud::Server
130 if strings.Contains(valueString, "::") {
131 return true
132 }
133 return false
134}