glusterfs

Форк
0
/
glusterd-hooks.c 
625 строк · 16.8 Кб
1
/*
2
   Copyright (c) 2007-2012 Red Hat, Inc. <http://www.redhat.com>
3
   This file is part of GlusterFS.
4

5
   This file is licensed to you under your choice of the GNU Lesser
6
   General Public License, version 3 or any later version (LGPLv3 or
7
   later), or the GNU General Public License, version 2 (GPLv2), in all
8
   cases as published by the Free Software Foundation.
9
*/
10

11
#include <glusterfs/dict.h>
12
#include <glusterfs/logging.h>
13
#include <glusterfs/run.h>
14
#include <glusterfs/syscall.h>
15
#include <glusterfs/compat.h>
16
#include <glusterfs/compat-errno.h>
17
#include "glusterd-sm.h"
18
#include "glusterd-op-sm.h"
19
#include "glusterd-utils.h"
20
#include "glusterd-store.h"
21
#include "glusterd-hooks.h"
22
#include "glusterd-messages.h"
23

24
#include <fnmatch.h>
25

26
#define EMPTY ""
27
char glusterd_hook_dirnames[GD_OP_MAX][256] = {
28
    [GD_OP_NONE] = EMPTY,
29
    [GD_OP_CREATE_VOLUME] = "create",
30
    [GD_OP_START_BRICK] = EMPTY,
31
    [GD_OP_STOP_BRICK] = EMPTY,
32
    [GD_OP_DELETE_VOLUME] = "delete",
33
    [GD_OP_START_VOLUME] = "start",
34
    [GD_OP_STOP_VOLUME] = "stop",
35
    [GD_OP_DEFRAG_VOLUME] = EMPTY,
36
    [GD_OP_ADD_BRICK] = "add-brick",
37
    [GD_OP_REMOVE_BRICK] = "remove-brick",
38
    [GD_OP_REPLACE_BRICK] = EMPTY,
39
    [GD_OP_SET_VOLUME] = "set",
40
    [GD_OP_RESET_VOLUME] = "reset",
41
    [GD_OP_SYNC_VOLUME] = EMPTY,
42
    [GD_OP_LOG_ROTATE] = EMPTY,
43
    [GD_OP_GSYNC_CREATE] = "gsync-create",
44
    [GD_OP_GSYNC_SET] = EMPTY,
45
    [GD_OP_PROFILE_VOLUME] = EMPTY,
46
    [GD_OP_QUOTA] = EMPTY,
47
    [GD_OP_STATUS_VOLUME] = EMPTY,
48
    [GD_OP_REBALANCE] = EMPTY,
49
    [GD_OP_HEAL_VOLUME] = EMPTY,
50
    [GD_OP_STATEDUMP_VOLUME] = EMPTY,
51
    [GD_OP_LIST_VOLUME] = EMPTY,
52
    [GD_OP_CLEARLOCKS_VOLUME] = EMPTY,
53
    [GD_OP_DEFRAG_BRICK_VOLUME] = EMPTY,
54
    [GD_OP_RESET_BRICK] = EMPTY,
55
};
56
#undef EMPTY
57

58
static gf_boolean_t
59
glusterd_is_hook_enabled(char *script)
60
{
61
    return (script[0] == 'S' && (fnmatch("*.rpmsave", script, 0) != 0) &&
62
            (fnmatch("*.rpmnew", script, 0) != 0));
63
}
64

