github.com/vnpaycloud-console/gophercloud/v2@v2.0.5/openstack/orchestration/v1/stacks/environment.go (about) 1 package stacks 2 3 import ( 4 "fmt" 5 "strings" 6 7 yaml "gopkg.in/yaml.v2" 8 ) 9 10 // Environment is a structure that represents stack environments 11 type Environment struct { 12 TE 13 } 14 15 // EnvironmentSections is a map containing allowed sections in a stack environment file 16 var EnvironmentSections = map[string]bool{ 17 "parameters": true, 18 "parameter_defaults": true, 19 "resource_registry": true, 20 } 21 22 // Validate validates the contents of the Environment 23 func (e *Environment) Validate() error { 24 if e.Parsed == nil { 25 if err := e.Parse(); err != nil { 26 return err 27 } 28 } 29 for key := range e.Parsed { 30 if _, ok := EnvironmentSections[key]; !ok { 31 return ErrInvalidEnvironment{Section: key} 32 } 33 } 34 return nil 35 } 36 37 // Parse environment file to resolve the URL's of the resources. This is done by 38 // reading from the `Resource Registry` section, which is why the function is 39 // named GetRRFileContents. 40 func (e *Environment) getRRFileContents(ignoreIf igFunc) error { 41 // initialize environment if empty 42 if e.Files == nil { 43 e.Files = make(map[string]string) 44 } 45 if e.fileMaps == nil { 46 e.fileMaps = make(map[string]string) 47 } 48 49 // get the resource registry 50 rr := e.Parsed["resource_registry"] 51 52 // search the resource registry for URLs 53 switch rr.(type) { 54 // process further only if the resource registry is a map 55 case map[string]any, map[any]any: 56 rrMap, err := toStringKeys(rr) 57 if err != nil { 58 return err 59 } 60 // the resource registry might contain a base URL for the resource. If 61 // such a field is present, use it. Otherwise, use the default base URL. 62 var baseURL string 63 if val, ok := rrMap["base_url"]; ok { 64 baseURL = val.(string) 65 } else { 66 baseURL = e.baseURL 67 } 68 69 // The contents of the resource may be located in a remote file, which 70 // will be a template. Instantiate a temporary template to manage the 71 // contents. 72 tempTemplate := new(Template) 73 tempTemplate.baseURL = baseURL 74 tempTemplate.client = e.client 75 76 // Fetch the contents of remote resource URL's 77 if err = tempTemplate.getFileContents(rr, ignoreIf, false); err != nil { 78 return err 79 } 80 // check the `resources` section (if it exists) for more URL's. Note that 81 // the previous call to GetFileContents was (deliberately) not recursive 82 // as we want more control over where to look for URL's 83 if val, ok := rrMap["resources"]; ok { 84 switch val.(type) { 85 // process further only if the contents are a map 86 case map[string]any, map[any]any: 87 resourcesMap, err := toStringKeys(val) 88 if err != nil { 89 return err 90 } 91 for _, v := range resourcesMap { 92 switch v.(type) { 93 case map[string]any, map[any]any: 94 resourceMap, err := toStringKeys(v) 95 if err != nil { 96 return err 97 } 98 var resourceBaseURL string 99 // if base_url for the resource type is defined, use it 100 if val, ok := resourceMap["base_url"]; ok { 101 resourceBaseURL = val.(string) 102 } else { 103 resourceBaseURL = baseURL 104 } 105 tempTemplate.baseURL = resourceBaseURL 106 if err := tempTemplate.getFileContents(v, ignoreIf, false); err != nil { 107 return err 108 } 109 } 110 } 111 } 112 } 113 // if the resource registry contained any URL's, store them. This can 114 // then be passed as parameter to api calls to Heat api. 115 e.Files = tempTemplate.Files 116 117 // In case some element was updated, regenerate the string representation 118 if len(e.Files) > 0 { 119 var err error 120 e.Bin, err = yaml.Marshal(&e.Parsed) 121 if err != nil { 122 return fmt.Errorf("failed to marshal updated environment: %w", err) 123 } 124 } 125 126 return nil 127 default: 128 return nil 129 } 130 } 131 132 // function to choose keys whose values are other environment files 133 func ignoreIfEnvironment(key string, value any) bool { 134 // base_url and hooks refer to components which cannot have urls 135 if key == "base_url" || key == "hooks" { 136 return true 137 } 138 // if value is not string, it cannot be a URL 139 valueString, ok := value.(string) 140 if !ok { 141 return true 142 } 143 // if value contains `::`, it must be a reference to another resource type 144 // e.g. OS::Nova::Server : Rackspace::Cloud::Server 145 if strings.Contains(valueString, "::") { 146 return true 147 } 148 return false 149 }