Statistics
| Branch: | Tag: | Revision:

one / src / pool / PoolSQL.cc @ 621a1869

History | View | Annotate | Download (22.3 KB)

1
/* -------------------------------------------------------------------------- */
2
/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems                */
3
/*                                                                            */
4
/* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
5
/* not use this file except in compliance with the License. You may obtain    */
6
/* a copy of the License at                                                   */
7
/*                                                                            */
8
/* http://www.apache.org/licenses/LICENSE-2.0                                 */
9
/*                                                                            */
10
/* Unless required by applicable law or agreed to in writing, software        */
11
/* distributed under the License is distributed on an "AS IS" BASIS,          */
12
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
13
/* See the License for the specific language governing permissions and        */
14
/* limitations under the License.                                             */
15
/* -------------------------------------------------------------------------- */
16

    
17
#include <climits>
18
#include <sstream>
19
#include <iostream>
20
#include <stdexcept>
21
#include <algorithm>
22

    
23
#include "PoolSQL.h"
24
#include "RequestManagerPoolInfoFilter.h"
25

    
26
#include <errno.h>
27

    
28
/* ************************************************************************** */
29
/* PoolSQL constructor/destructor                                             */
30
/* ************************************************************************** */
31

    
32
/* -------------------------------------------------------------------------- */
33
/* -------------------------------------------------------------------------- */
34

    
35
const unsigned int PoolSQL::MAX_POOL_SIZE = 15000;
36

    
37
/* -------------------------------------------------------------------------- */
38
/* -------------------------------------------------------------------------- */
39

    
40
int PoolSQL::init_cb(void *nil, int num, char **values, char **names)
41
{
42
    lastOID = -1;
43

    
44
    if ( values[0] != 0 )
45
    {
46
        lastOID = atoi(values[0]);
47
    }
48

    
49
    return 0;
50
}
51

    
52
/* -------------------------------------------------------------------------- */
53

    
54
PoolSQL::PoolSQL(SqlDB * _db, const char * _table, bool _cache, bool cache_by_name):
55
    db(_db), lastOID(-1), table(_table), cache(_cache), uses_name_pool(cache_by_name)
56
{
57
    ostringstream   oss;
58

    
59
    pthread_mutex_init(&mutex,0);
60

    
61
    set_callback(static_cast<Callbackable::Callback>(&PoolSQL::init_cb));
62

    
63
    oss << "SELECT last_oid FROM pool_control WHERE tablename='" << table <<"'";
64

    
65
    db->exec(oss,this);
66

    
67
    unset_callback();
68
};
69

    
70
/* -------------------------------------------------------------------------- */
71
/* -------------------------------------------------------------------------- */
72

    
73
PoolSQL::~PoolSQL()
74
{
75
    map<int,PoolObjectSQL *>::iterator  it;
76

    
77
    pthread_mutex_lock(&mutex);
78

    
79
    for ( it = pool.begin(); it != pool.end(); it++)
80
    {
81
        it->second->lock();
82

    
83
        delete it->second;
84
    }
85

    
86
    pthread_mutex_unlock(&mutex);
87

    
88
    pthread_mutex_destroy(&mutex);
89
}
90

    
91

    
92
/* ************************************************************************** */
93
/* PoolSQL public interface                                                   */
94
/* ************************************************************************** */
95

    
96
/* -------------------------------------------------------------------------- */
97
/* -------------------------------------------------------------------------- */
98

    
99
int PoolSQL::allocate(
100
    PoolObjectSQL   *objsql,
101
    string&         error_str)
102
{
103
    int rc;
104

    
105
    lock();
106

    
107
    if (lastOID == INT_MAX)
108
    {
109
        lastOID = -1;
110
    }
111

    
112
    objsql->lock();
113

    
114
    objsql->oid = ++lastOID;
115

    
116
    rc = objsql->insert(db,error_str);
117

    
118
    if ( rc != 0 )
119
    {
120
        lastOID--;
121
        rc = -1;
122
    }
123
    else
124
    {
125
        rc = lastOID;
126
        do_hooks(objsql, Hook::ALLOCATE);
127
    }
128

    
129
    objsql->unlock();
130

    
131
    delete objsql;
132

    
133
    if( rc != -1 )
134
    {
135
        update_lastOID();
136
    }
137

    
138
    unlock();
139

    
140
    return rc;
141
}
142

    
143
/* -------------------------------------------------------------------------- */
144
/* -------------------------------------------------------------------------- */
145

    
146
void PoolSQL::update_lastOID()
147
{
148
    // db->escape_str is not used for 'table' since its name can't be set in
149
    // any way by the user, it is hardcoded.
150

    
151
    ostringstream oss;
152

    
153
    oss << "REPLACE INTO pool_control (tablename, last_oid) VALUES ("
154
        << "'" <<   table       << "',"
155
        <<          lastOID     << ")";
156

    
157
    db->exec(oss);
158
}
159

    
160
/* -------------------------------------------------------------------------- */
161
/* -------------------------------------------------------------------------- */
162

    
163
PoolObjectSQL * PoolSQL::get(
164
    int     oid,
165
    bool    olock)
