Compare commits

...

14 Commits

15 changed files with 113 additions and 45 deletions

View File

@@ -35,9 +35,9 @@ RUN (echo deb http://vitastor.io/debian bookworm main > /etc/apt/sources.list.d/
wget -q -O /etc/apt/trusted.gpg.d/vitastor.gpg https://vitastor.io/debian/pubkey.gpg && \ wget -q -O /etc/apt/trusted.gpg.d/vitastor.gpg https://vitastor.io/debian/pubkey.gpg && \
apt-get update && \ apt-get update && \
apt-get install -y vitastor-client && \ apt-get install -y vitastor-client && \
apt-get download qemu-system-common && \ wget https://vitastor.io/archive/qemu/qemu-bookworm-8.1.2%2Bds-1%2Bvitastor1/qemu-utils_8.1.2%2Bds-1%2Bvitastor1_amd64.deb && \
apt-get download qemu-block-extra && \ wget https://vitastor.io/archive/qemu/qemu-bookworm-8.1.2%2Bds-1%2Bvitastor1/qemu-block-extra_8.1.2%2Bds-1%2Bvitastor1_amd64.deb && \
dpkg -x qemu-system-common*.deb tmp1 && \ dpkg -x qemu-utils*.deb tmp1 && \
dpkg -x qemu-block-extra*.deb tmp1 && \ dpkg -x qemu-block-extra*.deb tmp1 && \
cp -a tmp1/usr/bin/qemu-storage-daemon /usr/bin/ && \ cp -a tmp1/usr/bin/qemu-storage-daemon /usr/bin/ && \
mkdir -p /usr/lib/x86_64-linux-gnu/qemu && \ mkdir -p /usr/lib/x86_64-linux-gnu/qemu && \

View File

@@ -97,6 +97,15 @@ func GetConnectionParams(params map[string]string) (map[string]string, error)
} }
case []string: case []string:
etcdUrl = config["etcd_address"].([]string) etcdUrl = config["etcd_address"].([]string)
case []interface{}:
for _, url := range config["etcd_address"].([]interface{})
{
s, ok := url.(string)
if (ok)
{
etcdUrl = append(etcdUrl, s)
}
}
} }
if (len(etcdUrl) == 0) if (len(etcdUrl) == 0)
{ {
@@ -105,8 +114,9 @@ func GetConnectionParams(params map[string]string) (map[string]string, error)
return ctxVars, nil return ctxVars, nil
} }
func system(program string, args ...string) ([]byte, error) func system(program string, args ...string) ([]byte, []byte, error)
{ {
klog.Infof("Running "+program+" "+strings.Join(args, " "))
c := exec.Command(program, args...) c := exec.Command(program, args...)
var stdout, stderr bytes.Buffer var stdout, stderr bytes.Buffer
c.Stdout, c.Stderr = &stdout, &stderr c.Stdout, c.Stderr = &stdout, &stderr
@@ -115,9 +125,9 @@ func system(program string, args ...string) ([]byte, error)
{ {
stdoutStr, stderrStr := string(stdout.Bytes()), string(stderr.Bytes()) stdoutStr, stderrStr := string(stdout.Bytes()), string(stderr.Bytes())
klog.Errorf(program+" "+strings.Join(args, " ")+" failed: %s, status %s\n", stdoutStr+stderrStr, err) klog.Errorf(program+" "+strings.Join(args, " ")+" failed: %s, status %s\n", stdoutStr+stderrStr, err)
return nil, status.Error(codes.Internal, stdoutStr+stderrStr+" (status "+err.Error()+")") return nil, nil, status.Error(codes.Internal, stdoutStr+stderrStr+" (status "+err.Error()+")")
} }
return stdout.Bytes(), nil return stdout.Bytes(), stderr.Bytes(), nil
} }
func invokeCLI(ctxVars map[string]string, args []string) ([]byte, error) func invokeCLI(ctxVars map[string]string, args []string) ([]byte, error)
@@ -126,7 +136,8 @@ func invokeCLI(ctxVars map[string]string, args []string) ([]byte, error)
{ {
args = append(args, "--config_path", ctxVars["configPath"]) args = append(args, "--config_path", ctxVars["configPath"])
} }
return system("/usr/bin/vitastor-cli", args...) stdout, _, err := system("/usr/bin/vitastor-cli", args...)
return stdout, err
} }
// Create the volume // Create the volume

