func (suite *TestSuiteSource) TestSourceUsage(c *C) { ctx := ContextPutTimeout(context.Background(), 1*time.Minute) url := "zk://" + strings.Join(Hosts(), ",") zk, err := namespace.Dial(ctx, url) c.Assert(err, IsNil) c.Log(zk) defer zk.Close() root := namespace.NewPathf("/unit-test/zk/%d/source", time.Now().Unix()) value := []byte("test-value-12345") _, err = zk.Put(root, value, false) c.Assert(err, IsNil) read, _, err := zk.Get(root) c.Assert(read, DeepEquals, value) sourced, err := resource.Fetch(ctx, url+root.String()) c.Assert(err, IsNil) c.Assert(sourced, DeepEquals, value) // Test default to what's in the environment variable -- no hosts specified. sourced, err = resource.Fetch(ctx, "zk://"+root.String()) c.Assert(err, IsNil) c.Assert(sourced, DeepEquals, value) // Test default to what's in the environment variable -- no hosts specified. sourced, err = resource.Fetch(ctx, "zk://bogus/node") c.Assert(err, Not(IsNil)) }
// Fetch the url and write content inline // ex) {{ inline "http://file/here" }} func ContentInline(ctx context.Context) interface{} { return func(uri string) (string, error) { data := ContextGetTemplateData(ctx) applied, err := Apply([]byte(uri), data) if err != nil { return NullTemplate, err } url := string(applied) content, err := resource.Fetch(ctx, url) if err != nil { return NullTemplate, err } return string(content), nil } }
// This test here shows how to implement two stages of configuring an object. // First a field in the struct gets the source of the config url from the command line flags. // Second, the config is fetched and unmarshalled to the object. // Finally, we parse again so that additional flag values are overlaid onto the struct. func (suite *TestSuiteCommand) TestCommandReparseFlag(c *C) { Register("person", func() (Module, ErrorHandling) { return new(person), PanicOnError }) // Generate the auth token required by the server. token := auth.NewToken(1*time.Hour).Add("secure", 1) header := http.Header{} token.SetHeader(header, testutil.PrivateKeyFunc) ctx := resource.ContextPutHttpHeader(context.Background(), header) suite.template = ` name: joe age: 21 employee: false not-a-field: hello ` p := &person{ Age: 18, Employee: true, } RunModule("person", p, strings.Split("--config_url=http://localhost:7986/secure --age=35", " "), nil) c.Assert(p.ConfigUrl, Equals, "http://localhost:7986/secure") c.Assert(p.Employee, Equals, true) data, err := resource.Fetch(ctx, p.ConfigUrl) c.Assert(err, IsNil) c.Log(string(data)) err = encoding.Unmarshal(encoding.ContentTypeYAML, bytes.NewBuffer(data), p) c.Assert(err, IsNil) c.Assert(p.Age, Equals, 21) c.Assert(p.Name, Equals, "joe") c.Assert(p.Employee, Equals, true) // we don't expect the yaml to change the field. ReparseFlags(p) c.Assert(p.Age, Equals, 35) // This is overwritten by the flag value c.Assert(p.Name, Equals, "joe") c.Assert(p.Employee, Equals, true) }
// Execute a template at the given uri/url. The data to be applied to the template should // be placed in the context via the ContextPutTemplateData() function. func Execute(ctx context.Context, uri string, funcs ...template.FuncMap) ([]byte, error) { data := ContextGetTemplateData(ctx) fm := DefaultFuncMap(ctx) for _, opt := range funcs { fm = MergeFuncMaps(fm, opt) } // THe url itself can be a template that uses the state of the context object as vars. url := uri if applied, err := Apply([]byte(uri), data, fm); err != nil { return nil, err } else { url = string(applied) } body, err := resource.Fetch(ctx, url) if err != nil { return nil, err } return Apply2(body, data, fm) }
func ContentToFile(ctx context.Context) interface{} { return func(uri string, opts ...interface{}) (string, error) { data := ContextGetTemplateData(ctx) applied, err := Apply([]byte(uri), data) if err != nil { return NullTemplate, err } url := string(applied) content, err := resource.Fetch(ctx, url) if err != nil { return NullTemplate, err } destination := os.TempDir() fileMode := os.FileMode(0644) // The optional param ordering not important. We check by type. // String -> destination path // Int -> file mode for _, opt := range opts { switch opt.(type) { case int: fileMode = os.FileMode(opt.(int)) case string: if applied, err = Apply([]byte(opt.(string)), data); err != nil { return NullContent, err } else { destination = string(applied) } // Also expands shell path variables switch { case strings.Index(destination, "~") > -1: // expand tilda destination = strings.Replace(destination, "~", os.Getenv("HOME"), 1) case strings.Index(destination, "./") > -1: // expand tilda destination = strings.Replace(destination, "./", os.Getenv("PWD")+"/", 1) } } } parent := filepath.Dir(destination) fi, err := os.Stat(parent) if err != nil { switch { case os.IsNotExist(err): err = os.MkdirAll(parent, fileMode) if err != nil { return NullContent, err } default: return NullContent, err } } // read again after we created the directories fi, err = os.Stat(destination) if err == nil && fi.IsDir() { // build the name because we provided only a directory path destination = filepath.Join(destination, filepath.Base(string(url))) } err = ioutil.WriteFile(destination, []byte(content), fileMode) if err != nil { return NullTemplate, err } return destination, nil } }