166
{
167
    map<int,PoolObjectSQL *>::iterator  index;
168
    PoolObjectSQL *                     objectsql;
169
    int                                 rc;
170

    
171
    if ( oid < 0 )
172
    {
173
        objectsql = 0;
174
        return objectsql;
175
    }
176

    
177
    lock();
178

    
179
    if (!cache)
180
    {
181
        flush_cache(oid);
182
    }
183

    
184
    index = pool.find(oid);
185

    
186
    if ( index != pool.end() )
187
    {
188
        if ( index->second->isValid() == false )
189
        {
190
            objectsql = 0;
191
        }
192
        else
193
        {
194
            objectsql = index->second;
195

    
196
            if ( olock == true )
197
            {
198
                objectsql->lock();
199

    
200
                if ( objectsql->isValid() == false )
201
                {
202
                    objectsql->unlock();
203
                    objectsql = 0;
204
                }
205
            }
206
        }
207

    
208
        unlock();
209

    
210
        return objectsql;
211
    }
212
    else
213
    {
214
        objectsql = create();
215

    
216
        objectsql->oid = oid;
217

    
218
        rc = objectsql->select(db);
219

    
220
        if ( rc != 0 )
221
        {
222
            delete objectsql;
223

    
224
            unlock();
225

    
226
            objectsql = 0;
227
            return 0;
228
        }
229

    
230
        if ( uses_name_pool )
231
        {
232
            map<string,PoolObjectSQL *>::iterator name_index;
233
            string okey;
234

    
235
            okey       = key(objectsql->name,objectsql->uid);
236
            name_index = name_pool.find(okey);
237

    
238
            if ( name_index != name_pool.end() )
239
            {
240
                name_index->second->lock();
241

    
242
                PoolObjectSQL * tmp_ptr  = name_index->second;
243

    
244
                name_pool.erase(okey);
245
                pool.erase(tmp_ptr->oid);
246

    
247
                delete tmp_ptr;
248
            }
249

    
250
            name_pool.insert(make_pair(okey, objectsql));
251
        }
252

    
253
        pool.insert(make_pair(objectsql->oid,objectsql));
254

    
255
        if ( olock == true )
256
        {
257
            objectsql->lock();
258
        }
259

    
260
        if (cache)
261
        {
262
            oid_queue.push(objectsql->oid);
263

    
264
            if ( pool.size() > MAX_POOL_SIZE )
265
            {
266
                replace();
267
            }
268
        }
269

    
270
        unlock();
271

    
272
        return objectsql;
273
    }
274
}
275

    
276
/* -------------------------------------------------------------------------- */
277
/* -------------------------------------------------------------------------- */
278

    
279
PoolObjectSQL * PoolSQL::get(const string& name, int ouid, bool olock)
280
{
281
    map<string,PoolObjectSQL *>::iterator  index;
282

    
283
    PoolObjectSQL *  objectsql;
284
    int              rc;
285
    string           name_key;
286

    
287
    if ( uses_name_pool == false )
288
    {
289
        return 0;
290
    }
291

    
292
    lock();
293

    
294
    name_key = key(name,ouid);
295

    
296
    if (!cache)
297
    {
298
        flush_cache(name_key);
299
    }
300

    
301
    index = name_pool.find(name_key);
302

    
303
    if ( index != name_pool.end() && index->second->isValid() == true )
304
    {
305
        objectsql = index->second;
306

    
307
        if ( olock == true )
308
        {
309
            objectsql->lock();
310

    
311
            if ( objectsql->isValid() == false )
312
            {
313
                objectsql->unlock();
314
                objectsql = 0;
315
            }
316
        }
317

    
318
        unlock();
319

    
320
        return objectsql;
321
    }
322
    else
323
    {
324
        if ( index != name_pool.end() && index->second->isValid() == false )
325
        {
326
            index->second->lock();
327

    
328
            PoolObjectSQL * tmp_ptr  = index->second;
329
            string          tmp_okey = key(tmp_ptr->name,tmp_ptr->uid);
330

    
331
            pool.erase(tmp_ptr->oid);
332
            name_pool.erase(tmp_okey);
333

    
334
            delete tmp_ptr;
335
        }
336

    
337
        objectsql = create();
338

    
339
        rc = objectsql->select(db,name,ouid);
340

    
341
        if ( rc != 0 )
342
        {
343
            delete objectsql;
344

    
345
            unlock();
346

    
347
            return 0;
348
        }
349

    
350
        string okey = key(objectsql->name,objectsql->uid);
351

    
352
        pool.insert(make_pair(objectsql->oid, objectsql));
353
        name_pool.insert(make_pair(okey, objectsql));
354

    
355
        if ( olock == true )
356
        {
357
            objectsql->lock();
358
        }
359

    
360
        if (cache)
361
        {
362
            oid_queue.push(objectsql->oid);
363

    
364
            if ( pool.size() > MAX_POOL_SIZE )
365
            {
366
                replace();
367
            }
368
        }
369

    
370
        unlock();
371

    
372
        return objectsql;
373
    }
374
}
375

    
376
/* -------------------------------------------------------------------------- */
377
/* -------------------------------------------------------------------------- */
378

    
379
void PoolSQL::update_cache_index(string& old_name,
380
                                 int     old_uid,
381
                                 string& new_name,
382
                                 int     new_uid)