View File

@@ -7,6 +7,7 @@ import (
"context" "context"
"errors" "errors"
"encoding/json" "encoding/json"
"fmt"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@@ -154,8 +155,13 @@ func (ns *NodeServer) mapNbd(volName string, ctxVars map[string]string, readonly
{ {
args = append(args, "--readonly", "1") args = append(args, "--readonly", "1")
} }
dev, err := system("/usr/bin/vitastor-nbd", args...) stdout, stderr, err := system("/usr/bin/vitastor-nbd", args...)
return strings.TrimSpace(string(dev)), err dev := strings.TrimSpace(string(stdout))
if (dev == "")
{
return "", fmt.Errorf("vitastor-nbd did not return the name of NBD device. output: %s", stderr)
}
return dev, err
} }
func (ns *NodeServer) unmapNbd(devicePath string) func (ns *NodeServer) unmapNbd(devicePath string)
@@ -170,6 +176,7 @@ func (ns *NodeServer) unmapNbd(devicePath string)
func findByPidFile(pidFile string) (*os.Process, error) func findByPidFile(pidFile string) (*os.Process, error)
{ {
klog.Infof("killing process with PID from file %s", pidFile)
pidBuf, err := os.ReadFile(pidFile) pidBuf, err := os.ReadFile(pidFile)
if (err != nil) if (err != nil)
{ {
@@ -221,7 +228,7 @@ func startStorageDaemon(vdpaId, volName, pidFile, configPath string, readonly bo
{ {
writable = "false" writable = "false"
} }
_, err := system( _, _, err := system(
"/usr/bin/qemu-storage-daemon", "--daemonize", "--pidfile", pidFile, "--blockdev", string(blockSpecJson), "/usr/bin/qemu-storage-daemon", "--daemonize", "--pidfile", pidFile, "--blockdev", string(blockSpecJson),
"--export", "vduse-blk,id="+vdpaId+",node-name=disk1,name="+vdpaId+",num-queues=16,queue-size=128,writable="+writable, "--export", "vduse-blk,id="+vdpaId+",node-name=disk1,name="+vdpaId+",num-queues=16,queue-size=128,writable="+writable,
) )
@@ -234,7 +241,7 @@ func (ns *NodeServer) mapVduse(volName string, ctxVars map[string]string, readon
stateFd, err := os.CreateTemp(ns.stateDir, "vitastor-vduse-*.json") stateFd, err := os.CreateTemp(ns.stateDir, "vitastor-vduse-*.json")
if (err != nil) if (err != nil)
{ {
return "", "", status.Error(codes.Internal, err.Error()) return "", "", err
} }
stateFile := stateFd.Name() stateFile := stateFd.Name()
stateFd.Close() stateFd.Close()
@@ -246,11 +253,12 @@ func (ns *NodeServer) mapVduse(volName string, ctxVars map[string]string, readon
if (err == nil) if (err == nil)
{ {
// Add device to VDPA bus // Add device to VDPA bus
_, err = system("/sbin/vdpa", "-j", "dev", "add", "name", vdpaId, "mgmtdev", "vduse") _, _, err = system("/sbin/vdpa", "-j", "dev", "add", "name", vdpaId, "mgmtdev", "vduse")
if (err == nil) if (err == nil)
{ {
// Find block device name // Find block device name
matches, err := filepath.Glob("/sys/bus/vdpa/devices/"+vdpaId+"/virtio*/block/*") var matches []string
matches, err = filepath.Glob("/sys/bus/vdpa/devices/"+vdpaId+"/virtio*/block/*")
if (err == nil && len(matches) == 0) if (err == nil && len(matches) == 0)
{ {
err = errors.New("/sys/bus/vdpa/devices/"+vdpaId+"/virtio*/block/* is not found") err = errors.New("/sys/bus/vdpa/devices/"+vdpaId+"/virtio*/block/* is not found")
@@ -277,21 +285,14 @@ func (ns *NodeServer) mapVduse(volName string, ctxVars map[string]string, readon
} }
} }
} }
if (err != nil)
{
err = status.Error(codes.Internal, err.Error())
}
} }
if (err != nil) killErr := killByPidFile(pidFile)
if (killErr != nil)
{ {
killErr := killByPidFile(pidFile) klog.Errorf("Failed to kill started qemu-storage-daemon: %v", killErr)
if (killErr != nil)
{
klog.Errorf("Failed to kill started qemu-storage-daemon: %v", killErr)
}
os.Remove(stateFile)
os.Remove(pidFile)
} }
os.Remove(stateFile)
os.Remove(pidFile)
} }
return "", "", err return "", "", err
} }
@@ -337,7 +338,7 @@ func (ns *NodeServer) unmapVduseById(vdpaId string)
} }
else else
{ {
_, _ = system("/sbin/vdpa", "-j", "dev", "del", vdpaId) _, _, _ = system("/sbin/vdpa", "-j", "dev", "del", vdpaId)
} }
stateFile := ns.stateDir + vdpaId + ".json" stateFile := ns.stateDir + vdpaId + ".json"
os.Remove(stateFile) os.Remove(stateFile)
@@ -377,7 +378,7 @@ func (ns *NodeServer) restoreVduseDaemons()
} }
devList := make(map[string]interface{}) devList := make(map[string]interface{})
// example output: {"dev":{"test1":{"type":"block","mgmtdev":"vduse","vendor_id":0,"max_vqs":16,"max_vq_size":128}}} // example output: {"dev":{"test1":{"type":"block","mgmtdev":"vduse","vendor_id":0,"max_vqs":16,"max_vq_size":128}}}
devListJSON, err := system("/sbin/vdpa", "-j", "dev", "list") devListJSON, _, err := system("/sbin/vdpa", "-j", "dev", "list")
if (err != nil) if (err != nil)
{ {
return return
@@ -456,13 +457,13 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
if (err != nil) if (err != nil)
{ {
klog.Errorf("failed to create block device mount target %s with error: %v", targetPath, err) klog.Errorf("failed to create block device mount target %s with error: %v", targetPath, err)
return nil, status.Error(codes.Internal, err.Error()) return nil, err
} }
err = pathFile.Close() err = pathFile.Close()
if (err != nil) if (err != nil)
{ {
klog.Errorf("failed to close %s with error: %v", targetPath, err) klog.Errorf("failed to close %s with error: %v", targetPath, err)
return nil, status.Error(codes.Internal, err.Error()) return nil, err
} }
} }
else else
@@ -471,13 +472,13 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
if (err != nil) if (err != nil)
{ {
klog.Errorf("failed to create fs mount target %s with error: %v", targetPath, err) klog.Errorf("failed to create fs mount target %s with error: %v", targetPath, err)
return nil, status.Error(codes.Internal, err.Error()) return nil, err
} }
} }
} }
else else
{ {
return nil, status.Error(codes.Internal, err.Error()) return nil, err
} }
} }
@@ -538,6 +539,10 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
{ {
opt = append(opt, "nouuid") opt = append(opt, "nouuid")
} }
if (fsType == "ext4")
{
opt = append(opt, "relatime","lazytime")
}
readOnly := Contains(opt, "ro") readOnly := Contains(opt, "ro")
if (existingFormat == "" && !readOnly) if (existingFormat == "" && !readOnly)
{ {
@@ -597,7 +602,7 @@ unmap:
{ {
ns.unmapVduseById(vdpaId) ns.unmapVduseById(vdpaId)
} }
return nil, status.Error(codes.Internal, err.Error()) return nil, err
} }
// NodeUnpublishVolume unmounts the volume from the target path // NodeUnpublishVolume unmounts the volume from the target path
@@ -612,7 +617,7 @@ func (ns *NodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpu
{ {
return nil, status.Error(codes.NotFound, "Target path not found") return nil, status.Error(codes.NotFound, "Target path not found")
} }
return nil, status.Error(codes.Internal, err.Error()) return nil, err
} }
if (devicePath == "") if (devicePath == "")
{ {
@@ -625,7 +630,7 @@ func (ns *NodeServer) NodeUnpublishVolume(ctx context.Context, req *csi.NodeUnpu
err = mount.CleanupMountPoint(targetPath, ns.mounter, false) err = mount.CleanupMountPoint(targetPath, ns.mounter, false)
if (err != nil) if (err != nil)
{ {
return nil, status.Error(codes.Internal, err.Error()) return nil, err
} }
// unmap NBD device // unmap NBD device
if (refCount == 1) if (refCount == 1)

View File

@@ -7,7 +7,7 @@ ARG REL=
WORKDIR /root WORKDIR /root
RUN if [ "$REL" = "buster" -o "$REL" = "bullseye" ]; then \ RUN if [ "$REL" = "buster" -o "$REL" = "bullseye" -o "$REL" = "bookworm" ]; then \
echo "deb http://deb.debian.org/debian $REL-backports main" >> /etc/apt/sources.list; \ echo "deb http://deb.debian.org/debian $REL-backports main" >> /etc/apt/sources.list; \
echo >> /etc/apt/preferences; \ echo >> /etc/apt/preferences; \
echo 'Package: *' >> /etc/apt/preferences; \ echo 'Package: *' >> /etc/apt/preferences; \
@@ -45,7 +45,7 @@ RUN set -e; \
rm -rf /root/packages/qemu-$REL/*; \ rm -rf /root/packages/qemu-$REL/*; \
cd /root/packages/qemu-$REL; \ cd /root/packages/qemu-$REL; \
dpkg-source -x /root/qemu*.dsc; \ dpkg-source -x /root/qemu*.dsc; \
QEMU_VER=$(ls -d qemu*/ | perl -pe 's!^.*(\d+\.\d+).*!$1!'); \ QEMU_VER=$(ls -d qemu*/ | perl -pe 's!^.*?(\d+\.\d+).*!$1!'); \
D=$(ls -d qemu*/); \ D=$(ls -d qemu*/); \
cp /root/vitastor/patches/qemu-$QEMU_VER-vitastor.patch ./qemu-*/debian/patches; \ cp /root/vitastor/patches/qemu-$QEMU_VER-vitastor.patch ./qemu-*/debian/patches; \
echo qemu-$QEMU_VER-vitastor.patch >> $D/debian/patches/series; \ echo qemu-$QEMU_VER-vitastor.patch >> $D/debian/patches/series; \

View File

@@ -18,7 +18,7 @@
stable version from 0.9.x branch instead of 1.x stable version from 0.9.x branch instead of 1.x
- For Debian 10 (Buster) also enable backports repository: - For Debian 10 (Buster) also enable backports repository:
`deb http://deb.debian.org/debian buster-backports main` `deb http://deb.debian.org/debian buster-backports main`
- Install packages: `apt update; apt install vitastor lp-solve etcd linux-image-amd64 qemu` - Install packages: `apt update; apt install vitastor lp-solve etcd linux-image-amd64 qemu-system-x86`
## CentOS ## CentOS

View File

@@ -18,7 +18,7 @@
установить последнюю стабильную версию из ветки 0.9.x вместо 1.x установить последнюю стабильную версию из ветки 0.9.x вместо 1.x
- Для Debian 10 (Buster) также включите репозиторий backports: - Для Debian 10 (Buster) также включите репозиторий backports:
`deb http://deb.debian.org/debian buster-backports main` `deb http://deb.debian.org/debian buster-backports main`
- Установите пакеты: `apt update; apt install vitastor lp-solve etcd linux-image-amd64 qemu` - Установите пакеты: `apt update; apt install vitastor lp-solve etcd linux-image-amd64 qemu-system-x86`
## CentOS ## CentOS

View File

@@ -17,6 +17,7 @@ It supports the following commands:
- [purge](#purge) - [purge](#purge)
- [read-sb](#read-sb) - [read-sb](#read-sb)
- [write-sb](#write-sb) - [write-sb](#write-sb)
- [update-sb](#update-sb)
- [udev](#udev) - [udev](#udev)
- [exec-osd](#exec-osd) - [exec-osd](#exec-osd)
- [pre-exec](#pre-exec) - [pre-exec](#pre-exec)
@@ -182,6 +183,14 @@ Try to read Vitastor OSD superblock from `<device>` and print it in JSON format.
Read JSON from STDIN and write it into Vitastor OSD superblock on `<device>`. Read JSON from STDIN and write it into Vitastor OSD superblock on `<device>`.
## update-sb
`vitastor-disk update-sb <device> [--force] [--<parameter> <value>] [...]`
Read Vitastor OSD superblock from <device>, update parameters in it and write it back.
`--force` allows to ignore validation errors.
## udev ## udev
`vitastor-disk udev <device>` `vitastor-disk udev <device>`

View File

@@ -17,6 +17,7 @@ vitastor-disk - инструмент командной строки для уп
- [purge](#purge) - [purge](#purge)
- [read-sb](#read-sb) - [read-sb](#read-sb)
- [write-sb](#write-sb) - [write-sb](#write-sb)
- [update-sb](#update-sb)
- [udev](#udev) - [udev](#udev)
- [exec-osd](#exec-osd) - [exec-osd](#exec-osd)
- [pre-exec](#pre-exec) - [pre-exec](#pre-exec)
@@ -187,6 +188,15 @@ throttle_target_mbs, throttle_target_parallelism, throttle_threshold_us.
Прочитать JSON со стандартного ввода и записать его в суперблок OSD на диск `<device>`. Прочитать JSON со стандартного ввода и записать его в суперблок OSD на диск `<device>`.
## update-sb
`vitastor-disk update-sb <device> [--force] [--<параметр> <значение>] [...]`
Прочитать суперблок OSD с диска `<device>`, изменить в нём заданные параметры и записать обратно.
Опция `--force` позволяет читать суперблок, даже если он считается некорректным
из-за ошибок валидации.
## udev ## udev
`vitastor-disk udev <device>` `vitastor-disk udev <device>`

View File

@@ -146,7 +146,7 @@ Example performance comparison:
| 4k random read Q1 | 9600 iops | 7640 iops | 7780 iops | | 4k random read Q1 | 9600 iops | 7640 iops | 7780 iops |
To try VDUSE you need at least Linux 5.15, built with VDUSE support To try VDUSE you need at least Linux 5.15, built with VDUSE support
(CONFIG_VIRTIO_VDPA=m, CONFIG_VDPA_USER=m, CONFIG_VIRTIO_VDPA=m). (CONFIG_VDPA=m, CONFIG_VDPA_USER=m, CONFIG_VIRTIO_VDPA=m).
Debian Linux kernels have these options disabled by now, so if you want to try it on Debian, Debian Linux kernels have these options disabled by now, so if you want to try it on Debian,
use a kernel from Ubuntu [kernel-ppa/mainline](https://kernel.ubuntu.com/~kernel-ppa/mainline/), Proxmox, use a kernel from Ubuntu [kernel-ppa/mainline](https://kernel.ubuntu.com/~kernel-ppa/mainline/), Proxmox,

View File

@@ -149,7 +149,7 @@ VDUSE - на данный момент лучший интерфейс для п
| 4k случайное чтение Q1 | 9600 iops | 7640 iops | 7780 iops | | 4k случайное чтение Q1 | 9600 iops | 7640 iops | 7780 iops |
Чтобы попробовать VDUSE, вам нужно ядро Linux как минимум версии 5.15, собранное с поддержкой Чтобы попробовать VDUSE, вам нужно ядро Linux как минимум версии 5.15, собранное с поддержкой
VDUSE (CONFIG_VIRTIO_VDPA=m, CONFIG_VDPA_USER=m, CONFIG_VIRTIO_VDPA=m). VDUSE (CONFIG_VDPA=m, CONFIG_VDPA_USER=m, CONFIG_VIRTIO_VDPA=m).
В ядрах в Debian Linux поддержка пока отключена по умолчанию, так что чтобы попробовать VDUSE В ядрах в Debian Linux поддержка пока отключена по умолчанию, так что чтобы попробовать VDUSE
на Debian, поставьте ядро из Ubuntu [kernel-ppa/mainline](https://kernel.ubuntu.com/~kernel-ppa/mainline/), на Debian, поставьте ядро из Ubuntu [kernel-ppa/mainline](https://kernel.ubuntu.com/~kernel-ppa/mainline/),

View File

@@ -732,8 +732,9 @@ int blockstore_init_journal::handle_journal_part(void *buf, uint64_t done_pos, u
resume: resume:
while (pos < bs->journal.block_size) while (pos < bs->journal.block_size)
{ {
journal_entry *je = (journal_entry*)((uint8_t*)buf + proc_pos - done_pos + pos); auto buf_pos = proc_pos - done_pos + pos;
if (je->magic != JOURNAL_MAGIC || je_crc32(je) != je->crc32 || journal_entry *je = (journal_entry*)((uint8_t*)buf + buf_pos);
if (je->magic != JOURNAL_MAGIC || buf_pos+je->size > len || je_crc32(je) != je->crc32 ||
je->type < JE_MIN || je->type > JE_MAX || started && je->crc32_prev != crc32_last) je->type < JE_MIN || je->type > JE_MAX || started && je->crc32_prev != crc32_last)
{ {
if (pos == 0) if (pos == 0)

View File

@@ -127,6 +127,10 @@ static const char *help_text =
"vitastor-disk write-sb <device>\n" "vitastor-disk write-sb <device>\n"
" Read JSON from STDIN and write it into Vitastor OSD superblock on <device>.\n" " Read JSON from STDIN and write it into Vitastor OSD superblock on <device>.\n"
"\n" "\n"
"vitastor-disk update-sb <device> [--force] [--<parameter> <value>] [...]\n"
" Read Vitastor OSD superblock from <device>, update parameters in it and write it back.\n"
" --force allows to ignore validation errors.\n"
"\n"
"vitastor-disk udev <device>\n" "vitastor-disk udev <device>\n"
" Try to read Vitastor OSD superblock from <device> and print variables for udev.\n" " Try to read Vitastor OSD superblock from <device> and print variables for udev.\n"
"\n" "\n"
@@ -363,6 +367,15 @@ int main(int argc, char *argv[])
} }
return self.write_sb(cmd[1]); return self.write_sb(cmd[1]);
} }
else if (!strcmp(cmd[0], "update-sb"))
{
if (cmd.size() != 2)
{
fprintf(stderr, "Exactly 1 device path argument is required\n");
return 1;
}
return self.update_sb(cmd[1]);
}
else if (!strcmp(cmd[0], "start") || !strcmp(cmd[0], "stop") || else if (!strcmp(cmd[0], "start") || !strcmp(cmd[0], "stop") ||
!strcmp(cmd[0], "restart") || !strcmp(cmd[0], "enable") || !strcmp(cmd[0], "disable")) !strcmp(cmd[0], "restart") || !strcmp(cmd[0], "enable") || !strcmp(cmd[0], "disable"))
{ {

View File

@@ -109,6 +109,7 @@ struct disk_tool_t
int udev_import(std::string device); int udev_import(std::string device);
int read_sb(std::string device); int read_sb(std::string device);
int write_sb(std::string device); int write_sb(std::string device);
int update_sb(std::string device);
int exec_osd(std::string device); int exec_osd(std::string device);
int systemd_start_stop_osds(const std::vector<std::string> & cmd, const std::vector<std::string> & devices); int systemd_start_stop_osds(const std::vector<std::string> & cmd, const std::vector<std::string> & devices);
int pre_exec_osd(std::string device); int pre_exec_osd(std::string device);

View File

@@ -86,6 +86,24 @@ int disk_tool_t::write_sb(std::string device)
return !write_osd_superblock(device, params); return !write_osd_superblock(device, params);
} }
int disk_tool_t::update_sb(std::string device)
{
json11::Json sb = read_osd_superblock(device, true, options.find("force") != options.end());
if (sb.is_null())
{
return 1;
}
auto sb_obj = sb["params"].object_items();
for (auto & kv: options)
{
if (kv.first != "force")
{
sb_obj[kv.first] = kv.second;
}
}
return !write_osd_superblock(device, sb_obj);
}
uint32_t disk_tool_t::write_osd_superblock(std::string device, json11::Json params) uint32_t disk_tool_t::write_osd_superblock(std::string device, json11::Json params)
{ {
std::string json_data = params.dump(); std::string json_data = params.dump();

View File

@@ -135,8 +135,8 @@ void etcd_state_client_t::etcd_call(std::string api, json11::Json payload, int t
{ {
if (this->log_level > 0) if (this->log_level > 0)
{ {
printf( fprintf(
"Warning: etcd request failed: %s, retrying %d more times\n", stderr, "Warning: etcd request failed: %s, retrying %d more times\n",
err.c_str(), retries err.c_str(), retries
); );
} }
@@ -333,7 +333,7 @@ void etcd_state_client_t::start_etcd_watcher()
etcd_watch_ws = NULL; etcd_watch_ws = NULL;
} }
if (this->log_level > 1) if (this->log_level > 1)
printf("Trying to connect to etcd websocket at %s\n", etcd_address.c_str()); fprintf(stderr, "Trying to connect to etcd websocket at %s\n", etcd_address.c_str());
etcd_watch_ws = open_websocket(tfd, etcd_address, etcd_api_path+"/watch", etcd_slow_timeout, etcd_watch_ws = open_websocket(tfd, etcd_address, etcd_api_path+"/watch", etcd_slow_timeout,
[this, cur_addr = selected_etcd_address](const http_response_t *msg) [this, cur_addr = selected_etcd_address](const http_response_t *msg)
{ {