65
int
66
glusterd_hooks_create_hooks_directory(char *basedir)
67
{
68
    int ret = -1;
69
    int op = GD_OP_NONE;
70
    int type = GD_COMMIT_HOOK_NONE;
71
    char version_dir[PATH_MAX] = {
72
        0,
73
    };
74
    char path[PATH_MAX] = {
75
        0,
76
    };
77
    char *cmd_subdir = NULL;
78
    char type_subdir[GD_COMMIT_HOOK_MAX][256] = {{
79
                                                     0,
80
                                                 },
81
                                                 "pre",
82
                                                 "post"};
83
    glusterd_conf_t *priv = NULL;
84
    int32_t len = 0;
85

86
    xlator_t *this = THIS;
87
    priv = this->private;
88

89
    snprintf(path, sizeof(path), "%s/hooks", basedir);
90
    ret = mkdir_p(path, 0755, _gf_true);
91
    if (ret) {
92
        gf_smsg(this->name, GF_LOG_CRITICAL, errno, GD_MSG_CREATE_DIR_FAILED,
93
                "Path=%s", path, NULL);
94
        goto out;
95
    }
96

97
    GLUSTERD_GET_HOOKS_DIR(version_dir, GLUSTERD_HOOK_VER, priv);
98
    ret = mkdir_p(version_dir, 0755, _gf_true);
99
    if (ret) {
100
        gf_smsg(this->name, GF_LOG_CRITICAL, errno, GD_MSG_CREATE_DIR_FAILED,
101
                "Directory=%s", version_dir, NULL);
102
        goto out;
103
    }
104

105
    for (op = GD_OP_NONE + 1; op < GD_OP_MAX; op++) {
106
        cmd_subdir = glusterd_hooks_get_hooks_cmd_subdir(op);
107
        if (strlen(cmd_subdir) == 0)
108
            continue;
109

110
        len = snprintf(path, sizeof(path), "%s/%s", version_dir, cmd_subdir);
111
        if ((len < 0) || (len >= sizeof(path))) {
112
            gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL, NULL);
113
            ret = -1;
114
            goto out;
115
        }
116
        ret = mkdir_p(path, 0755, _gf_true);
117
        if (ret) {
118
            gf_smsg(this->name, GF_LOG_CRITICAL, errno,
119
                    GD_MSG_CREATE_DIR_FAILED, "Path=%s", path, NULL);
120
            goto out;
121
        }
122

123
        for (type = GD_COMMIT_HOOK_PRE; type < GD_COMMIT_HOOK_MAX; type++) {
124
            len = snprintf(path, sizeof(path), "%s/%s/%s", version_dir,
125
                           cmd_subdir, type_subdir[type]);
126
            if ((len < 0) || (len >= sizeof(path))) {
127
                gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_COPY_FAIL,
128
                        NULL);
129
                ret = -1;
130
                goto out;
131
            }
132
            ret = mkdir_p(path, 0755, _gf_true);
133
            if (ret) {
134
                gf_smsg(this->name, GF_LOG_CRITICAL, errno,
135
                        GD_MSG_CREATE_DIR_FAILED, "Path=%s", path, NULL);
136
                goto out;
137
            }
138
        }
139
    }
140

141
    ret = 0;
142
out:
143
    return ret;
144
}
145

146
char *
147
glusterd_hooks_get_hooks_cmd_subdir(glusterd_op_t op)
148
{
149
    GF_ASSERT((op > GD_OP_NONE) && (op < GD_OP_MAX));
150

151
    return glusterd_hook_dirnames[op];
152
}
153

154
void
155
glusterd_hooks_add_working_dir(runner_t *runner, glusterd_conf_t *priv)
156
{
157
    runner_argprintf(runner, "--gd-workdir=%s", priv->workdir);
158
}
159

160
void
161
glusterd_hooks_add_op(runner_t *runner, char *op)
162
{
163
    runner_argprintf(runner, "--volume-op=%s", op);
164
}
165

166
void
167
glusterd_hooks_add_hooks_version(runner_t *runner)
168
{
169
    runner_argprintf(runner, "--version=%d", GLUSTERD_HOOK_VER);
170
}
171

