Example #1
0
// Run server.
func (c *config) Run() error {
	session = c.session

	log.Infof("Bind to: %s", c.bind)
	log.Infof("Using server URI: %s", c.serverURI)
	logr := handlers.LoggingHandler(os.Stderr, c.router)
	return http.ListenAndServe(c.bind, logr)
}
Example #2
0
// deleteDoc delete document.
func (c *config) deleteDoc(endpoint, path string) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		var newPath bytes.Buffer

		err := templ.ExecuteTemplate(&newPath, endpoint, mux.Vars(r))
		if err != nil {
			log.Fatal(err.Error())
		}

		log.Infof("etcd path: %s", newPath.String())

		data, code, err := c.session.Get(newPath.String(), false, "")
		if err != nil {
			c.writeError(w, r, err, code)
			return
		}

		if code, err := c.session.Delete(newPath.String()); err != nil {
			c.writeError(w, r, err, code)
			return
		}

		c.write(w, r, data)
	}
}
Example #3
0
// getDoc get document.
func (c *config) getDoc(endpoint, path string, collection bool, dirName string) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		var newPath bytes.Buffer

		table := false
		if collection == true && strings.ToLower(r.URL.Query().Get("table")) == "true" {
			table = true
		}

		err := templ.ExecuteTemplate(&newPath, endpoint, mux.Vars(r))
		if err != nil {
			log.Fatal(err.Error())
		}

		log.Infof("etcd path: %s", newPath.String())

		doc, code, err := c.session.Get(newPath.String(), table, dirName)
		if err != nil {
			c.writeError(w, r, err, code)
			return
		}

		c.write(w, r, doc)
	}
}
Example #4
0
// RouteEtcd add route for etcd.
func (c *config) RouteEtcd(collection, collectionPath, resource, resourcePath, schema, dirName string) {
	log.Infof("Add collection: %s collection path: %s", collection, collectionPath)
	log.Infof("Add resource: %s resource path: %s schema: %s", resource, resourcePath, schema)

	if templ == nil {
		templ = template.Must(template.New(collection).Parse(collectionPath))
	} else {
		template.Must(templ.New(collection).Parse(collectionPath))
	}

	template.Must(templ.New(resource).Parse(resourcePath))

	c.router.HandleFunc(collection, c.getDoc(collection, collectionPath, true, dirName)).Methods("GET")
	c.router.HandleFunc(resource, c.getDoc(resource, resourcePath, false, dirName)).Methods("GET")
	c.router.HandleFunc(resource, c.putOrPatchDoc(resource, resourcePath, schema)).Methods("PUT")
	c.router.HandleFunc(resource, c.putOrPatchDoc(resource, resourcePath, schema)).Methods("PATCH")
	c.router.HandleFunc(resource, c.deleteDoc(resource, resourcePath)).Methods("DELETE")
}
Example #5
0
// RouteTempl add route for Go Text Template.
func (c *config) RouteTemplate(endpoint, templ string) {
	if templates == nil {
		templates = template.Must(template.New("main").Funcs(funcs).ParseGlob(c.templDir + "/*.tmpl"))
		vm = otto.New()
	}

	url := endpoint
	log.Infof("Add endpoint: %s template: %s", url, templ)
	c.router.HandleFunc(url, c.getTemplate(templ)).Methods("GET")
}
Example #6
0
func (c *config) Connect() (Session, error) {
	log.Infof("Connect to etcd peers: %s", c.peers)
	cl, err := c.newClient()
	if err != nil {
		return nil, err
	}

	return &session{
		client:  cl,
		keysAPI: client.NewKeysAPI(cl),
	}, nil
}
Example #7
0
func (c *config) validateDoc(doc []byte, path string, schema string) (int, []error) {
	// Prepare document and JSON schema.
	docLoader := gojsonschema.NewStringLoader(string(doc))
	log.Infof("Using schema URI: %s/%s", c.schemaURI, schema)
	schemaLoader := gojsonschema.NewReferenceLoader(c.schemaURI + "/" + schema)

	// Validate document using JSON schema.
	res, err := gojsonschema.Validate(schemaLoader, docLoader)
	if err != nil {
		return http.StatusInternalServerError, []error{err}
	}

	if !res.Valid() {
		var errors []error
		for _, e := range res.Errors() {
			errors = append(errors, fmt.Errorf("%s: %s", strings.Replace(e.Context().String("/"), "(root)", path, 1), e.Description()))
		}

		return http.StatusBadRequest, errors
	}

	return http.StatusOK, nil
}
Example #8
0
func (cfg *Config) Load(c *cli.Context) {
	// Enable debug.
	if c.GlobalBool("debug") {
		log.SetDebug()
	}

	// Default path for config file.
	u, _ := user.Current()
	cfgs := []string{
		u.HomeDir + "/.etcdrest.json",
		u.HomeDir + "/.etcdrest.yaml",
		u.HomeDir + "/.etcdrest.yml",
		u.HomeDir + "/.etcdrest.toml",
		u.HomeDir + "/.etcdrest.tml",
		"/etc/etcdrest.json",
		"/etc/etcdrest.yaml",
		"/etc/etcdrest.yml",
		"/etc/etcdrest.toml",
		"/etc/etcdrest.tml",
		"/app/etc/etcdrest.json",
		"/app/etc/etcdrest.yaml",
		"/app/etc/etcdrest.yml",
		"/app/etc/etcdrest.toml",
		"/app/etc/etcdrest.tml",
	}

	// Check if we have an arg. for config file and that it exist's.
	if c.GlobalString("config") != "" {
		if _, err := os.Stat(c.GlobalString("config")); os.IsNotExist(err) {
			log.Fatalf("Config file doesn't exist: %s", c.GlobalString("config"))
		}
		cfgs = append([]string{c.GlobalString("config")}, cfgs...)
	}

	for _, fn := range cfgs {
		if _, err := os.Stat(fn); os.IsNotExist(err) {
			continue
		}

		log.Infof("Using config file: %s", fn)

		// Load config file.
		b, err := ioutil.ReadFile(fn)
		if err != nil {
			log.Fatal(err.Error())
		}

		switch filepath.Ext(fn) {
		case ".json":
			if err := json.Unmarshal(b, cfg); err != nil {
				log.Fatal(err.Error())
			}
		case ".yaml", ".yml":
			if err := yaml.Unmarshal(b, cfg); err != nil {
				log.Fatal(err.Error())
			}
		case ".toml", ".tml":
			if err := toml.Unmarshal(b, cfg); err != nil {
				log.Fatal(err.Error())
			}
		default:
			log.Fatal("unsupported data format")
		}

		// Validate config using JSON schema.

		break
	}

	// Override configuration.
	if c.GlobalString("templ-dir") != "" {
		cfg.TemplDir = c.GlobalString("templ-dir")
	}

	if c.GlobalString("schema-uri") != "" {
		cfg.SchemaURI = c.GlobalString("schema-uri")
	}

	if c.GlobalString("bind") != "" {
		cfg.Bind = c.GlobalString("bind")
	}

	if c.GlobalString("server-uri") != "" {
		cfg.ServerURI = c.GlobalString("server-uri")
	}

	if c.GlobalBool("envelope") {
		cfg.Envelope = true
	}

	if c.GlobalBool("no-indent") {
		cfg.Indent = true
	}

	// Override etcd configuration.
	if c.GlobalString("peers") != "" {
		cfg.Etcd.Peers = c.GlobalString("peers")
	}

	if c.GlobalString("cert") != "" {
		cfg.Etcd.Cert = c.GlobalString("cert")
	}

	if c.GlobalString("key") != "" {
		cfg.Etcd.Key = c.GlobalString("key")
	}

	if c.GlobalString("ca") != "" {
		cfg.Etcd.CA = c.GlobalString("ca")
	}

	if c.GlobalString("user") != "" {
		cfg.Etcd.User = c.GlobalString("user")
	}

	if c.GlobalDuration("timeout") != 0 {
		cfg.Etcd.Timeout = c.GlobalDuration("timeout")
	}

	if c.GlobalDuration("command-timeout") != 0 {
		cfg.Etcd.CmdTimeout = c.GlobalDuration("command-timeout")
	}
}
Example #9
0
// RouteStatic add route for file system path.
func (c *config) RouteStatic(endpoint, path string) {
	log.Infof("Add endpoint: %s path: %s", endpoint, path)

	c.router.PathPrefix(endpoint + "/").Handler(http.StripPrefix(endpoint+"/", http.FileServer(http.Dir(path))))
	http.Handle(endpoint+"/", c.router)
}
Example #10
0
// putOrPatchDoc put or patch document.
func (c *config) putOrPatchDoc(endpoint, path, schema string) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		var newPath bytes.Buffer

		err := templ.ExecuteTemplate(&newPath, endpoint, mux.Vars(r))
		if err != nil {
			log.Fatal(err.Error())
		}

		log.Infof("etcd path: %s", newPath.String())

		// Get request body.
		body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
		if err != nil {
			c.writeError(w, r, err, http.StatusInternalServerError)
			return
		}
		if err := r.Body.Close(); err != nil {
			c.writeError(w, r, err, http.StatusInternalServerError)
			return
		}

		// Patch document using JSON patch RFC 6902.
		var doc []byte
		if r.Method == "PATCH" {
			data, code, err := c.session.Get(newPath.String(), false, "")
			if err != nil {
				c.writeError(w, r, err, code)
				return
			}

			origDoc, err := json.Marshal(&data)
			if err != nil {
				c.writeError(w, r, err, http.StatusInternalServerError)
				return
			}

			doc, err = c.patchDoc(origDoc, body)
			if err != nil {
				c.writeError(w, r, err, code)
				return
			}
		} else {
			doc = body
		}

		// Validate document using JSON schema
		if code, errors := c.validateDoc(doc, newPath.String(), schema); errors != nil {
			c.writeErrors(w, r, errors, code)
			return
		}

		var data interface{}
		if err := json.Unmarshal(doc, &data); err != nil {
			c.writeError(w, r, err, http.StatusInternalServerError)
			return
		}

		// Create document.
		if code, err := c.session.Put(newPath.String(), data); err != nil {
			c.writeError(w, r, err, code)
			return
		}

		c.write(w, r, data)
	}
}