Giter Club home page Giter Club logo

confd's People

Contributors

andrewchubatiuk avatar aquam8 avatar armon avatar bracki avatar carmstrong avatar cinience avatar crandles avatar ecliptik avatar elsonrodriguez avatar ericbarch avatar ernesto-jimenez avatar fritzy avatar gdw2 avatar heavyhorst avatar hubo1016 avatar jenshz avatar jmooradi avatar johnrengelman avatar jsolmon avatar karthequian avatar kelseyhightower avatar odedlaz avatar okushchenko avatar philipsoutham avatar say5 avatar sheepkiller avatar stepanstipl avatar ttousai avatar zealic avatar zyf0330 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

confd's Issues

confd should have an option to force a config update

I have a situation where confd finds a different config file from what it expects:

2014-03-24T12:33:51Z ip-172-16-1-185 confd[8382]: NOTICE Starting confd
2014-03-24T12:33:51Z ip-172-16-1-185 confd[8382]: NOTICE etcd nodes set to http://127.0.0.1:5001
2014-03-24T12:33:51Z ip-172-16-1-185 confd[8382]: INFO /etc/nginx/sites-enabled/site.conf has md5sum f70137102cd936cecd5890f2b330da43 should be a434ed9390072b9bc9d0c2e8be60fa47
2014-03-24T12:33:51Z ip-172-16-1-185 confd[8382]: INFO Target config /etc/nginx/sites-enabled/site.conf out of sync
2014-03-24T12:33:51Z ip-172-16-1-185 confd[8382]: ERROR Config check failed: exit status 1

However there seems to be no way for me to tell it to force overwrite the config file, and I'm forced to remove the old file before it will write a new one.

Add example etcd cluster setup

To make following the examples easier, provide a short tutorial on setting up an etcd cluster and populating the initial set of keys.

Show output from reload_cmd

It would be very helpful to show the output from reload_cmd and check_cmd in standard out. I've looked through the documentation and can't find an option.

I'm using confd with CoreOS, so sending all output to standard out logs it into journald. I can wrap the reload command and send output somewhere else, but sending it to standard out would simplify my setup. Thanks!

Intermittent ERROR exit status 2

$ confd -debug -verbose -onetime -node 192.168.61.100:4001 -config-file /app/confd.toml
2014-01-16T20:39:22Z 436e246d8953 confd[17]: ERROR exit status 2

..running it a few more times eventually result in success.

An strace suggests an EINPROGRESS error on the connect() to etcd peers. It seems like the socket FD (3) is being closed and reused a few times. I suspect some kind of race condition. I can dig in more, but I wanted to report it now.