172
static void
173
glusterd_hooks_add_custom_args(dict_t *dict, runner_t *runner)
174
{
175
    char *hooks_args = NULL;
176
    int32_t ret = -1;
177
    xlator_t *this = THIS;
178

179
    GF_VALIDATE_OR_GOTO(this->name, dict, out);
180
    GF_VALIDATE_OR_GOTO(this->name, runner, out);
181

182
    ret = dict_get_str(dict, "hooks_args", &hooks_args);
183
    if (ret)
184
        gf_msg_debug(this->name, 0, "No Hooks Arguments.");
185
    else
186
        gf_msg_debug(this->name, 0, "Hooks Args = %s", hooks_args);
187

188
    if (hooks_args)
189
        runner_argprintf(runner, "%s", hooks_args);
190

191
out:
192
    return;
193
}
194

195
int
196
glusterd_hooks_set_volume_args(dict_t *dict, runner_t *runner)
197
{
198
    int i = 0;
199
    int count = 0;
200
    int ret = -1;
201
    int flag = 0;
202
    char query[1024] = {
203
        0,
204
    };
205
    char *key = NULL;
206
    char *value = NULL;
207
    char *inet_family = NULL;
208
    xlator_t *this = THIS;
209

210
    ret = dict_get_int32(dict, "count", &count);
211
    if (ret) {
212
        gf_smsg(this->name, GF_LOG_ERROR, -ret, GD_MSG_DICT_GET_FAILED,
213
                "Key=count", NULL);
214
        goto out;
215
    }
216

217
    /* This will not happen unless op_ctx
218
     * is corrupted*/
219
    if (!count) {
220
        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ENTRY, "count",
221
                NULL);
222
        goto out;
223
    }
224

225
    runner_add_arg(runner, "-o");
226
    for (i = 1; ret == 0; i++) {
227
        snprintf(query, sizeof(query), "key%d", i);
228
        ret = dict_get_str(dict, query, &key);
229
        if (ret)
230
            continue;
231

232
        snprintf(query, sizeof(query), "value%d", i);
233
        ret = dict_get_str(dict, query, &value);
234
        if (ret)
235
            continue;
236

237
        runner_argprintf(runner, "%s=%s", key, value);
238
        if ((strncmp(key, "cluster.enable-shared-storage",
239
                     SLEN("cluster.enable-shared-storage")) == 0 ||
240
             strncmp(key, "enable-shared-storage",
241
                     SLEN("enable-shared-storage")) == 0) &&
242
            strncmp(value, "enable", SLEN("enable")) == 0)
243
            flag = 1;
244
    }
245

246
    glusterd_hooks_add_custom_args(dict, runner);
247
    if (flag == 1) {
248
        ret = dict_get_str(this->options, "transport.address-family",
249
                           &inet_family);
250
        if (!ret) {
251
            runner_argprintf(runner, "transport.address-family=%s",
252
                             inet_family);
253
        }
254
    }
255

256
    ret = 0;
257
out:
258
    return ret;
259
}
260

261
static int
262
glusterd_hooks_add_op_args(runner_t *runner, glusterd_op_t op, dict_t *op_ctx,
263
                           glusterd_commit_hook_type_t type)