383
{
384
    map<string,PoolObjectSQL *>::iterator  index;
385
    PoolObjectSQL * the_object;
386

    
387
    lock();
388

    
389
    if ( uses_name_pool == false )
390
    {
391
        unlock();
392
        return;
393
    }
394

    
395
    string old_key  = key(old_name, old_uid);
396
    string new_key  = key(new_name, new_uid);
397

    
398
    index = name_pool.find(old_key);
399

    
400
    if ( index != name_pool.end() )
401
    {
402
        the_object = index->second;
403

    
404
        name_pool.erase(old_key);
405

    
406
        if ( name_pool.find(new_key) == name_pool.end())
407
        {
408
            name_pool.insert(make_pair(new_key, the_object));
409
        }
410
    }
411

    
412
    unlock();
413
}
414

    
415
/* -------------------------------------------------------------------------- */
416
/* -------------------------------------------------------------------------- */
417

    
418
void PoolSQL::replace()
419
{
420
    bool removed = false;
421
    int  oid;
422
    int  rc;
423

    
424
    map<int,PoolObjectSQL *>::iterator  index;
425

    
426
    while (!removed)
427
    {
428
        oid   = oid_queue.front();
429
        index = pool.find(oid);
430

    
431
        if ( index == pool.end())
432
        {
433
            oid_queue.pop();
434
            continue;
435
        }
436

    
437
        rc = pthread_mutex_trylock(&(index->second->mutex));
438

    
439
        if ( rc == EBUSY ) // In use by other thread, move to back
440
        {
441
            oid_queue.pop();
442
            oid_queue.push(oid);
443
        }
444
        else
445
        {
446
            PoolObjectSQL * tmp_ptr = index->second;
447

    
448
            pool.erase(index);
449

    
450
            if ( uses_name_pool )
451
            {
452
                string okey = key(tmp_ptr->name,tmp_ptr->uid);
453
                name_pool.erase(okey);
454
            }
455

    
456
            delete tmp_ptr;
457

    
458
            oid_queue.pop();
459
            removed = true;
460
        }
461
    }
462
}
463

    
464
/* -------------------------------------------------------------------------- */
465
/* -------------------------------------------------------------------------- */
466

    
467
void PoolSQL::flush_cache(int oid)
468
{
469
    int  rc;
470
    PoolObjectSQL * tmp_ptr;
471

    
472
    map<int,PoolObjectSQL *>::iterator  it;
473

    
474
    for (it = pool.begin(); it != pool.end(); )
475
    {
476
        // The object we are looking for in ::get(). Will wait until it is
477
        // unlocked()
478
        if (it->second->oid == oid)
479
        {
480
            it->second->lock();
481
        }
482
        else
483
        {
484
            // Any other locked object is just ignored
485
            rc = pthread_mutex_trylock(&(it->second->mutex));
486

    
487
            if ( rc == EBUSY ) // In use by other thread
488
            {
489
                it++;
490
                continue;
491
            }
492
        }
493

    
494
        tmp_ptr = it->second;
495

    
496
        // map::erase does not invalidate the iterator, except for the current
497
        // one
498
        pool.erase(it++);
499

    
500
        if ( uses_name_pool )
501
        {
502
            string okey = key(tmp_ptr->name,tmp_ptr->uid);
503
            name_pool.erase(okey);
504
        }
505

    
506
        delete tmp_ptr;
507
    }
508
}
509

    
510
/* -------------------------------------------------------------------------- */
511
/* -------------------------------------------------------------------------- */
512

    
513
void PoolSQL::flush_cache(const string& name_key)
514
{
515
    int  rc;
516
    PoolObjectSQL * tmp_ptr;
517

    
518
    map<string,PoolObjectSQL *>::iterator it;
519

    
520
    for (it = name_pool.begin(); it != name_pool.end(); )
521
    {
522
        string okey = key(it->second->name, it->second->uid);
523

    
524
        // The object we are looking for in ::get(). Will wait until it is
525
        // unlocked()
526
        if (name_key == okey)
527
        {
528
            it->second->lock();
529
        }
530
        else
531
        {
532
            // Any other locked object is just ignored
533
            rc = pthread_mutex_trylock(&(it->second->mutex));
534

    
535
            if ( rc == EBUSY ) // In use by other thread
536
            {
537
                it++;
538
                continue;
539
            }
540
        }
541

    
542
        tmp_ptr = it->second;
543

    
544
        // map::erase does not invalidate the iterator, except for the current
545
        // one
546
        name_pool.erase(it++);
547
        pool.erase(tmp_ptr->oid);
548

    
549
        delete tmp_ptr;
550
    }
551
}
552

    
553
/* -------------------------------------------------------------------------- */
554
/* -------------------------------------------------------------------------- */
555

    
556
void PoolSQL::clean()
557
{
558
    map<int,PoolObjectSQL *>::iterator  it;
559

    
560
    lock();
561

    
562
    for ( it = pool.begin(); it != pool.end(); it++)
563
    {
564
        it->second->lock();
565

    
566
        delete it->second;
567
    }
568

    
569
    pool.clear();
570
    name_pool.clear();
571

    
572
    unlock();
573
}
574

    
575
/* -------------------------------------------------------------------------- */
576
/* -------------------------------------------------------------------------- */
577

    
578
int PoolSQL::dump_cb(void * _oss, int num, char **values, char **names)
579
{
580
    ostringstream * oss;
581

    
582
    oss = static_cast<ostringstream *>(_oss);
583

    
584
    if ( (!values[0]) || (num != 1) )
585
    {
586
        return -1;
587
    }
588

    
589
    *oss << values[0];
590
    return 0;
591
}
592

    
593
/* -------------------------------------------------------------------------- */
594

    
595
int PoolSQL::dump(ostringstream& oss,
596
                  const string& elem_name,
597
                  const char * table,
598
                  const string& where,
599
                  const string& limit)
