Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ Environment variables:
| `ETCD` | etcd endpoint | `etcd:2379` |
| `CORS` | allowed origins | `http://localhost:8080,http://localhost:8081` |
| `EDITABLE` | set to `1` to enable edit functionality | `0` |
| `PREFIX` | only browse keys under a given prefix | `` |
| `USERNAME` | optionally send a username to etcd | `<empty>` |
| `PASSWORD` | optionally send a password to etcd | `<empty>` |

## Development environment

Expand Down
32 changes: 25 additions & 7 deletions backend/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,39 @@ var (
etcdEndpoints = env("ETCD", "etcd:2379", "comma-separated list of etcd endpoints")
editable = envInt("EDITABLE", 0, "enable update functionality")
pprof = envInt("PPROF", 0, "enable /debug/pprof endpoint")
username = env("USERNAME", "", "supply username to etcd")
password = env("PASSWORD", "", "supply password to etcd")
prefix = env("PREFIX", "", "browse KVs under the given prefix")
)

func main() {
log.Printf("etcdv3-browser starting on port %d, etcd endpoint: %s, editable: %d, pprof: %d\n", httpPort, etcdEndpoints, editable, pprof)

etcdClient, err := clientv3.New(clientv3.Config{
Endpoints: strings.Split(etcdEndpoints, ","),
DialTimeout: 7 * time.Second,
DialKeepAliveTime: 30 * time.Second,
DialKeepAliveTimeout: 10 * time.Second,
})
clientConfig := clientv3.Config{}

if username != "" && password != "" {
clientConfig = clientv3.Config{
Username: username,
Password: password,
Endpoints: strings.Split(etcdEndpoints, ","),
DialTimeout: 7 * time.Second,
DialKeepAliveTime: 30 * time.Second,
DialKeepAliveTimeout: 10 * time.Second,
}
} else {
clientConfig = clientv3.Config{
Endpoints: strings.Split(etcdEndpoints, ","),
DialTimeout: 7 * time.Second,
DialKeepAliveTime: 30 * time.Second,
DialKeepAliveTimeout: 10 * time.Second,
}
}

etcdClient, err := clientv3.New(clientConfig)
if err != nil {
log.Fatal(errors.Wrap(err, "etcd client"))
}
server := newServer(etcdClient, editable == 1)
server := newServer(etcdClient, editable == 1, prefix)

mux := http.DefaultServeMux
if pprof == 0 {
Expand Down
9 changes: 5 additions & 4 deletions backend/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type apiServer struct {
leases map[int64]bool
rev int64
editable bool
prefix string
}

type okResponse struct {
Expand All @@ -40,8 +41,8 @@ type updateMsg struct {
Lease int64 `json:"lease,omitempty"`
}

func newServer(etcd *clientv3.Client, editable bool) *apiServer {
server := apiServer{etcd: etcd, root: nodetree.NewNode("", 0), editable: editable, broker: NewBroker()}
func newServer(etcd *clientv3.Client, editable bool, prefix string) *apiServer {
server := apiServer{etcd: etcd, root: nodetree.NewNode("", 0), editable: editable, broker: NewBroker(), prefix: prefix}
go server.initAndWatch()
go server.broker.Start()
go server.removeExpiredLoop()
Expand Down Expand Up @@ -187,7 +188,7 @@ func (s *apiServer) initAndWatch() {
go s.loadUpdates(s.broker.Subscribe())
for delay := 20; delay < 10000; delay *= 2 {
log.Print("Watching starting from rev ", rev)
for resp := range s.etcd.Watch(context.Background(), "", clientv3.WithPrefix(), clientv3.WithRev(rev)) {
for resp := range s.etcd.Watch(context.Background(), s.prefix, clientv3.WithPrefix(), clientv3.WithRev(rev)) {
if err := resp.Err(); err != nil {
if err == rpctypes.ErrCompacted {
rev = resp.CompactRevision
Expand Down Expand Up @@ -215,7 +216,7 @@ func (s *apiServer) initAndWatch() {
}

func (s *apiServer) loadExisting() {
resp, err := s.etcd.Get(context.Background(), "", clientv3.WithPrefix())
resp, err := s.etcd.Get(context.Background(), s.prefix, clientv3.WithPrefix())
if err != nil {
log.Fatal("loadExisting: ", err)
return
Expand Down