264
{
265
    int vol_count = 0;
266
    gf_boolean_t truth = _gf_false;
267
    glusterd_volinfo_t *voliter = NULL;
268
    glusterd_conf_t *priv = NULL;
269
    int ret = -1;
270

271
    priv = THIS->private;
272
    cds_list_for_each_entry(voliter, &priv->volumes, vol_list)
273
    {
274
        if (glusterd_is_volume_started(voliter))
275
            vol_count++;
276
    }
277

278
    ret = 0;
279
    switch (op) {
280
        case GD_OP_START_VOLUME:
281
            if (type == GD_COMMIT_HOOK_PRE && vol_count == 0)
282
                truth = _gf_true;
283

284
            else if (type == GD_COMMIT_HOOK_POST && vol_count == 1)
285
                truth = _gf_true;
286

287
            else
288
                truth = _gf_false;
289

290
            runner_argprintf(runner, "--first=%s", truth ? "yes" : "no");
291

292
            glusterd_hooks_add_hooks_version(runner);
293
            glusterd_hooks_add_op(runner, "start");
294
            glusterd_hooks_add_working_dir(runner, priv);
295

296
            break;
297

298
        case GD_OP_STOP_VOLUME:
299
            if (type == GD_COMMIT_HOOK_PRE && vol_count == 1)
300
                truth = _gf_true;
301

302
            else if (type == GD_COMMIT_HOOK_POST && vol_count == 0)
303
                truth = _gf_true;
304

305
            else
306
                truth = _gf_false;
307

308
            runner_argprintf(runner, "--last=%s", truth ? "yes" : "no");
309
            break;
310

311
        case GD_OP_SET_VOLUME:
312
            ret = glusterd_hooks_set_volume_args(op_ctx, runner);
313
            glusterd_hooks_add_working_dir(runner, priv);
314
            break;
315

316
        case GD_OP_GSYNC_CREATE:
317
            glusterd_hooks_add_custom_args(op_ctx, runner);
318
            break;
319

320
        case GD_OP_ADD_BRICK:
321
            glusterd_hooks_add_hooks_version(runner);
322
            glusterd_hooks_add_op(runner, "add-brick");
323
            glusterd_hooks_add_working_dir(runner, priv);
324
            break;
325

326
        case GD_OP_RESET_VOLUME:
327
            glusterd_hooks_add_hooks_version(runner);
328
            glusterd_hooks_add_op(runner, "reset");
329
            glusterd_hooks_add_working_dir(runner, priv);
330
            break;
331

332
        default:
333
            break;
334
    }
335

336
    return ret;
337
}
338

339
int
340
glusterd_hooks_run_hooks(char *hooks_path, glusterd_op_t op, dict_t *op_ctx,
341
                         glusterd_commit_hook_type_t type)
342
{
343
    xlator_t *this = THIS;
344
    runner_t runner = {
345
        0,
346
    };
347
    DIR *hookdir = NULL;
348
    struct dirent *entry = NULL;
349
    struct dirent scratch[2] = {
350
        {
351
            0,
352
        },
353
    };
354
    char *volname = NULL;
355
    char **lines = NULL;
356
    int N = 8; /*arbitrary*/
357
    int lineno = 0;
358
    int line_count = 0;
359
    int ret = -1;
360

361
    ret = dict_get_str(op_ctx, "volname", &volname);
362
    if (ret) {
363
        gf_msg(this->name, GF_LOG_CRITICAL, -ret, GD_MSG_DICT_GET_FAILED,
364
               "Failed to get volname "
365
               "from operation context");
366
        goto out;
367
    }
368

369
    hookdir = sys_opendir(hooks_path);
370
    if (!hookdir) {
371
        ret = -1;
372
        gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DIR_OP_FAILED,
373
               "Failed to open dir %s", hooks_path);
374
        goto out;
375
    }
376

377
    lines = GF_CALLOC(1, N * sizeof(*lines), gf_gld_mt_charptr);
378
    if (!lines) {
379
        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_NO_MEMORY, NULL);
380
        ret = -1;
381
        goto out;
382
    }
383

384
    ret = -1;
385
    line_count = 0;
386

387
    while ((entry = sys_readdir(hookdir, scratch))) {
388
        if (gf_irrelevant_entry(entry))
389
            continue;
390
        if (line_count == N - 1) {
391
            N *= 2;
392
            lines = GF_REALLOC(lines, N * sizeof(char *));
393
            if (!lines) {
394
                gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_NO_MEMORY,
395
                        NULL);
396
                goto out;
397
            }
398
        }
399

400
        if (glusterd_is_hook_enabled(entry->d_name)) {
401
            lines[line_count] = gf_strdup(entry->d_name);
402
            line_count++;
403
        }
404
    }
405

406
    lines[line_count] = NULL;
407
    lines = GF_REALLOC(lines, (line_count + 1) * sizeof(char *));
408
    if (!lines)
409
        goto out;
410