600
{
601
    ostringstream   cmd;
602

    
603
    cmd << "SELECT body FROM " << table;
604

    
605
    if ( !where.empty() )
606
    {
607
        cmd << " WHERE " << where;
608
    }
609

    
610
    cmd << " ORDER BY oid";
611

    
612
    if ( !limit.empty() )
613
    {
614
        cmd << " LIMIT " << limit;
615
    }
616

    
617
    return dump(oss, elem_name, cmd);
618
}
619

    
620
/* -------------------------------------------------------------------------- */
621
/* -------------------------------------------------------------------------- */
622

    
623
int PoolSQL::dump(ostringstream&  oss,
624
                  const string&   root_elem_name,
625
                  ostringstream&  sql_query)
626
{
627
    int rc;
628

    
629
    oss << "<" << root_elem_name << ">";
630

    
631
    set_callback(static_cast<Callbackable::Callback>(&PoolSQL::dump_cb),
632
                 static_cast<void *>(&oss));
633

    
634
    rc = db->exec(sql_query, this);
635

    
636
    add_extra_xml(oss);
637

    
638
    oss << "</" << root_elem_name << ">";
639

    
640
    unset_callback();
641

    
642
    return rc;
643
}
644

    
645
/* -------------------------------------------------------------------------- */
646
/* -------------------------------------------------------------------------- */
647

    
648
int PoolSQL:: search_cb(void * _oids, int num, char **values, char **names)
649
{
650
    vector<int> *  oids;
651

    
652
    oids = static_cast<vector<int> *>(_oids);
653

    
654
    if ( num == 0 || values == 0 || values[0] == 0 )
655
    {
656
        return -1;
657
    }
658

    
659
    oids->push_back(atoi(values[0]));
660

    
661
    return 0;
662
}
663

    
664
/* -------------------------------------------------------------------------- */
665

    
666
int PoolSQL::search(
667
    vector<int>&    oids,
668
    const char *    table,
669
    const string&   where)
