dovecot-2.2: director: Added support for backend cluster "tags".
dovecot at dovecot.org
dovecot at dovecot.org
Wed Nov 12 04:59:53 UTC 2014
details: http://hg.dovecot.org/dovecot-2.2/rev/a7e830b9b967
changeset: 18067:a7e830b9b967
user: Timo Sirainen <tss at iki.fi>
date: Wed Nov 12 06:58:37 2014 +0200
description:
director: Added support for backend cluster "tags".
This allows using a single director ring for multiple backend clusters. By
default everything has an empty tag. A passdb lookup can return
"director_tag" field containing the wanted tag name. If there aren't any
backend servers with the wanted tag, it's treated the same as if there
aren't any backend servers available (= wait for 30 secs for a backend and
then return temporary failure).
Tags can be added to configuration by adding @tag suffix to IPs/hosts. For
example:
director_mail_servers = 10.0.0.100-10.0.0.110 at name1 10.0.0.120 at name2
"doveadm director add" can also add tags either with @tag suffix or with -t
parameter. "doveadm director status user at domain" requires giving the user's
correct tag with -t parameter or the results won't be correct (empty tag's
results are shown). Tags can't currently be changed for an existing host
without removing it first.
diffstat:
src/director/director-connection.c | 22 +++++++-
src/director/director-request.c | 29 ++++++++--
src/director/director-request.h | 1 +
src/director/director.c | 26 ++++++++-
src/director/director.h | 2 +
src/director/doveadm-connection.c | 38 ++++++++++++---
src/director/login-connection.c | 6 +-
src/director/mail-host.c | 94 +++++++++++++++++++++++++++++--------
src/director/mail-host.h | 9 ++-
src/director/main.c | 3 +-
src/doveadm/doveadm-director.c | 47 +++++++++++++-----
11 files changed, 214 insertions(+), 63 deletions(-)
diffs (truncated from 776 to 300 lines):
diff -r 26679856fbd5 -r a7e830b9b967 src/director/director-connection.c
--- a/src/director/director-connection.c Wed Nov 12 06:46:45 2014 +0200
+++ b/src/director/director-connection.c Wed Nov 12 06:58:37 2014 +0200
@@ -35,6 +35,7 @@
#include "istream.h"
#include "ostream.h"
#include "str.h"
+#include "strescape.h"
#include "master-service.h"
#include "mail-host.h"
#include "director.h"
@@ -821,15 +822,18 @@
{
struct mail_host *host;
struct ip_addr ip;
+ const char *tag = "";
unsigned int vhost_count;
bool update;
- if (str_array_length(args) != 2 ||
+ if (str_array_length(args) < 2 ||
net_addr2ip(args[0], &ip) < 0 ||
str_to_uint(args[1], &vhost_count) < 0) {
director_cmd_error(conn, "Invalid parameters");
return FALSE;
}
+ if (args[2] != NULL)
+ tag = args[2];
if (conn->ignore_host_events) {
/* remote is sending hosts in a handshake, but it doesn't have
a completed ring and we do. */
@@ -839,10 +843,17 @@
host = mail_host_lookup(conn->dir->mail_hosts, &ip);
if (host == NULL) {
- host = mail_host_add_ip(conn->dir->mail_hosts, &ip);
+ host = mail_host_add_ip(conn->dir->mail_hosts, &ip, tag);
update = TRUE;
} else {
update = host->vhost_count != vhost_count;
+ if (strcmp(tag, host->tag) != 0) {
+ i_error("director(%s): Host %s changed tag from '%s' to '%s'",
+ conn->name, net_ip2addr(&host->ip),
+ host->tag, tag);
+ mail_host_set_tag(host, tag);
+ update = TRUE;
+ }
}
if (update) {
@@ -1541,8 +1552,13 @@
str_printfa(str, "HOST-HAND-START\t%u\n", conn->dir->ring_handshaked);
array_foreach(mail_hosts_get(conn->dir->mail_hosts), hostp) {
- str_printfa(str, "HOST\t%s\t%u\n",
+ str_printfa(str, "HOST\t%s\t%u",
net_ip2addr(&(*hostp)->ip), (*hostp)->vhost_count);
+ if ((*hostp)->tag[0] != '\0') {
+ str_append_c(str, '\t');
+ str_append_tabescaped(str, (*hostp)->tag);
+ }
+ str_append_c(str, '\n');
}
str_printfa(str, "HOST-HAND-END\t%u\n", conn->dir->ring_handshaked);
}
diff -r 26679856fbd5 -r a7e830b9b967 src/director/director-request.c
--- a/src/director/director-request.c Wed Nov 12 06:46:45 2014 +0200
+++ b/src/director/director-request.c Wed Nov 12 06:58:37 2014 +0200
@@ -36,11 +36,18 @@
time_t create_time;
unsigned int username_hash;
enum director_request_delay_reason delay_reason;
+ char *username_tag;
director_request_callback *callback;
void *context;
};
+static void director_request_free(struct director_request *request)
+{
+ i_free(request->username_tag);
+ i_free(request);
+}
+
static const char *
director_request_get_timeout_error(struct director_request *request,
struct user *user, string_t *str)
@@ -68,7 +75,10 @@
str_printfa(str, ", user refreshed %u secs ago",
(unsigned int)(ioloop_time - user->timestamp));
}
- str_printfa(str, "hash=%u)", request->username_hash);
+ str_printfa(str, ", hash=%u", request->username_hash);
+ if (request->username_tag != NULL)
+ str_printfa(str, ", tag=%s", request->username_tag);
+ str_append_c(str, ')');
return str_c(str);
}
@@ -103,7 +113,7 @@
T_BEGIN {
request->callback(NULL, errormsg, request->context);
} T_END;
- i_free(request);
+ director_request_free(request);
}
if (array_count(&dir->pending_requests) == 0 && dir->to_request != NULL)
@@ -111,6 +121,7 @@
}
void director_request(struct director *dir, const char *username,
+ const char *tag,
director_request_callback *callback, void *context)
{
struct director_request *request;
@@ -121,6 +132,7 @@
request->dir = dir;
request->create_time = ioloop_time;
request->username_hash = username_hash;
+ request->username_tag = tag[0] == '\0' ? NULL : i_strdup(tag);
request->callback = callback;
request->context = context;
@@ -159,7 +171,8 @@
}
static bool
-director_request_existing(struct director_request *request, struct user *user)
+director_request_existing(struct director_request *request, struct user *user,
+ const char *tag)
{
struct director *dir = request->dir;
struct mail_host *host;
@@ -193,7 +206,7 @@
/* user is close to being expired. another director may have
already expired it. */
- host = mail_host_get_by_hash(dir->mail_hosts, user->username_hash);
+ host = mail_host_get_by_hash(dir->mail_hosts, user->username_hash, tag);
if (!dir->ring_synced) {
/* try again later once ring is synced */
request->delay_reason = REQUEST_DELAY_RINGNOTSYNCED;
@@ -253,6 +266,7 @@
struct director *dir = request->dir;
struct mail_host *host;
struct user *user;
+ const char *tag;
if (!dir->ring_handshaked) {
/* delay requests until ring handshaking is complete */
@@ -264,8 +278,9 @@
}
user = user_directory_lookup(dir->users, request->username_hash);
+ tag = request->username_tag == NULL ? "" : request->username_tag;
if (user != NULL) {
- if (!director_request_existing(request, user))
+ if (!director_request_existing(request, user, tag))
return FALSE;
user_directory_refresh(dir->users, user);
dir_debug("request: %u refreshed timeout to %u",
@@ -280,7 +295,7 @@
return FALSE;
}
host = mail_host_get_by_hash(dir->mail_hosts,
- request->username_hash);
+ request->username_hash, tag);
if (host == NULL) {
/* all hosts have been removed */
request->delay_reason = REQUEST_DELAY_NOHOSTS;
@@ -299,6 +314,6 @@
T_BEGIN {
request->callback(&user->host->ip, NULL, request->context);
} T_END;
- i_free(request);
+ director_request_free(request);
return TRUE;
}
diff -r 26679856fbd5 -r a7e830b9b967 src/director/director-request.h
--- a/src/director/director-request.h Wed Nov 12 06:46:45 2014 +0200
+++ b/src/director/director-request.h Wed Nov 12 06:58:37 2014 +0200
@@ -9,6 +9,7 @@
void *context);
void director_request(struct director *dir, const char *username,
+ const char *tag,
director_request_callback *callback, void *context);
bool director_request_continue(struct director_request *request);
diff -r 26679856fbd5 -r a7e830b9b967 src/director/director.c
--- a/src/director/director.c Wed Nov 12 06:46:45 2014 +0200
+++ b/src/director/director.c Wed Nov 12 06:58:37 2014 +0200
@@ -4,6 +4,7 @@
#include "ioloop.h"
#include "array.h"
#include "str.h"
+#include "strescape.h"
#include "ipc-client.h"
#include "user-directory.h"
#include "mail-host.h"
@@ -503,6 +504,8 @@
struct director_host *orig_src,
struct mail_host *host)
{
+ string_t *str;
+
/* update state in case this is the first mail host being added */
director_set_state_changed(dir);
@@ -511,10 +514,25 @@
orig_src->last_seq++;
}
- director_update_send(dir, src, t_strdup_printf(
- "HOST\t%s\t%u\t%u\t%s\t%u\n",
- net_ip2addr(&orig_src->ip), orig_src->port, orig_src->last_seq,
- net_ip2addr(&host->ip), host->vhost_count));
+ str = t_str_new(128);
+ str_printfa(str, "HOST\t%s\t%u\t%u\t%s\t%u",
+ net_ip2addr(&orig_src->ip), orig_src->port,
+ orig_src->last_seq,
+ net_ip2addr(&host->ip), host->vhost_count);
+ if (host->tag[0] == '\0')
+ ;
+ else if (dir->ring_handshaked &&
+ dir->ring_min_version < DIRECTOR_VERSION_TAGS) {
+ i_error("Ring has directors that don't support tags - removing host %s with tag '%s'",
+ net_ip2addr(&host->ip), host->tag);
+ director_remove_host(dir, NULL, NULL, host);
+ return;
+ } else {
+ str_append_c(str, '\t');
+ str_append_tabescaped(str, host->tag);
+ }
+ str_append_c(str, '\n');
+ director_update_send(dir, src, str_c(str));
director_sync(dir);
}
diff -r 26679856fbd5 -r a7e830b9b967 src/director/director.h
--- a/src/director/director.h Wed Nov 12 06:46:45 2014 +0200
+++ b/src/director/director.h Wed Nov 12 06:58:37 2014 +0200
@@ -18,6 +18,8 @@
#define DIRECTOR_VERSION_USER_KICK 4
/* options supported in handshake */
#define DIRECTOR_VERSION_OPTIONS 5
+/* user tags supported */
+#define DIRECTOR_VERSION_TAGS 5
/* Minimum time between even attempting to communicate with a director that
failed due to a protocol error. */
diff -r 26679856fbd5 -r a7e830b9b967 src/director/doveadm-connection.c
--- a/src/director/doveadm-connection.c Wed Nov 12 06:46:45 2014 +0200
+++ b/src/director/doveadm-connection.c Wed Nov 12 06:58:37 2014 +0200
@@ -7,6 +7,7 @@
#include "ostream.h"
#include "array.h"
#include "str.h"
+#include "strescape.h"
#include "llist.h"
#include "master-service.h"
#include "user-directory.h"
@@ -46,9 +47,11 @@
string_t *str = t_str_new(1024);
array_foreach(mail_hosts_get(conn->dir->mail_hosts), hostp) {
- str_printfa(str, "%s\t%u\t%u\n",
+ str_printfa(str, "%s\t%u\t%u\t",
net_ip2addr(&(*hostp)->ip), (*hostp)->vhost_count,
(*hostp)->user_count);
+ str_append_tabescaped(str, (*hostp)->tag);
+ str_append_c(str, '\n');
}
str_append_c(str, '\n');
o_stream_nsend(conn->output, str_data(str), str_len(str));
@@ -244,14 +247,21 @@
doveadm_cmd_host_set(struct doveadm_connection *conn, const char *line)
{
struct director *dir = conn->dir;
- const char *const *args;
+ const char *const *args, *ip_str, *tag = "";
struct mail_host *host;
struct ip_addr ip;
unsigned int vhost_count = UINT_MAX;
args = t_strsplit_tab(line);
- if (args[0] == NULL ||
- net_addr2ip(args[0], &ip) < 0 ||
+ ip_str = args[0];
+ if (ip_str != NULL) {
+ tag = strchr(ip_str, '@');
+ if (tag == NULL)
+ tag = "";
+ else
+ ip_str = t_strdup_until(ip_str, tag++);
+ }
+ if (ip_str == NULL || net_addr2ip(ip_str, &ip) < 0 ||
(args[1] != NULL && str_to_uint(args[1], &vhost_count) < 0)) {
i_error("doveadm sent invalid HOST-SET parameters: %s", line);
More information about the dovecot-cvs
mailing list