411
    qsort(lines, line_count, sizeof(*lines), glusterd_compare_lines);
412

413
    for (lineno = 0; lineno < line_count; lineno++) {
414
        runinit(&runner);
415
        runner_argprintf(&runner, "%s/%s", hooks_path, lines[lineno]);
416
        /*Add future command line arguments to hook scripts below*/
417
        runner_argprintf(&runner, "--volname=%s", volname);
418
        ret = glusterd_hooks_add_op_args(&runner, op, op_ctx, type);
419
        if (ret) {
420
            gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_ADD_OP_ARGS_FAIL,
421
                   "Failed to add "
422
                   "command specific arguments");
423
            goto out;
424
        }
425

426
        ret = runner_run_reuse(&runner);
427
        if (ret) {
428
            runner_log(&runner, this->name, GF_LOG_ERROR,
429
                       "Failed to execute script");
430
        } else {
431
            runner_log(&runner, this->name, GF_LOG_INFO, "Ran script");
432
        }
433
        runner_end(&runner);
434
    }
435

436
    ret = 0;
437
out:
438
    if (lines) {
439
        for (lineno = 0; lineno < line_count + 1; lineno++)
440
            GF_FREE(lines[lineno]);
441

442
        GF_FREE(lines);
443
    }
444

445
    if (hookdir)
446
        sys_closedir(hookdir);
447

448
    return ret;
449
}
450

451
int
452
glusterd_hooks_post_stub_enqueue(char *scriptdir, glusterd_op_t op,
453
                                 dict_t *op_ctx)
454
{
455
    int ret = -1;
456
    glusterd_hooks_stub_t *stub = NULL;
457
    glusterd_hooks_private_t *hooks_priv = NULL;
458
    glusterd_conf_t *conf = NULL;
459

460
    conf = THIS->private;
461
    hooks_priv = conf->hooks_priv;
462

463
    ret = glusterd_hooks_stub_init(&stub, scriptdir, op, op_ctx);
464
    if (ret)
465
        goto out;
466

467
    pthread_mutex_lock(&hooks_priv->mutex);
468
    {
469
        hooks_priv->waitcount++;
470
        cds_list_add_tail(&stub->all_hooks, &hooks_priv->list);
471
        pthread_cond_signal(&hooks_priv->cond);
472
    }
473
    pthread_mutex_unlock(&hooks_priv->mutex);
474

475
    ret = 0;
476
out:
477
    return ret;
478
}
479

480
int
481
glusterd_hooks_stub_init(glusterd_hooks_stub_t **stub, char *scriptdir,
482
                         glusterd_op_t op, dict_t *op_ctx)
483
{
484
    int ret = -1;
485
    glusterd_hooks_stub_t *hooks_stub = NULL;
486

487
    xlator_t *this = THIS;
488
    GF_ASSERT(stub);
489
    if (!stub)
490
        goto out;
491

492
    hooks_stub = GF_CALLOC(1, sizeof(*hooks_stub), gf_gld_mt_hooks_stub_t);
493
    if (!hooks_stub) {
494
        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_NO_MEMORY, NULL);
495
        goto out;
496
    }
497

498
    CDS_INIT_LIST_HEAD(&hooks_stub->all_hooks);
499
    hooks_stub->op = op;
500
    hooks_stub->scriptdir = gf_strdup(scriptdir);
501
    if (!hooks_stub->scriptdir) {
502
        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_STRDUP_FAILED,
503
                "scriptdir=%s", scriptdir, NULL);
504
        goto out;
505
    }
506

507
    hooks_stub->op_ctx = dict_copy_with_ref(op_ctx, hooks_stub->op_ctx);
508
    if (!hooks_stub->op_ctx) {
509
        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_COPY_FAIL, NULL);
510
        goto out;
511
    }
512

513
    *stub = hooks_stub;
514
    ret = 0;