670
{
671
    ostringstream   sql;
672
    int             rc;
673

    
674
    set_callback(static_cast<Callbackable::Callback>(&PoolSQL::search_cb),
675
                 static_cast<void *>(&oids));
676

    
677
    sql  << "SELECT oid FROM " <<  table;
678

    
679
    if (!where.empty())
680
    {
681
        sql << " WHERE " << where;
682
    }
683

    
684
    rc = db->exec(sql, this);
685

    
686
    unset_callback();
687

    
688
    return rc;
689
}
690

    
691
/* -------------------------------------------------------------------------- */
692
/* -------------------------------------------------------------------------- */
693

    
694
void PoolSQL::acl_filter(int                       uid,
695
                         const set<int>&           user_groups,
696
                         PoolObjectSQL::ObjectType auth_object,
697
                         bool&                     all,
698
                         bool                      disable_all_acl,
699
                         bool                      disable_cluster_acl,
700
                         bool                      disable_group_acl,
701
                         string&                   filter)
702
{
703
    filter.clear();
704

    
705
    if ( uid == UserPool::ONEADMIN_ID || user_groups.count( GroupPool::ONEADMIN_ID ) == 1 )
706
    {
707
        all = true;
708
        return;
709
    }
710

    
711
    Nebula&     nd   = Nebula::instance();
712
    AclManager* aclm = nd.get_aclm();
713

    
714
    ostringstream         acl_filter;
715
    vector<int>::iterator it;
716

    
717
    vector<int> oids;
718
    vector<int> gids;
719
    vector<int> cids;
720

    
721
    aclm->reverse_search(uid,
722
                         user_groups,
723
                         auth_object,
724
                         AuthRequest::USE,
725
                         disable_all_acl,
726
                         disable_cluster_acl,
727
                         disable_group_acl,
728
                         all,
729
                         oids,
730
                         gids,
731
                         cids);
732

    
733
    for ( it = oids.begin(); it < oids.end(); it++ )
734
    {
735
        acl_filter << " OR oid = " << *it;
736
    }
737

    
738
    for ( it = gids.begin(); it < gids.end(); it++ )
739
    {
740
        acl_filter << " OR gid = " << *it;
741
    }
742

    
743
    string cl_table;
744

    
745
    if (auth_object == PoolObjectSQL::HOST)
746
    {
747
        cl_table = Cluster::host_table;
748
    }
749
    else if (auth_object == PoolObjectSQL::DATASTORE)
750
    {
751
        cl_table = Cluster::datastore_table;
752
    }
753
    else if (auth_object == PoolObjectSQL::NET)
754
    {
755
        cl_table = Cluster::network_table;
756
    }
757

    
758
    if (!cl_table.empty())
759
    {
760
        for ( it = cids.begin(); it < cids.end(); it++ )
761
        {
762
            acl_filter << " OR oid IN ("
763
                << "SELECT oid from " << cl_table
764
                << " WHERE cid = " << *it << ")";
765
        }
766
    }
767

    
768
    filter = acl_filter.str();
769
}
770

    
771
/* -------------------------------------------------------------------------- */
772

    
773
void PoolSQL::usr_filter(int                uid,
774
                         const set<int>&    user_groups,
775
                         int                filter_flag,
776
                         bool               all,
777
                         const string&      acl_str,
778
                         string&            filter)
