func TestNormalizePathURL(t *testing.T) { baseDir, _ := os.Getwd() rawPath := "template.yaml" basePath, _ := filepath.Abs(".") result, _ := gophercloud.NormalizePathURL(basePath, rawPath) expected := strings.Join([]string{"file:/", filepath.ToSlash(baseDir), "template.yaml"}, "/") th.CheckEquals(t, expected, result) rawPath = "http://www.google.com" basePath, _ = filepath.Abs(".") result, _ = gophercloud.NormalizePathURL(basePath, rawPath) expected = "http://www.google.com" th.CheckEquals(t, expected, result) rawPath = "very/nested/file.yaml" basePath, _ = filepath.Abs(".") result, _ = gophercloud.NormalizePathURL(basePath, rawPath) expected = strings.Join([]string{"file:/", filepath.ToSlash(baseDir), "very/nested/file.yaml"}, "/") th.CheckEquals(t, expected, result) rawPath = "very/nested/file.yaml" basePath = "http://www.google.com" result, _ = gophercloud.NormalizePathURL(basePath, rawPath) expected = "http://www.google.com/very/nested/file.yaml" th.CheckEquals(t, expected, result) rawPath = "very/nested/file.yaml/" basePath = "http://www.google.com/" result, _ = gophercloud.NormalizePathURL(basePath, rawPath) expected = "http://www.google.com/very/nested/file.yaml" th.CheckEquals(t, expected, result) rawPath = "very/nested/file.yaml" basePath = "http://www.google.com/even/more" result, _ = gophercloud.NormalizePathURL(basePath, rawPath) expected = "http://www.google.com/even/more/very/nested/file.yaml" th.CheckEquals(t, expected, result) rawPath = "very/nested/file.yaml" basePath = strings.Join([]string{"file:/", filepath.ToSlash(baseDir), "only/file/even/more"}, "/") result, _ = gophercloud.NormalizePathURL(basePath, rawPath) expected = strings.Join([]string{"file:/", filepath.ToSlash(baseDir), "only/file/even/more/very/nested/file.yaml"}, "/") th.CheckEquals(t, expected, result) rawPath = "very/nested/file.yaml/" basePath = strings.Join([]string{"file:/", filepath.ToSlash(baseDir), "only/file/even/more"}, "/") result, _ = gophercloud.NormalizePathURL(basePath, rawPath) expected = strings.Join([]string{"file:/", filepath.ToSlash(baseDir), "only/file/even/more/very/nested/file.yaml"}, "/") th.CheckEquals(t, expected, result) }
// get the basepath of the TE func getBasePath() (string, error) { basePath, err := filepath.Abs(".") if err != nil { return "", err } u, err := gophercloud.NormalizePathURL("", basePath) if err != nil { return "", err } return u, nil }
// Fetch fetches the contents of a TE from its URL. Once a TE structure has a // URL, call the fetch method to fetch the contents. func (t *TE) Fetch() error { // if the baseURL is not provided, use the current directors as the base URL if t.baseURL == "" { u, err := getBasePath() if err != nil { return err } t.baseURL = u } // if the contents are already present, do nothing. if t.Bin != nil { return nil } // get a fqdn from the URL using the baseURL of the TE. For local files, // the URL's will have the `file` scheme. u, err := gophercloud.NormalizePathURL(t.baseURL, t.URL) if err != nil { return err } t.URL = u // get an HTTP client if none present if t.client == nil { t.client = getHTTPClient() } // use the client to fetch the contents of the TE resp, err := t.client.Get(t.URL) if err != nil { return err } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { return err } t.Bin = body return nil }
// GetFileContents recursively parses a template to search for urls. These urls // are assumed to point to other templates (known in OpenStack Heat as child // templates). The contents of these urls are fetched and stored in the `Files` // parameter of the template structure. This is the only way that a user can // use child templates that are located in their filesystem; urls located on the // web (e.g. on github or swift) can be fetched directly by Heat engine. func (t *Template) getFileContents(te interface{}, ignoreIf igFunc, recurse bool) error { // initialize template if empty if t.Files == nil { t.Files = make(map[string]string) } if t.fileMaps == nil { t.fileMaps = make(map[string]string) } switch te.(type) { // if te is a map case map[string]interface{}, map[interface{}]interface{}: teMap, err := toStringKeys(te) if err != nil { return err } for k, v := range teMap { value, ok := v.(string) if !ok { // if the value is not a string, recursively parse that value if err := t.getFileContents(v, ignoreIf, recurse); err != nil { return err } } else if !ignoreIf(k, value) { // at this point, the k, v pair has a reference to an external template. // The assumption of heatclient is that value v is a reference // to a file in the users environment // create a new child template childTemplate := new(Template) // initialize child template // get the base location of the child template baseURL, err := gophercloud.NormalizePathURL(t.baseURL, value) if err != nil { return err } childTemplate.baseURL = baseURL childTemplate.client = t.client // fetch the contents of the child template if err := childTemplate.Parse(); err != nil { return err } // process child template recursively if required. This is // required if the child template itself contains references to // other templates if recurse { if err := childTemplate.getFileContents(childTemplate.Parsed, ignoreIf, recurse); err != nil { return err } } // update parent template with current child templates' content. // At this point, the child template has been parsed recursively. t.fileMaps[value] = childTemplate.URL t.Files[childTemplate.URL] = string(childTemplate.Bin) } } return nil // if te is a slice, call the function on each element of the slice. case []interface{}: teSlice := te.([]interface{}) for i := range teSlice { if err := t.getFileContents(teSlice[i], ignoreIf, recurse); err != nil { return err } } // if te is anything else, return case string, bool, float64, nil, int: return nil default: return gophercloud.ErrUnexpectedType{Actual: fmt.Sprintf("%v", reflect.TypeOf(te))} } return nil }