support volfile fetch from multiple glusterd nodes
authorRaghavendra Talur <rtalur@redhat.com>
Thu, 25 Aug 2016 10:33:55 +0000 (16:03 +0530)
committerGünther Deschner <gd@samba.org>
Fri, 14 Oct 2016 15:09:24 +0000 (17:09 +0200)
glusterfs:volfile_server option can be used in smb.conf to define where
to fetch the volfile from. Currently it supports only a single IP or a
hostname. The default is 'localhost'.

glfs_set_volfile_server() has been enhanced in gfapi to support
multiple invocations. A list is maintained in libgfapi which gets
appended on every invocation. When glfs_init is performed, libgfapi
would first try to fetch the volfile from glusterd on that node.
However, on failure to fetch the volfile, it would proceed to contact
glusterd on every node in the list until it gets the volfile or
exhausts the list. This enhacement was done in Gluster commit [2].
This commit is available in 3.6, 3.7, 3.8 versions of Gluster.

As we cannot have multiple lines having the same key of
glusterfs:volfile_server in a share definition in smb.conf, we propose
a scheme like this:

where value of glusterfs:volfile_server could be list of white space seperated
elements where each element could be unix+/path/to/socket/file or
[tcp+]IP|hostname|\[IPv6\][:port].

Note the restriction on naming a IPv6 host, it follows the same
restriction that is based on IPv6 naming in URL as per RFC 2732[1].

[1] http://www.ietf.org/rfc/rfc2732.txt
[2] 0c1d78f5c52c69268ec3a1d8d5fcb1a1bf15f243

Signed-off-by: Raghavendra Talur <rtalur@redhat.com>
Reviewed-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Michael Adam <obnox@samba.org>
Reviewed-by: Guenther Deschner <gd@samba.org>
Autobuild-User(master): Günther Deschner <gd@samba.org>
Autobuild-Date(master): Fri Oct 14 17:09:24 CEST 2016 on sn-devel-144

docs-xml/manpages/vfs_glusterfs.8.xml
source3/modules/vfs_glusterfs.c

index 5e18e533c2adec7ed2fe59d85d4b00d7d64d8981..5e67f715b21c24bd2a7dbde563c6566257c32cd1 100644 (file)
                <listitem>
                <para>
                        Defines which volfile server to use, defaults to
-                       localhost.
+                       localhost. It could be list of white space
+                       seperated elements where each element could be
+               </para>
+               <para>
+                       1. unix+/path/to/socket/file
+               </para>
+               <para>
+                       2. [tcp+]IP|hostname|\[IPv6\][:port]
+               </para>
+               <para>
+                       Note the restriction on naming a IPv6 host, it follows
+                       the same restriction that is based on IPv6 naming in
+                       URL as per RFC 2732.
                </para>
                </listitem>
                </varlistentry>
        <title>VERSION</title>
 
        <para>
-               This man page is correct for version 4.2.0 of the Samba suite.
+               This man page is correct for version 4.6.0 of the Samba suite.
        </para>
 </refsect1>
 
index b0ff0f61ca35454d6bf82f1df83e7a5d54719075..3e15ce6ff98ee6572c32ec0c2d5a9ed1755d920e 100644 (file)
@@ -157,13 +157,116 @@ static void glfs_clear_preopened(glfs_t *fs)
        }
 }
 
