/* Copyright (c) 2014 Red Hat, Inc. This file is part of GlusterFS. This file is licensed to you under your choice of the GNU Lesser General Public License, version 3 or any later version (LGPLv3 or later), or the GNU General Public License, version 2 (GPLv2), in all cases as published by the Free Software Foundation. */ #include "globals.h" #include "run.h" #include "glusterd-utils.h" #include "glusterd-volgen.h" #include "glusterd-messages.h" #include "glusterd-svc-mgmt.h" #include "glusterd-svc-helper.h" #include "glusterd-conn-mgmt.h" #include "glusterd-proc-mgmt.h" #include "glusterd-snapd-svc.h" #include "glusterd-snapd-svc-helper.h" #include "glusterd-snapshot-utils.h" char *snapd_svc_name = "snapd"; static void glusterd_svc_build_snapd_logdir (char *logdir, char *volname, size_t len) { snprintf (logdir, len, "%s/snaps/%s", DEFAULT_LOG_FILE_DIRECTORY, volname); } static void glusterd_svc_build_snapd_logfile (char *logfile, char *logdir, size_t len) { snprintf (logfile, len, "%s/snapd.log", logdir); } int glusterd_snapdsvc_init (void *data) { int ret = -1; char rundir[PATH_MAX] = {0,}; char sockpath[PATH_MAX] = {0,}; char pidfile[PATH_MAX] = {0,}; char volfile[PATH_MAX] = {0,}; char logdir[PATH_MAX] = {0,}; char logfile[PATH_MAX] = {0,}; char volfileid[256] = {0}; glusterd_svc_t *svc = NULL; glusterd_volinfo_t *volinfo = NULL; glusterd_conf_t *priv = NULL; glusterd_conn_notify_t notify = NULL; xlator_t *this = NULL; char *volfileserver = NULL; this = THIS; GF_ASSERT (this); priv = this->private; GF_ASSERT (priv); volinfo = data; svc = &(volinfo->snapd.svc); ret = snprintf (svc->name, sizeof (svc->name), "%s", snapd_svc_name); if (ret < 0) goto out; svc->manager = glusterd_snapdsvc_manager; svc->start = glusterd_snapdsvc_start; svc->stop = glusterd_svc_stop; notify = glusterd_snapdsvc_rpc_notify; glusterd_svc_build_snapd_rundir (volinfo, rundir, sizeof (rundir)); glusterd_svc_create_rundir (rundir); /* Initialize the connection mgmt */ glusterd_svc_build_snapd_socket_filepath (volinfo, sockpath, sizeof (sockpath)); ret = glusterd_conn_init (&(svc->conn), sockpath, 600, notify); if (ret) goto out; /* Initialize the process mgmt */ glusterd_svc_build_snapd_pidfile (volinfo, pidfile, sizeof (pidfile)); glusterd_svc_build_snapd_volfile (volinfo, volfile, sizeof (volfile)); glusterd_svc_build_snapd_logdir (logdir, volinfo->volname, sizeof (logdir)); ret = mkdir_p (logdir, 0755, _gf_true); if ((ret == -1) && (EEXIST != errno)) { gf_log (this->name, GF_LOG_ERROR, "Unable to create logdir %s", logdir); goto out; } glusterd_svc_build_snapd_logfile (logfile, logdir, sizeof (logfile)); snprintf (volfileid, sizeof (volfileid), "snapd/%s", volinfo->volname); if (dict_get_str (this->options, "transport.socket.bind-address", &volfileserver) != 0) { volfileserver = "localhost"; } ret = glusterd_proc_init (&(svc->proc), snapd_svc_name, pidfile, logdir, logfile, volfile, volfileid, volfileserver); if (ret) goto out; out: gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } int glusterd_snapdsvc_manager (glusterd_svc_t *svc, void *data, int flags) { int ret = 0; xlator_t *this = THIS; glusterd_volinfo_t *volinfo = NULL; volinfo = data; ret = glusterd_is_snapd_enabled (volinfo); if (ret == -1) { gf_log (this->name, GF_LOG_ERROR, "Failed to read volume " "options"); goto out; } if (ret) { if (!glusterd_is_volume_started (volinfo)) { if (glusterd_proc_is_running (&svc->proc)) { ret = svc->stop (svc, SIGTERM); if (ret) gf_log (this->name, GF_LOG_ERROR, "Couldn't stop snapd for " "volume: %s", volinfo->volname); } else { /* Since snapd is not running set ret to 0 */ ret = 0; } goto out; } ret = glusterd_snapdsvc_create_volfile (volinfo); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Couldn't create " "snapd volfile for volume: %s", volinfo->volname); goto out; } ret = svc->start (svc, flags); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Couldn't start " "snapd for volume: %s", volinfo->volname); goto out; } glusterd_volinfo_ref (volinfo); ret = glusterd_conn_connect (&(svc->conn)); if (ret) { glusterd_volinfo_unref (volinfo); goto out; } } else if (glusterd_proc_is_running (&svc->proc)) { ret = svc->stop (svc, SIGTERM); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Couldn't stop snapd for volume: %s", volinfo->volname); goto out; } volinfo->snapd.port = 0; } out: gf_log (THIS->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } int32_t glusterd_snapdsvc_start (glusterd_svc_t *svc, int flags) { int ret = -1; runner_t runner = {0,}; glusterd_conf_t *priv = NULL; xlator_t *this = NULL; char valgrind_logfile[PATH_MAX] = {0}; int snapd_port = 0; char msg[1024] = {0,}; char snapd_id[PATH_MAX] = {0,}; glusterd_volinfo_t *volinfo = NULL; glusterd_snapdsvc_t *snapd = NULL; this = THIS; GF_ASSERT(this); priv = this->private; GF_ASSERT (priv); if (glusterd_proc_is_running (&svc->proc)) { ret = 0; goto out; } /* Get volinfo->snapd from svc object */ snapd = cds_list_entry (svc, glusterd_snapdsvc_t, svc); if (!snapd) { gf_log (this->name, GF_LOG_ERROR, "Failed to get snapd object " "from snapd service"); goto out; } /* Get volinfo from snapd */ volinfo = cds_list_entry (snapd, glusterd_volinfo_t, snapd); if (!volinfo) { gf_log (this->name, GF_LOG_ERROR, "Failed to get volinfo from " "from snapd"); goto out; } ret = access (svc->proc.volfile, F_OK); if (ret) { gf_log (this->name, GF_LOG_DEBUG, "snapd Volfile %s is not present", svc->proc.volfile); /* If glusterd is down on one of the nodes and during * that time "USS is enabled" for the first time. After some * time when the glusterd which was down comes back it tries * to look for the snapd volfile and it does not find snapd * volfile and because of this starting of snapd fails. * Therefore, if volfile is not present then create a fresh * volfile. */ ret = glusterd_snapdsvc_create_volfile (volinfo); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Couldn't create " "snapd volfile for volume: %s", volinfo->volname); goto out; } } runinit (&runner); if (priv->valgrind) { snprintf (valgrind_logfile, PATH_MAX, "%s/valgrind-snapd.log", svc->proc.logdir); runner_add_args (&runner, "valgrind", "--leak-check=full", "--trace-children=yes", "--track-origins=yes", NULL); runner_argprintf (&runner, "--log-file=%s", valgrind_logfile); } snprintf (snapd_id, sizeof (snapd_id), "snapd-%s", volinfo->volname); runner_add_args (&runner, SBIN_DIR"/glusterfsd", "-s", svc->proc.volfileserver, "--volfile-id", svc->proc.volfileid, "-p", svc->proc.pidfile, "-l", svc->proc.logfile, "--brick-name", snapd_id, "-S", svc->conn.sockpath, NULL); snapd_port = volinfo->snapd.port; if (!snapd_port) { snapd_port = pmap_registry_alloc (THIS); if (!snapd_port) { snprintf (msg, sizeof (msg), "Could not allocate port " "for snapd service for volume %s", volinfo->volname); runner_log (&runner, this->name, GF_LOG_DEBUG, msg); ret = -1; goto out; } } runner_add_arg (&runner, "--brick-port"); runner_argprintf (&runner, "%d", snapd_port); runner_add_arg (&runner, "--xlator-option"); runner_argprintf (&runner, "%s-server.listen-port=%d", volinfo->volname, snapd_port); runner_add_arg (&runner, "--no-mem-accounting"); snprintf (msg, sizeof (msg), "Starting the snapd service for volume %s", volinfo->volname); runner_log (&runner, this->name, GF_LOG_DEBUG, msg); if (flags == PROC_START_NO_WAIT) { ret = runner_run_nowait (&runner); } else { synclock_unlock (&priv->big_lock); { ret = runner_run (&runner); } synclock_lock (&priv->big_lock); } volinfo->snapd.port = snapd_port; out: return ret; } int glusterd_snapdsvc_restart () { glusterd_volinfo_t *volinfo = NULL; int ret = 0; xlator_t *this = THIS; glusterd_conf_t *conf = NULL; glusterd_svc_t *svc = NULL; GF_ASSERT (this); conf = this->private; GF_ASSERT (conf); cds_list_for_each_entry (volinfo, &conf->volumes, vol_list) { /* Start per volume snapd svc */ if (volinfo->status == GLUSTERD_STATUS_STARTED && glusterd_is_snapd_enabled (volinfo)) { svc = &(volinfo->snapd.svc); ret = svc->start (svc, PROC_START_NO_WAIT); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Couldn't start snapd for " "vol: %s", volinfo->volname); goto out; } } } out: return ret; } int glusterd_snapdsvc_rpc_notify (glusterd_conn_t *conn, rpc_clnt_event_t event) { int ret = 0; glusterd_svc_t *svc = NULL; xlator_t *this = NULL; glusterd_volinfo_t *volinfo = NULL; glusterd_snapdsvc_t *snapd = NULL; this = THIS; GF_ASSERT (this); svc = cds_list_entry (conn, glusterd_svc_t, conn); if (!svc) { gf_log (this->name, GF_LOG_ERROR, "Failed to get the service"); return -1; } switch (event) { case RPC_CLNT_CONNECT: gf_log (this->name, GF_LOG_DEBUG, "%s has connected with " "glusterd.", svc->name); svc->online = _gf_true; break; case RPC_CLNT_DISCONNECT: if (svc->online) { gf_msg (this->name, GF_LOG_INFO, 0, GD_MSG_NODE_DISCONNECTED, "%s has disconnected " "from glusterd.", svc->name); svc->online = _gf_false; } break; case RPC_CLNT_DESTROY: snapd = cds_list_entry (svc, glusterd_snapdsvc_t, svc); if (!snapd) { gf_log (this->name, GF_LOG_ERROR, "Failed to get the " "snapd object"); return -1; } volinfo = cds_list_entry (snapd, glusterd_volinfo_t, snapd); if (!volinfo) { gf_log (this->name, GF_LOG_ERROR, "Failed to get the " "volinfo object"); return -1; } glusterd_volinfo_unref (volinfo); default: gf_log (this->name, GF_LOG_TRACE, "got some other RPC event %d", event); break; } return ret; }