515
out:
516
    if (ret) {
517
        gf_smsg(this->name, GF_LOG_ERROR, 0, GD_MSG_POST_HOOK_STUB_INIT_FAIL,
518
                NULL);
519
        glusterd_hooks_stub_cleanup(hooks_stub);
520
    }
521

522
    return ret;
523
}
524

525
void
526
glusterd_hooks_stub_cleanup(glusterd_hooks_stub_t *stub)
527
{
528
    if (!stub) {
529
        gf_msg_callingfn(THIS->name, GF_LOG_WARNING, 0, GD_MSG_HOOK_STUB_NULL,
530
                         "hooks_stub is NULL");
531
        return;
532
    }
533

534
    if (stub->op_ctx)
535
        dict_unref(stub->op_ctx);
536

537
    GF_FREE(stub->scriptdir);
538

539
    GF_FREE(stub);
540
}
541

542
static void *
543
hooks_worker(void *args)
544
{
545
    glusterd_conf_t *conf = NULL;
546
    glusterd_hooks_private_t *hooks_priv = NULL;
547
    glusterd_hooks_stub_t *stub = NULL;
548

549
    THIS = args;
550
    conf = THIS->private;
551
    hooks_priv = conf->hooks_priv;
552

553
    for (;;) {
554
        pthread_mutex_lock(&hooks_priv->mutex);
555
        {
556
            while (cds_list_empty(&hooks_priv->list)) {
557
                pthread_cond_wait(&hooks_priv->cond, &hooks_priv->mutex);
558
            }
559
            stub = cds_list_entry(hooks_priv->list.next, glusterd_hooks_stub_t,
560
                                  all_hooks);
561
            cds_list_del_init(&stub->all_hooks);
562
            hooks_priv->waitcount--;
563
        }
564
        pthread_mutex_unlock(&hooks_priv->mutex);
565

566
        glusterd_hooks_run_hooks(stub->scriptdir, stub->op, stub->op_ctx,
567
                                 GD_COMMIT_HOOK_POST);
568
        glusterd_hooks_stub_cleanup(stub);
569
    }
570

571
    return NULL;
572
}
573

574
int
575
glusterd_hooks_priv_init(glusterd_hooks_private_t **new)
576
{
577
    int ret = -1;
578
    glusterd_hooks_private_t *hooks_priv = NULL;
579

580
    xlator_t *this = THIS;
581

582
    if (!new) {
583
        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_INVALID_ARGUMENT, NULL);
584
        goto out;
585
    }
586

587
    hooks_priv = GF_CALLOC(1, sizeof(*hooks_priv), gf_gld_mt_hooks_priv_t);
588
    if (!hooks_priv) {
589
        gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_NO_MEMORY, NULL);
590
        goto out;
591
    }
592

593
    pthread_mutex_init(&hooks_priv->mutex, NULL);
594
    pthread_cond_init(&hooks_priv->cond, NULL);
595
    CDS_INIT_LIST_HEAD(&hooks_priv->list);
596
    hooks_priv->waitcount = 0;
597

598
    *new = hooks_priv;
599
    ret = 0;
600
out:
601
    return ret;
602
}
603

604
int
605
glusterd_hooks_spawn_worker(xlator_t *this)
606
{
607
    int ret = -1;
608
    glusterd_conf_t *conf = NULL;
609
    glusterd_hooks_private_t *hooks_priv = NULL;
610

611
    ret = glusterd_hooks_priv_init(&hooks_priv);
612
    if (ret)
613
        goto out;
614

615
    conf = this->private;
616
    conf->hooks_priv = hooks_priv;
617
    ret = gf_thread_create(&hooks_priv->worker, NULL, hooks_worker,
618
                           (void *)this, "gdhooks");
619
    if (ret)
620
        gf_msg(this->name, GF_LOG_CRITICAL, errno, GD_MSG_SPAWN_THREADS_FAIL,
621
               "Failed to spawn post "
622
               "hooks worker thread");
623
out:
624
    return ret;
625
}
626

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.