+static int vfs_gluster_set_volfile_servers(glfs_t *fs,
+                                          const char *volfile_servers)
+{
+       char *server = NULL;
+       int   server_count = 0;
+       int   server_success = 0;
+       int   ret = -1;
+       TALLOC_CTX *frame = talloc_stackframe();
+
+       DBG_INFO("servers list %s\n", volfile_servers);
+
+       while (next_token_talloc(frame, &volfile_servers, &server, " \t")) {
+               char *transport = NULL;
+               char *host = NULL;
+               int   port = 0;
+
+               server_count++;
+               DBG_INFO("server %d %s\n", server_count, server);
+
+               /* Determine the transport type */
+               if (strncmp(server, "unix+", 5) == 0) {
+                       port = 0;
+                       transport = talloc_strdup(frame, "unix");
+                       if (!transport) {
+                               errno = ENOMEM;
+                               goto out;
+                       }
+                       host = talloc_strdup(frame, server + 5);
+                       if (!host) {
+                               errno = ENOMEM;
+                               goto out;
+                       }
+               } else {
+                       char *p = NULL;
+                       char *port_index = NULL;
+
+                       if (strncmp(server, "tcp+", 4) == 0) {
+                               server += 4;
+                       }
+
+                       /* IPv6 is enclosed in []
+                        * ':' before ']' is part of IPv6
+                        * ':' after  ']' indicates port
+                        */
+                       p = server;
+                       if (server[0] == '[') {
+                               server++;
+                               p = index(server, ']');
+                               if (p == NULL) {
+                                       /* Malformed IPv6 */
+                                       continue;
+                               }
+                               p[0] = '\0';
+                               p++;
+                       }
+
+                       port_index = index(p, ':');
+
+                       if (port_index == NULL) {
+                               port = 0;
+                       } else {
+                               port = atoi(port_index + 1);
+                               port_index[0] = '\0';
+                       }
+                       transport = talloc_strdup(frame, "tcp");
+                       if (!transport) {
+                               errno = ENOMEM;
+                               goto out;
+                       }
+                       host = talloc_strdup(frame, server);
+                       if (!host) {
+                               errno = ENOMEM;
+                               goto out;
+                       }
+               }
+
+               DBG_INFO("Calling set volfile server with params "
+                        "transport=%s, host=%s, port=%d\n", transport,
+                         host, port);
+
+               ret = glfs_set_volfile_server(fs, transport, host, port);
+               if (ret < 0) {
+                       DBG_WARNING("Failed to set volfile_server "
+                                   "transport=%s, host=%s, port=%d (%s)\n",
+                                   transport, host, port, strerror(errno));
+               } else {
+                       server_success++;
+               }
+       }
+
+out:
+       if (server_count == 0) {
+               ret = -1;
+       } else if (server_success < server_count) {
+               DBG_WARNING("Failed to set %d out of %d servers parsed\n",
+                           server_count - server_success, server_count);
+               ret = 0;
+       }
+
+       TALLOC_FREE(frame);
+       return ret;
+}
+
 /* Disk Operations */
 
 static int vfs_gluster_connect(struct vfs_handle_struct *handle,
                               const char *service,
                               const char *user)
 {
-       const char *volfile_server;
+       const char *volfile_servers;
        const char *volume;
        char *logfile;
        int loglevel;
@@ -181,10 +284,11 @@ static int vfs_gluster_connect(struct vfs_handle_struct *handle,
 
        loglevel = lp_parm_int(SNUM(handle->conn), "glusterfs", "loglevel", -1);
 
-       volfile_server = lp_parm_const_string(SNUM(handle->conn), "glusterfs",
-                                              "volfile_server", NULL);
-       if (volfile_server == NULL) {
-               volfile_server = DEFAULT_VOLFILE_SERVER;
+       volfile_servers = lp_parm_talloc_string(tmp_ctx, SNUM(handle->conn),
+                                              "glusterfs", "volfile_server",
+                                              NULL);
+       if (volfile_servers == NULL) {
+               volfile_servers = DEFAULT_VOLFILE_SERVER;
        }
 
        volume = lp_parm_const_string(SNUM(handle->conn), "glusterfs", "volume",
@@ -204,9 +308,10 @@ static int vfs_gluster_connect(struct vfs_handle_struct *handle,
                goto done;
        }
 
-       ret = glfs_set_volfile_server(fs, "tcp", volfile_server, 0);
+       ret = vfs_gluster_set_volfile_servers(fs, volfile_servers);
        if (ret < 0) {
-               DEBUG(0, ("Failed to set volfile_server %s\n", volfile_server));
+               DBG_ERR("Failed to set volfile_servers from list %s\n",
+                       volfile_servers);
                goto done;
        }
 
@@ -248,17 +353,16 @@ static int vfs_gluster_connect(struct vfs_handle_struct *handle,
                goto done;
        }
 done:
-       talloc_free(tmp_ctx);
        if (ret < 0) {
                if (fs)
                        glfs_fini(fs);
-               return -1;
        } else {
-               DEBUG(0, ("%s: Initialized volume from server %s\n",
-                         volume, volfile_server));
+               DBG_ERR("%s: Initialized volume from servers %s\n",
+                       volume, volfile_servers);
                handle->data = fs;
-               return 0;
        }
+       talloc_free(tmp_ctx);
+       return ret;
 }
 
 static void vfs_gluster_disconnect(struct vfs_handle_struct *handle)