+ strace confd -debug -verbose -onetime -node 192.168.61.100:4001 -config-file /app/confd.toml
execve("/usr/local/bin/confd", ["confd", "-debug", "-verbose", "-onetime", "-node", "192.168.61.100:4001", "-config-file", "/app/confd.toml"], [/* 11 vars */]) = 0
arch_prctl(ARCH_SET_FS, 0x9fab10)       = 0
sched_getaffinity(0, 128, {3, 0, 0, 0}) = 32
mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f539db8b000
mmap(0xc000000000, 65536, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xc000000000
munmap(0xc000000000, 65536)             = 0
mmap(0xc210000000, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xc210000000
mmap(0xc20fff0000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xc20fff0000
mmap(0xc000000000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xc000000000
mmap(NULL, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f539db7b000
mmap(NULL, 1439992, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f539da1b000
mmap(NULL, 131072, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f539d9fb000
sigaltstack({ss_sp=0xc210002000, ss_flags=0, ss_size=32768}, NULL) = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigaction(SIGHUP, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGHUP, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGINT, NULL, {SIG_DFL, [], 0}, 8) = 0
rt_sigaction(SIGINT, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGQUIT, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGILL, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGTRAP, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGABRT, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGBUS, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGFPE, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGUSR1, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGSEGV, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGUSR2, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGPIPE, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGALRM, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGTERM, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGSTKFLT, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGCHLD, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGURG, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGXCPU, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGXFSZ, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGVTALRM, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGPROF, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGWINCH, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGIO, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGPWR, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGSYS, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRTMIN, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_2, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_3, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_4, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_5, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_6, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_7, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_8, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_9, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_10, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_11, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_12, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_13, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_14, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_15, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_16, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_17, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_18, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_19, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_20, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_21, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_22, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_23, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_24, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_25, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_26, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_27, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_28, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_29, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_30, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_31, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigaction(SIGRT_32, {0x4255c0, ~[], SA_RESTORER|SA_STACK|SA_RESTART|SA_SIGINFO, 0x425630}, NULL, 8) = 0
rt_sigprocmask(SIG_SETMASK, ~[], [], 8) = 0
clone(child_stack=0x7f539da1afa0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD) = 25
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
mmap(NULL, 4080, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f539d9fa000
mmap(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f539d8fa000
futex(0x9facf8, FUTEX_WAKE, 1)          = 1
rt_sigprocmask(SIG_SETMASK, ~[], [], 8) = 0
clone(child_stack=0x7f539da16fa0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD) = 26
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
futex(0xa014e8, FUTEX_WAIT, 0, NULL)    = 0
rt_sigprocmask(SIG_SETMASK, ~[], [], 8) = 0
clone(child_stack=0x7f539da14fa0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD) = 28
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
futex(0xa014e8, FUTEX_WAIT, 0, NULL)    = 0
open("/proc/sys/net/core/somaxconn", O_RDONLY|O_CLOEXEC) = 3
futex(0xa014e8, FUTEX_WAIT, 0, NULL)    = 0
read(3, "128\n", 4096)                  = 4
read(3, "", 4092)                       = 0
close(3)                                = 0
socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
close(3)                                = 0
socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP) = 3
setsockopt(3, SOL_IPV6, IPV6_V6ONLY, [0], 4) = 0
bind(3, {sa_family=AF_INET6, sin6_port=htons(0), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = 0
socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP) = 4
setsockopt(4, SOL_IPV6, IPV6_V6ONLY, [0], 4) = 0
futex(0x9facf8, FUTEX_WAKE, 1)          = 1
bind(4, {sa_family=AF_INET6, sin6_port=htons(0), inet_pton(AF_INET6, "::ffff:127.0.0.1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = 0
close(4)                                = 0
close(3)                                = 0
socket(PF_FILE, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 3
setsockopt(3, SOL_SOCKET, SO_BROADCAST, [1], 4) = 0
epoll_create1(O_CLOEXEC)                = 4
epoll_ctl(4, EPOLL_CTL_ADD, 3, {EPOLLIN|EPOLLOUT|EPOLLET|0x2000, {u32=2646200624, u64=139997105213744}}) = 0
connect(3, {sa_family=AF_FILE, path="/run/systemd/journal/socket"}, 30) = -1 ENOENT (No such file or directory)
epoll_ctl(4, EPOLL_CTL_DEL, 3, {0, {u32=4236712, u64=4236712}}) = 0
close(3)                                = 0
readlink("/proc/self/exe", "/usr/local/bin/confd", 128) = 20
readlink("/proc/self/exe", "/usr/local/bin/confd", 128) = 20
open("/app/confd.toml", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=154, ...}) = 0
read(3, "[confd]\nconfdir  = \"/app\"\ninterv"..., 666) = 154
read(3, "", 512)                        = 0
close(3)                                = 0
open("/etc/localtime", O_RDONLY)        = 3
read(3, "TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\0"..., 4096) = 118
read(3, "", 4096)                       = 0
close(3)                                = 0
open("/proc/sys/kernel/hostname", O_RDONLY|O_CLOEXEC) = 3
read(3, "c0cd58e62acc\n", 512)          = 13
close(3)                                = 0
open("/proc/sys/kernel/hostname", O_RDONLY|O_CLOEXEC) = 3
read(3, "c0cd58e62acc\n", 512)          = 13
close(3)                                = 0
socket(PF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 3
setsockopt(3, SOL_SOCKET, SO_BROADCAST, [1], 4) = 0
epoll_ctl(4, EPOLL_CTL_ADD, 3, {EPOLLIN|EPOLLOUT|EPOLLET|0x2000, {u32=2646200624, u64=139997105213744}}) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(4001), sin_addr=inet_addr("192.168.61.100")}, 16) = -1 EINPROGRESS (Operation now in progress)
futex(0xc21002c8e8, FUTEX_WAKE, 1)      = 1
futex(0x9faa58, FUTEX_WAIT, 0, {0, 998960735} <unfinished ... exit status 0>

too many tcp connections

It seems that every time confd checks into etcd, a new TCP connection is established, and old ones are never torn down.

Eventually, ulimit is hit:
2013/10/28 08:44:04 http: Accept error: accept tcp 127.0.0.1:4001: too many open files; retrying in 1s
2013/10/28 08:44:05 http: Accept error: accept tcp 127.0.0.1:4001: too many open files; retrying in 1s

Namespace for template resource keys?

@kelseyhightower

Have you considered namespacing watched keys in template resources similar to the global prefix option?

Something like an nginx site you may want to use a common template but have a discrete template resource watching separate keys. e.g.

example.com.toml

[template]
src   = "example.conf.tmpl"
dest  = "/etc/nginx/sites-enabled/example.com.conf"
owner = "root"
group = "root"
mode  = "0644"
prefix = "site"
keys = [
  "/nginx/examplecom"
]
check_cmd  = "/usr/sbin/nginx -t -c {{ .src }}"
reload_cmd = "/usr/sbin/service nginx restart"

example.net.toml

[template]
src   = "example.conf.tmpl"
dest  = "/etc/nginx/sites-enabled/example.net.conf"
owner = "root"
group = "root"
mode  = "0644"
prefix = "site"
keys = [
  "/nginx/examplenet"
]
check_cmd  = "/usr/sbin/nginx -t -c {{ .src }}"
reload_cmd = "/usr/sbin/service nginx restart"

example.conf.tmpl

server {
    listen 80;
    server_name www.{{ .site_domain }};
    access_log /var/log/nginx/{{ .site_domain }}.access.log;
    error_log /var/log/nginx/{{ .site_domain }}.log;

    location / {
        root   {{ .site_root }};
        index  index.html index.htm;
    }
}
$ etcdctl set /nginx/examplecom/domain "example.com"
$ etcdctl set /nginx/examplenet/domain "example.net"
$ etcdctl set /nginx/examplecom/root "/var/www/example.com"
$ etcdctl set /nginx/examplenet/root "/var/www/example.net"

example.com.conf

server {
    listen 80;
    server_name www.example.com
    access_log /var/log/nginx/example.com.access.log;
    error_log /var/log/nginx/example.com.log;

    location / {
        root   /var/www/example.com;
        index  index.html index.htm;
    }
}

example.net.conf

server {
    listen 80;
    server_name www.example.net
    access_log /var/log/nginx/example.net.access.log;
    error_log /var/log/nginx/example.net.log;

    location / {
        root   /var/www/example.net;
        index  index.html index.htm;
    }
}

Theoretically this would allow for DRY templates.

I see this as being potential problematic if you wanted to have everything pointed to say /var/www and use a common etcd key for both sites, but different template (for say logging purposes).
Perhaps the prefix could be set per watch key/dir like so:

foobar.toml

[template]
src   = "foobar.conf.tmpl"
dest  = "/etc/nginx/sites-enabled/foobar.conf"
owner = "root"
group = "root"
mode  = "0644"
keys = [
 ["/nginx/foobar","site"],
 "/nginx/root"
]
check_cmd  = "/usr/sbin/nginx -t -c {{ .src }}"
reload_cmd = "/usr/sbin/service nginx restart"

example.conf.tmpl

server {
    listen 80;
    server_name www.{{ .site_domain }};
    access_log /var/log/nginx/{{ .site_domain }}.access.log;
    error_log /var/log/nginx/{{ .site_domain }}.log;

    location / {
        root   {{ .nginx_root }};
        index  index.html index.htm;
    }
}
$ etcdctl set /nginx/foobar/domain "google.com"
$ etcdctl set /nginx/root "/var/www/"

foobar.conf

server {
    listen 80;
    server_name www.google.com
    access_log /var/log/nginx/google.com.access.log;
    error_log /var/log/nginx/google.com.log;

    location / {
        root   /var/www/;
        index  index.html index.htm;
    }
}

confd fails on a nested loop

If I have a nginx template like so:

# required to run in a container
daemon off;

user www-data;
worker_processes 4;
pid /run/nginx.pid;

events {
    worker_connections 768;
    # multi_accept on;
}

http {
    # basic settings
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    server_names_hash_bucket_size 64;
    gzip on;
    gzip_disable "msie6";

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    # send logs to STDOUT so they can be seen using 'docker logs'
    access_log /dev/stdout;
    error_log /dev/stdout;


    server {
        listen 80 default_server;
        server_name _; # will never match
        server_name_in_redirect off;
    }

    # service definitions for each application

    {{ range $service := .deis_services }}{{ if $service.Nodes }}
    upstream {{ Base $service.Key }} {
        {{ range $upstream := $service.Nodes }}server {{ $upstream.Value }};
        {{ end }}
    }

    server {
        server_name ~^{{ Base $service.Key }}\.(?<domain>.+)${{ range $domain := .deis_domains }}{{ $domain.Value }}{{ end }};

        server_name_in_redirect off;
        port_in_redirect off;

        location / {
            proxy_buffering             off;
            proxy_set_header            Host $host;
            proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_redirect              off;
            proxy_connect_timeout       10;
            proxy_send_timeout          30;
            proxy_read_timeout          30;

            proxy_pass                  http://{{ Base $service.Key }};
        }
    }
    {{ end }}{{ end }}
}

When I try to run confd, it fails with the following:

# confd -onetime -node 172.17.8.100:4001 -config-file /app/confd.toml
2014-05-12T22:34:28Z 907f2188b7f5 confd[19514]: ERROR template: nginx.conf:47:81: executing "nginx.conf" at <.deis_domains>: deis_domains is not a field of struct type etcd.Node

However, moving that logic out of the loop and putting it separately and works nicely (notice facebook.com at the very bottom):

$ cat /etc/nginx/nginx.conf
[...]
server {
        server_name ~^proper-newsreel\.(?<domain>.+)$;

        server_name_in_redirect off;
        port_in_redirect off;

        location / {
            proxy_buffering             off;
            proxy_set_header            Host $host;
            proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_redirect              off;
            proxy_connect_timeout       10;
            proxy_send_timeout          30;
            proxy_read_timeout          30;

            proxy_pass                  http://proper-newsreel;
        }
    }

}
facebook.com

I'd be happy to contribute a fix. Any idea where I'd have to start looking?

Confd panics when config specifies >1 etcd node

With both 0.3.0-beta1 and 0.3.0, I get the issue described below. What am I doing wrong?

This works

etcd_nodes = [ 
  "http://<node-1>:4001"
]

This, on the other hand...

etcd_nodes = [ 
  "http://<node-1>:4001",
  "http://<node-2>:4001",
  "http://<node-3>:4001"
]

...produces this:

root@f9ce598c2cf0:~# confd -onetime
panic: reflect: slice index out of range

goroutine 1 [running]:
runtime.panic(0x616a20, 0xc210036a90)
        /usr/local/go/src/pkg/runtime/panic.c:266 +0xb6
reflect.Value.Index(0x608a40, 0x9e1d88, 0x176, 0x1, 0xc2100368b0, ...)
        /usr/local/go/src/pkg/reflect/value.go:916 +0x223
github.com/BurntSushi/toml.unifySlice(0x6081c0, 0xc21000a6a0, 0x608a40, 0x9e1d88, 0x176, ...)
        /Users/kelseyhightower/go/src/github.com/BurntSushi/toml/decode.go:215 +0x26f
github.com/BurntSushi/toml.unify(0x6081c0, 0xc21000a6a0, 0x608a40, 0x9e1d88, 0x176, ...)
        /Users/kelseyhightower/go/src/github.com/BurntSushi/toml/decode.go:129 +0x7c1
github.com/BurntSushi/toml.unifyStruct(0x615160, 0xc21001dc90, 0x6c02c0, 0x9e1d40, 0x196, ...)
        /Users/kelseyhightower/go/src/github.com/BurntSushi/toml/decode.go:169 +0x2ed
github.com/BurntSushi/toml.unify(0x615160, 0xc21001dc90, 0x6c02c0, 0x9e1d40, 0x196, ...)
        /Users/kelseyhightower/go/src/github.com/BurntSushi/toml/decode.go:125 +0x84f
github.com/BurntSushi/toml.unifyStruct(0x615160, 0xc21001dc00, 0x680e00, 0x9e1d40, 0x196, ...)
        /Users/kelseyhightower/go/src/github.com/BurntSushi/toml/decode.go:169 +0x2ed
github.com/BurntSushi/toml.unify(0x615160, 0xc21001dc00, 0x680e00, 0x9e1d40, 0x196, ...)
        /Users/kelseyhightower/go/src/github.com/BurntSushi/toml/decode.go:125 +0x84f
github.com/BurntSushi/toml.Decode(0xc210060000, 0xa7, 0x601480, 0x9e1d40, 0xa7, ...)
        /Users/kelseyhightower/go/src/github.com/BurntSushi/toml/decode.go:69 +0x107
github.com/BurntSushi/toml.DecodeFile(0x702690, 0x15, 0x601480, 0x9e1d40, 0x15, ...)
        /Users/kelseyhightower/go/src/github.com/BurntSushi/toml/decode.go:79 +0x100
github.com/kelseyhightower/confd/config.LoadConfig(0x702690, 0x15, 0x1, 0x9ea7f3)
        /Users/kelseyhightower/go/src/github.com/kelseyhightower/confd/config/config.go:83 +0x344
main.main()
        /Users/kelseyhightower/go/src/github.com/kelseyhightower/confd/confd.go:41 +0xae

Consul iteration not working

I'm not able to get template iteration to work via consul, although etcd is working fine.

test.conf.tmpl:

{{range $i := .servers_api}}
    {{$i.Value}}
{{end}}

{{ .servers_api }}

test.toml

[template]
src = "test.conf.tmpl"
dest = "/tmp/test.conf"
keys = [
  "servers/api",
    ]

etcd setup:

curl http://127.0.0.1:4001/v2/keys/servers/api -XPUT -d dir=true
curl http://127.0.0.1:4001/v2/keys/servers/api/app2 -XPUT -d value="10.0.1.101:80"
curl http://127.0.0.1:4001/v2/keys/servers/api/app1 -XPUT -d value="10.0.1.100:80"

confd -verbose -onetime -node 'http://127.0.0.1:4001' -confdir="/etc/confd"

consul setup:

curl -X PUT -d '10.0.1.101:80' http://localhost:8500/v1/kv/servers/api/app1
curl -X PUT -d '10.0.1.100:80' http://localhost:8500/v1/kv/servers/api/app2

confd -verbose -onetime -consul=true -consul-addr="127.0.0.1:8500" -confdir="/etc/confd"

etcd 'test.conf' output:


    10.0.1.101:80

    10.0.1.100:80


[0xc21000a900 0xc21000a960]

consul 'test.conf' output:



<no value>

Q: How can I use confd to do service discovery?

e.g. : I have etcd keys like so:

└── webservers
    ├── web-001.mycompany.tld
    │   ├── listen_ip
    │   └── listen_port
    └── web-002.mycompany.tld
        ├── listen_ip
        └── listen_port

Can I use confd to write out a config from a dynamic list of etcd keys? The examples seem to assume that you know the path of all etcd keys you'll be referencing in a given template.

My use case for this is etcd + haproxy, with a dynamic set of backend servers for multiple haproxy "backends".

From the confd docs, and what I understood from text/template, I don't understand how I can accomplish this with confd.

If this isn't something you think confd should support, or my keystructure is silly, that's fine too!

Thanks!

Switch to TOML for configuration files

INI configuration files are proving to limited, we should really switch to TOML so thing like configuring a list of etcd servers is much cleaner.

We can go from:

[etcd]
machines = node1,node2

To:

[etcd]
machines = ["node1", "node2"]

panic: read /etc/confd/templates: is a directory

I am trying to run the pre-built confd from the 0.3.0 release tar.gz archive, and I keep getting the following error:

$ confd -debug -onetime
2014-04-08T13:41:01-04:00 twemproxy01 confd[3627]: NOTICE Starting confd
2014-04-08T13:41:01-04:00 twemproxy01 confd[3627]: NOTICE etcd nodes set to http://127.0.0.1:4001
2014-04-08T13:41:01-04:00 twemproxy01 confd[3627]: DEBUG Loading template resources from confdir /etc/confd
2014-04-08T13:41:01-04:00 twemproxy01 confd[3627]: DEBUG Processing template resource /etc/confd/conf.d/example.toml
2014-04-08T13:41:01-04:00 twemproxy01 confd[3627]: DEBUG Loading template resource from /etc/confd/conf.d/example.toml
2014-04-08T13:41:01-04:00 twemproxy01 confd[3627]: DEBUG Retrieving keys from etcd
2014-04-08T13:41:01-04:00 twemproxy01 confd[3627]: DEBUG Key prefix set to /
2014-04-08T13:41:01-04:00 twemproxy01 confd[3627]: DEBUG Using source template /etc/confd/templates
2014-04-08T13:41:01-04:00 twemproxy01 confd[3627]: DEBUG Compiling source template /etc/confd/templates
panic: read /etc/confd/templates: is a directory

goroutine 1 [running]:
runtime.panic(0x6751e0, 0xc210074870)
    /usr/local/go/src/pkg/runtime/panic.c:266 +0xb6
text/template.Must(0x0, 0x7f363facfab8, 0xc210074870, 0x1)
    /usr/local/go/src/pkg/text/template/helper.go:23 +0x4f
github.com/kelseyhightower/confd/resource/template.(*TemplateResource).createStageFile(0xc21000f820, 0x0, 0x0)
    /Users/kelseyhightower/go/src/github.com/kelseyhightower/confd/resource/template/resource.go:95 +0x4dd
github.com/kelseyhightower/confd/resource/template.(*TemplateResource).process(0xc21000f820, 0x1e, 0x7f363facfa90)
    /Users/kelseyhightower/go/src/github.com/kelseyhightower/confd/resource/template/resource.go:195 +0x81
github.com/kelseyhightower/confd/resource/template.ProcessTemplateResources(0x7f363facfa90, 0xc210061480, 0x9e07a8, 0x7f363facfa90, 0x0)
    /Users/kelseyhightower/go/src/github.com/kelseyhightower/confd/resource/template/resource.go:254 +0x7ad
main.main()
    /Users/kelseyhightower/go/src/github.com/kelseyhightower/confd/confd.go:58 +0x295

goroutine 5 [runnable]:
net/http.(*persistConn).readLoop(0xc210061600)
    /usr/local/go/src/pkg/net/http/transport.go:778 +0x68f
created by net/http.(*Transport).dialConn
    /usr/local/go/src/pkg/net/http/transport.go:528 +0x607

goroutine 6 [select]:
net/http.(*persistConn).writeLoop(0xc210061600)
    /usr/local/go/src/pkg/net/http/transport.go:791 +0x271
created by net/http.(*Transport).dialConn
    /usr/local/go/src/pkg/net/http/transport.go:529 +0x61e

My /etc/confd/confd.toml file reads as follows:

[confd]
confdir = "/etc/confd"
interval = 60
prefix = "/"
verbose = true
debug = false
quiet = false
etcd_nodes = ["http://127.0.0.1:4001"]
etcd_scheme = "http"
srv_domain = ""
client_cert = ""
client_key = ""
noop = false

Why is confd attempting to read /etc/confd/templates as though it is a template file?

Q: How to create INI-formated config files

Bonjour,

I would like to control a config file that has a simple INI format (it's carbons storage-schemas.conf).
It is going to look like this:

[carbon]
pattern = ^carbon\.
retentions = 1s:1d

[diamond]
pattern = ^servers\.
retentions = 5s:1d

To start simple I though about storing it like...

carbon/storageschemas/statsd  -d value="pattern = '^stats\.'\nretentions = 5s:1d"
carbon/storageschemas/default -d value="pattern = .*\nretentions = 60s:1d"

My template:

{{range $entry := .carbon_storageschemas}}
[{{ $entry.Key }}]
{{ $entry.Value }}
{{end}}

This results in...

$ cat /tmp/storage-schemas.conf

[/carbon/storageschemas/statsd]
pattern = '^stats\.'\nretentions = 5s:1d

[/carbon/storageschemas/default]
pattern = .*\nretentions = 60s:1d

So I am not that far away, spliting the key with ''.split("/")[-1]'' and I got the last part of the key.
But this ruby-magic has to be inserted somehow I could not get to wrap my head around (so far).
Now I have to split the value twice, maybe better:

carbon/storageschemas/statsd/pattern -d value="'^stats\.'"
carbon/storageschemas/statsd/retentions -d value="5s:1d"

Could someone help me out, plz... :) I guess INI files are not something strange to handle.

Thx
Christian

Key not found blocks processing of other template resources

I'm using v0.1.1beta3.

It seems like templates resources are parsed in alphabetical order.
If a watched key is not present an error is thrown and processing is stopped. Subsequent template resources are not processed.

e.g.
a.toml

[template]
src   = "a.conf.tmpl"
dest  = "/tmp/test/a.conf"
owner = "root"
group = "root"
mode  = "0644"
keys = [
  "/a",
]

b.toml

[template]
src   = "b.conf.tmpl"
dest  = "/temp/test/b.conf"
owner = "root"
group = "root"
mode  = "0644"
keys = [
  "/b",
]
$ etcdctl set /b 'bar'
$ confd -i 5
2013-10-21T05:13:21Z vagrant confd[7153]: ERROR 100: Key Not Found (get: /a)
2013-10-21T05:13:26Z vagrant confd[7153]: ERROR 100: Key Not Found (get: /a)
$ ls -l /tmp/test
total 0

etcd key to variable mapping

You can do some directory things with etcd key/values e.g.

$ curl -L http://127.0.0.1:4001/v1/keys/foo
[{"action":"GET","key":"/foo/bar","value":"hello","index":8},{"action":"GET","key":"/foo/maa","value":"world","index":8},{"action":"GET","key":"/foo/pop","dir":true,"index":8}]

$ curl -L http://127.0.0.1:4001/v1/keys/foo/pop
[{"action":"GET","key":"/foo/pop/tar","value":"dfa","index":8}]

In this case I have /foo watched for my template and confd doesn't like this. In the template {{.}} yields:

map[foo_bar:hello foo_maa:world foo_pop:]

Add status endpoint

confd should have a status endpoint that allows external tools and clients to gather stats and check the health of the confd daemon.

Add dryrun/noop mode

It's pretty easy to add a dryrun or noop mode to preview changes. I'm proposing a new flag, -noop, to enable this behavior.

Prefixes not properly striped when using consul client

The consul client returns the keys without the first / (e.g: map[string]string{"prefix/key":value})

However, cleanKeys expects keys to have the first / in order to trim the prefix.

This can easily be tested:

--- a/resource/template/resource_test.go
+++ b/resource/template/resource_test.go
@@ -433,6 +433,7 @@ func TestCleanKeys(t *testing.T) {
        "/this_key":             "foo",
        "/prefix/key":           "test",
        "/my/new-cool-val/here": "bar",
+       "prefix/second_key":     "ok",
    }
    config.SetPrefix("/prefix")
    clean := cleanKeys(pre, "/prefix")
@@ -451,4 +452,7 @@ func TestCleanKeys(t *testing.T) {
    if _, ok := clean["my_new_cool_val_here"]; !ok {
        t.Fatalf("bad: %v", clean)
    }
+   if _, ok := clean["second_key"]; !ok {
+       t.Fatalf("bad: %v", clean)
+   }
 }

Quick and dirty solution would be to strip first / from key and prefix before trimming prefix:

--- a/resource/template/resource.go
+++ b/resource/template/resource.go
@@ -108,6 +108,8 @@ func cleanKeys(vars map[string]interface{}, prefix string) map[string]interface{
 // pathToKey translates etcd key paths into something more suitable for use
 // in Golang templates. Turn /prefix/key/subkey into key_subkey.
 func pathToKey(key, prefix string) string {
+   prefix = strings.TrimPrefix(prefix, "/")
+   key = strings.TrimPrefix(key, "/")
    key = strings.TrimPrefix(key, prefix)
    key = strings.TrimPrefix(key, "/")
    return replacer.Replace(key)

Would you rather do this or fix it in the consul client?

/cc @armon since he did the consul implementation

Consul Support

@kelseyhightower

I noticed Consul has been added, when will a new release be made?

I tried compiling Go on my own but running into an issue.

go build
github.com/kelseyhightower/confd/etcd/etcdutil
etcd/etcdutil/client.go:70: cannot use &node (type **etcd.Node) as type *etcd.Node in function argument

consul not removing the prefix keys from template variables

Set a nested variable in consul:

export PREFIX=http://127.0.0.1:8500/v1/kv/foo/bar
curl -XPUT $PREFIX/role -d'master'

Create a template:

all = {{ . }}

role = {{ .role }}

Run consul:

$ confd -consul -prefix=/foo/bar ...

Expected result is:

all = map[role:master]

role = master

Actual result:

all = map[foo_bar_role:master]

role = <no value>

Controlling the files to be created via etcd

Say I am configuring an application that supports a hooks.d/ directory. The app will run 'hooks.d/foo" when the "foo" event occurs.

It would be nice if I can add the hook to etcd, and confd would have to place it in the proper directory. Essentially, this amounts to a etcd key whose content's are mirrored to an actual directory on the disk.

Is this something that confd might support?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.