779
{
780
    ostringstream uid_filter;
781

    
782
    set<int>::iterator g_it;
783

    
784
    if ( filter_flag == RequestManagerPoolInfoFilter::MINE )
785
    {
786
        uid_filter << "uid = " << uid;
787
    }
788
    else if ( filter_flag == RequestManagerPoolInfoFilter::MINE_GROUP )
789
    {
790
        uid_filter << "uid = " << uid << " OR ( (";
791

    
792
        string sep = " ";
793

    
794
        for (g_it = user_groups.begin(); g_it != user_groups.end(); g_it++)
795
        {
796
            uid_filter << sep << "( gid = " << *g_it << " )";
797
            sep = " OR ";
798
        }
799

    
800
        uid_filter << ")";
801

    
802
        if ( !all )
803
        {
804
            uid_filter << " AND ( other_u = 1";
805

    
806
            for (g_it = user_groups.begin(); g_it != user_groups.end(); g_it++)
807
            {
808
                uid_filter << " OR ( gid = " << *g_it << " AND group_u = 1 )";
809
            }
810

    
811
            uid_filter << acl_str << ")";
812
        }
813

    
814
        uid_filter << ")";
815
    }
816
    else if ( filter_flag == RequestManagerPoolInfoFilter::ALL )
817
    {
818
        if (!all)
819
        {
820
            uid_filter << " uid = " << uid
821
                    << " OR other_u = 1";
822

    
823
            for (g_it = user_groups.begin(); g_it != user_groups.end(); g_it++)
824
            {
825
                uid_filter << " OR ( gid = " << *g_it << " AND group_u = 1 )";
826
            }
827

    
828
            uid_filter << acl_str;
829
        }
830
    }
831
    else
832
    {
833
        uid_filter << "uid = " << filter_flag;
834

    
835
        if ( filter_flag != uid && !all )
836
        {
837
            uid_filter << " AND ( other_u = 1";
838

    
839
            for (g_it = user_groups.begin(); g_it != user_groups.end(); g_it++)
840
            {
841
                uid_filter << " OR ( gid = " << *g_it << " AND group_u = 1 )";
842
            }
843

    
844
            uid_filter << acl_str << ")";
845
        }
846
    }
847

    
848
    filter = uid_filter.str();
849
}
850

    
851
/* -------------------------------------------------------------------------- */
852

    
853
void PoolSQL::oid_filter(int     start_id,
854
                         int     end_id,
855
                         string& filter)
856
{
857
    ostringstream idfilter;
858

    
859
    if ( end_id >= -1 && start_id != -1 )
860
    {
861
        idfilter << "oid >= " << start_id;
862

    
863
        if ( end_id != -1 )
864
        {
865
            idfilter << " AND oid <= " << end_id;
866
        }
867
    }
868

    
869
    filter = idfilter.str();
870
}
871

    
872
/* -------------------------------------------------------------------------- */
873
/* -------------------------------------------------------------------------- */
874

    
875
void PoolSQL::register_hooks(vector<const VectorAttribute *> hook_mads,
876
                             const string&                   remotes_location)
877
{
878
    string name;
879
    string on;
880
    string cmd;
881
    string arg;
882

    
883
    for (unsigned int i = 0 ; i < hook_mads.size() ; i++ )
884
    {
885
        name = hook_mads[i]->vector_value("NAME");
886
        on   = hook_mads[i]->vector_value("ON");
887
        cmd  = hook_mads[i]->vector_value("COMMAND");
888
        arg  = hook_mads[i]->vector_value("ARGUMENTS");
889

    
890
        one_util::toupper(on);
891

    
892
        if ( on.empty() || cmd.empty() )
893
        {
894
            NebulaLog::log("VM", Log::WARNING, "Empty ON or COMMAND attribute"
895
                " in Hook, not registered!");
896

    
897
            continue;
898
        }
899

    
900
        if ( name.empty() )
901
        {
902
            name = cmd;
903
        }
904

    
905
        if (cmd[0] != '/')
906
        {
907
            ostringstream cmd_os;
908

    
909
            cmd_os << remotes_location << "/hooks/" << cmd;
910

    
911
            cmd = cmd_os.str();
912
        }
913

    
914
        if ( on == "CREATE" )
915
        {
916
            AllocateHook * hook;
917

    
918
            hook = new AllocateHook(name, cmd, arg, false);
919

    
920
            add_hook(hook);
921
        }
922
        else if ( on == "REMOVE" )
923
        {
924
            RemoveHook * hook;
925

    
926
            hook = new RemoveHook(name, cmd, arg, false);
927

    
928
            add_hook(hook);
929
        }
930
    }
931
}