Statistics
| Branch: | Tag: | Revision:

one / src / pool / PoolSQL.cc @ cfd29830

History | View | Annotate | Download (16 KB)

1
/* -------------------------------------------------------------------------- */
2
/* Copyright 2002-2017, 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
static int _get_lastOID(SqlDB * db, const string& table)
35
{
36
    ostringstream oss;
37

    
38
    int _last_oid = -1;
39

    
40
    single_cb<int> cb;
41

    
42
    cb.set_callback(&_last_oid);
43

    
44
    oss << "SELECT last_oid FROM pool_control WHERE tablename='" << table <<"'";
45

    
46
    db->exec_rd(oss, &cb);
47

    
48
    cb.unset_callback();
49

    
50
    return _last_oid;
51
}
52

    
53
int PoolSQL::get_lastOID()
54
{
55
    int _last_oid;
56

    
57
    lock();
58

    
59
    _last_oid = _get_lastOID(db, table);
60

    
61
    unlock();
62

    
63
    return _last_oid;
64
}
65

    
66
/* -------------------------------------------------------------------------- */
67

    
68
static void _set_lastOID(int _last_oid, SqlDB * db, const string& table)
69
{
70
    ostringstream oss;
71

    
72
    oss << "REPLACE INTO pool_control (tablename, last_oid) VALUES ('" << table
73
        << "'," << _last_oid << ")";
74

    
75
    db->exec_wr(oss);
76
}
77

    
78
void PoolSQL::set_lastOID(int _last_oid)
79
{
80
    lock();
81

    
82
    _set_lastOID(_last_oid, db, table);
83

    
84
    unlock();
85
}
86

    
87
/* -------------------------------------------------------------------------- */
88
/* -------------------------------------------------------------------------- */
89

    
90
PoolSQL::PoolSQL(SqlDB * _db, const char * _table):
91
    db(_db), table(_table)
92
{
93
    pthread_mutex_init(&mutex,0);
94
};
95

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

    
99
PoolSQL::~PoolSQL()
100
{
101
    vector<PoolObjectSQL *>::iterator it;
102

    
103
    pthread_mutex_lock(&mutex);
104

    
105
    for ( it = pool.begin(); it != pool.end(); ++it)
106
    {
107
        (*it)->lock();
108

    
109
        delete *it;
110
    }
111

    
112
    pthread_mutex_unlock(&mutex);
113

    
114
    pthread_mutex_destroy(&mutex);
115
}
116

    
117
/* -------------------------------------------------------------------------- */
118
/* -------------------------------------------------------------------------- */
119
/* PoolSQL public interface                                                   */
120
/* -------------------------------------------------------------------------- */
121
/* -------------------------------------------------------------------------- */
122
int PoolSQL::allocate(PoolObjectSQL *objsql, string& error_str)
123
{
124
    int rc;
125
    int lastOID;
126

    
127
    lock();
128

    
129
    lastOID = _get_lastOID(db, table);
130

    
131
    if (lastOID == INT_MAX)
132
    {
133
        lastOID = -1;
134
    }
135

    
136
    objsql->lock();
137

    
138
    objsql->oid = ++lastOID;
139

    
140
    _set_lastOID(lastOID, db, table);
141

    
142
    rc = objsql->insert(db, error_str);
143

    
144
    if ( rc != 0 )
145
    {
146
        rc = -1;
147
    }
148
    else
149
    {
150
        rc = lastOID;
151
        do_hooks(objsql, Hook::ALLOCATE);
152
    }
153

    
154
    delete objsql;
155

    
156
    if( rc == -1 )
157
    {
158
        _set_lastOID(--lastOID, db, table);
159
    }
160

    
161
    unlock();
162

    
163
    return rc;
164
}
165

    
166
/* -------------------------------------------------------------------------- */
167
/* -------------------------------------------------------------------------- */
168

    
169
PoolObjectSQL * PoolSQL::get(int oid, bool olock)
170
{
171
    if ( oid < 0 )
172
    {
173
        return 0;
174
    }
175

    
176
    lock();
177

    
178
    flush_cache(oid);
179

    
180
    PoolObjectSQL * objectsql = create();
181

    
182
    objectsql->oid = oid;
183

    
184
    int rc = objectsql->select(db);
185

    
186
    if ( rc != 0 )
187
    {
188
        objectsql->lock();
189

    
190
        delete objectsql;
191

    
192
        unlock();
193

    
194
        return 0;
195
    }
196

    
197
    pool.push_back(objectsql);
198

    
199
    if ( olock == true )
200
    {
201
        objectsql->lock();
202
    }
203

    
204
    unlock();
205

    
206
    return objectsql;
207
}
208

    
209
/* -------------------------------------------------------------------------- */
210
/* -------------------------------------------------------------------------- */
211

    
212
PoolObjectSQL * PoolSQL::get(const string& name, int ouid, bool olock)
213
{
214
    lock();
215

    
216
    string name_key = key(name, ouid);
217

    
218
    flush_cache(name_key);
219

    
220
    PoolObjectSQL * objectsql = create();
221

    
222
    int rc = objectsql->select(db, name, ouid);
223

    
224
    if ( rc != 0 )
225
    {
226
        objectsql->lock();
227

    
228
        delete objectsql;
229

    
230
        unlock();
231

    
232
        return 0;
233
    }
234

    
235
    pool.push_back(objectsql);
236

    
237
    if ( olock == true )
238
    {
239
        objectsql->lock();
240
    }
241

    
242
    unlock();
243

    
244
    return objectsql;
245
}
246

    
247
/* -------------------------------------------------------------------------- */
248
/* -------------------------------------------------------------------------- */
249

    
250
void PoolSQL::flush_cache(int oid)
251
{
252
    for (vector<PoolObjectSQL *>::iterator it = pool.begin(); it != pool.end();)
253
    {
254
        // The object we are looking for in ::get(). Wait until it is unlocked()
255
        if ((*it)->oid == oid)
256
        {
257
            (*it)->lock();
258
        }
259
        else
260
        {
261
            // Any other locked object is just ignored
262
            int rc = pthread_mutex_trylock(&((*it)->mutex));
263

    
264
            if ( rc == EBUSY ) // In use by other thread
265
            {
266
                it++;
267
                continue;
268
            }
269
        }
270

    
271
        delete *it;
272

    
273
        it = pool.erase(it);
274
    }
275
}
276

    
277
/* -------------------------------------------------------------------------- */
278
/* -------------------------------------------------------------------------- */
279

    
280
void PoolSQL::flush_cache(const string& name_key)
281
{
282
    for (vector<PoolObjectSQL *>::iterator it = pool.begin(); it != pool.end();)
283
    {
284
        string okey = key((*it)->name, (*it)->uid);
285

    
286
        // The object we are looking for in ::get(). Wait until it is unlocked()
287
        if ( name_key == okey)
288
        {
289
            (*it)->lock();
290
        }
291
        else
292
        {
293
            // Any other locked object is just ignored
294
            int rc = pthread_mutex_trylock(&((*it)->mutex));
295

    
296
            if ( rc == EBUSY ) // In use by other thread
297
            {
298
                it++;
299
                continue;
300
            }
301
        }
302

    
303
        delete *it;
304

    
305
        it = pool.erase(it);
306
    }
307
}
308

    
309
/* -------------------------------------------------------------------------- */
310
/* -------------------------------------------------------------------------- */
311

    
312
void PoolSQL::clean()
313
{
314
    vector<PoolObjectSQL *>::iterator it;
315

    
316
    lock();
317

    
318
    for (it = pool.begin(); it != pool.end(); ++it)
319
    {
320
        (*it)->lock();
321

    
322
        delete *it;
323
    }
324

    
325
    pool.clear();
326

    
327
    unlock();
328
}
329

    
330
/* -------------------------------------------------------------------------- */
331
/* -------------------------------------------------------------------------- */
332

    
333
int PoolSQL::dump_cb(void * _oss, int num, char **values, char **names)
334
{
335
    ostringstream * oss;
336

    
337
    oss = static_cast<ostringstream *>(_oss);
338

    
339
    if ( (!values[0]) || (num != 1) )
340
    {
341
        return -1;
342
    }
343

    
344
    *oss << values[0];
345
    return 0;
346
}
347

    
348
/* -------------------------------------------------------------------------- */
349

    
350
int PoolSQL::dump(ostringstream& oss, const string& elem_name, const char* table,
351
    const string& where, const string& limit)
352
{
353
    ostringstream   cmd;
354

    
355
    cmd << "SELECT body FROM " << table;
356

    
357
    if ( !where.empty() )
358
    {
359
        cmd << " WHERE " << where;
360
    }
361

    
362
    cmd << " ORDER BY oid";
363

    
364
    if ( !limit.empty() )
365
    {
366
        cmd << " LIMIT " << limit;
367
    }
368

    
369
    return dump(oss, elem_name, cmd);
370
}
371

    
372
/* -------------------------------------------------------------------------- */
373
/* -------------------------------------------------------------------------- */
374

    
375
int PoolSQL::dump(ostringstream& oss, const string& root_elem_name,
376
    ostringstream& sql_query)
377
{
378
    int rc;
379

    
380
    oss << "<" << root_elem_name << ">";
381

    
382
    set_callback(static_cast<Callbackable::Callback>(&PoolSQL::dump_cb),
383
                 static_cast<void *>(&oss));
384

    
385
    rc = db->exec_rd(sql_query, this);
386

    
387
    add_extra_xml(oss);
388

    
389
    oss << "</" << root_elem_name << ">";
390

    
391
    unset_callback();
392

    
393
    return rc;
394
}
395

    
396
/* -------------------------------------------------------------------------- */
397
/* -------------------------------------------------------------------------- */
398

    
399
int PoolSQL:: search_cb(void * _oids, int num, char **values, char **names)
400
{
401
    vector<int> *  oids;
402

    
403
    oids = static_cast<vector<int> *>(_oids);
404

    
405
    if ( num == 0 || values == 0 || values[0] == 0 )
406
    {
407
        return -1;
408
    }
409

    
410
    oids->push_back(atoi(values[0]));
411

    
412
    return 0;
413
}
414

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

    
417
int PoolSQL::search(
418
    vector<int>&    oids,
419
    const char *    table,
420
    const string&   where)
421
{
422
    ostringstream   sql;
423
    int             rc;
424

    
425
    set_callback(static_cast<Callbackable::Callback>(&PoolSQL::search_cb),
426
                 static_cast<void *>(&oids));
427

    
428
    sql  << "SELECT oid FROM " <<  table;
429

    
430
    if (!where.empty())
431
    {
432
        sql << " WHERE " << where;
433
    }
434

    
435
    rc = db->exec_rd(sql, this);
436

    
437
    unset_callback();
438

    
439
    return rc;
440
}
441

    
442
/* -------------------------------------------------------------------------- */
443
/* -------------------------------------------------------------------------- */
444

    
445
void PoolSQL::acl_filter(int                       uid,
446
                         const set<int>&           user_groups,
447
                         PoolObjectSQL::ObjectType auth_object,
448
                         bool&                     all,
449
                         bool                      disable_all_acl,
450
                         bool                      disable_cluster_acl,
451
                         bool                      disable_group_acl,
452
                         string&                   filter)
453
{
454
    filter.clear();
455

    
456
    if ( uid == UserPool::ONEADMIN_ID ||
457
            user_groups.count( GroupPool::ONEADMIN_ID ) == 1 )
458
    {
459
        all = true;
460
        return;
461
    }
462

    
463
    Nebula&     nd   = Nebula::instance();
464
    AclManager* aclm = nd.get_aclm();
465

    
466
    ostringstream         acl_filter;
467
    vector<int>::iterator it;
468

    
469
    vector<int> oids;
470
    vector<int> gids;
471
    vector<int> cids;
472

    
473
    aclm->reverse_search(uid,
474
                         user_groups,
475
                         auth_object,
476
                         AuthRequest::USE,
477
                         disable_all_acl,
478
                         disable_cluster_acl,
479
                         disable_group_acl,
480
                         all,
481
                         oids,
482
                         gids,
483
                         cids);
484

    
485
    for ( it = oids.begin(); it < oids.end(); it++ )
486
    {
487
        acl_filter << " OR oid = " << *it;
488
    }
489

    
490
    for ( it = gids.begin(); it < gids.end(); it++ )
491
    {
492
        acl_filter << " OR gid = " << *it;
493
    }
494

    
495
    ClusterPool::cluster_acl_filter(acl_filter, auth_object, cids);
496

    
497
    filter = acl_filter.str();
498
}
499

    
500
/* -------------------------------------------------------------------------- */
501

    
502
void PoolSQL::usr_filter(int                uid,
503
                         int                gid,
504
                         const set<int>&    user_groups,
505
                         int                filter_flag,
506
                         bool               all,
507
                         const string&      acl_str,
508
                         string&            filter)
509
{
510
    ostringstream uid_filter;
511

    
512
    set<int>::iterator g_it;
513

    
514
    if ( filter_flag == RequestManagerPoolInfoFilter::MINE )
515
    {
516
        uid_filter << "uid = " << uid;
517
    }
518
    else if ( filter_flag == RequestManagerPoolInfoFilter::GROUP )
519
    {
520
        uid_filter << "gid = " << gid;
521
    }
522
    else if ( filter_flag == RequestManagerPoolInfoFilter::MINE_GROUP )
523
    {
524
        uid_filter << "uid = " << uid << " OR ( (";
525

    
526
        string sep = " ";
527

    
528
        for (g_it = user_groups.begin(); g_it != user_groups.end(); g_it++)
529
        {
530
            uid_filter << sep << "( gid = " << *g_it << " )";
531
            sep = " OR ";
532
        }
533

    
534
        uid_filter << ")";
535

    
536
        if ( !all )
537
        {
538
            uid_filter << " AND ( other_u = 1";
539

    
540
            for (g_it = user_groups.begin(); g_it != user_groups.end(); g_it++)
541
            {
542
                uid_filter << " OR ( gid = " << *g_it << " AND group_u = 1 )";
543
            }
544

    
545
            uid_filter << acl_str << ")";
546
        }
547

    
548
        uid_filter << ")";
549
    }
550
    else if ( filter_flag == RequestManagerPoolInfoFilter::ALL )
551
    {
552
        if (!all)
553
        {
554
            uid_filter << " uid = " << uid
555
                    << " OR other_u = 1";
556

    
557
            for (g_it = user_groups.begin(); g_it != user_groups.end(); g_it++)
558
            {
559
                uid_filter << " OR ( gid = " << *g_it << " AND group_u = 1 )";
560
            }
561

    
562
            uid_filter << acl_str;
563
        }
564
    }
565
    else
566
    {
567
        uid_filter << "uid = " << filter_flag;
568

    
569
        if ( filter_flag != uid && !all )
570
        {
571
            uid_filter << " AND ( other_u = 1";
572

    
573
            for (g_it = user_groups.begin(); g_it != user_groups.end(); g_it++)
574
            {
575
                uid_filter << " OR ( gid = " << *g_it << " AND group_u = 1 )";
576
            }
577

    
578
            uid_filter << acl_str << ")";
579
        }
580
    }
581

    
582
    filter = uid_filter.str();
583
}
584

    
585
/* -------------------------------------------------------------------------- */
586

    
587
void PoolSQL::oid_filter(int     start_id,
588
                         int     end_id,
589
                         string& filter)
590
{
591
    ostringstream idfilter;
592

    
593
    if ( end_id >= -1 && start_id != -1 )
594
    {
595
        idfilter << "oid >= " << start_id;
596

    
597
        if ( end_id != -1 )
598
        {
599
            idfilter << " AND oid <= " << end_id;
600
        }
601
    }
602

    
603
    filter = idfilter.str();
604
}
605

    
606
/* -------------------------------------------------------------------------- */
607
/* -------------------------------------------------------------------------- */
608

    
609
void PoolSQL::register_hooks(vector<const VectorAttribute *> hook_mads,
610
                             const string&                   remotes_location)
611
{
612
    string name;
613
    string on;
614
    string cmd;
615
    string arg;
616

    
617
    for (unsigned int i = 0 ; i < hook_mads.size() ; i++ )
618
    {
619
        name = hook_mads[i]->vector_value("NAME");
620
        on   = hook_mads[i]->vector_value("ON");
621
        cmd  = hook_mads[i]->vector_value("COMMAND");
622
        arg  = hook_mads[i]->vector_value("ARGUMENTS");
623

    
624
        one_util::toupper(on);
625

    
626
        if ( on.empty() || cmd.empty() )
627
        {
628
            NebulaLog::log("VM", Log::WARNING, "Empty ON or COMMAND attribute"
629
                " in Hook, not registered!");
630

    
631
            continue;
632
        }
633

    
634
        if ( name.empty() )
635
        {
636
            name = cmd;
637
        }
638

    
639
        if (cmd[0] != '/')
640
        {
641
            ostringstream cmd_os;
642

    
643
            cmd_os << remotes_location << "/hooks/" << cmd;
644

    
645
            cmd = cmd_os.str();
646
        }
647

    
648
        if ( on == "CREATE" )
649
        {
650
            AllocateHook * hook;
651

    
652
            hook = new AllocateHook(name, cmd, arg, false);
653

    
654
            add_hook(hook);
655
        }
656
        else if ( on == "REMOVE" )
657
        {
658
            RemoveHook * hook;
659

    
660
            hook = new RemoveHook(name, cmd, arg, false);
661

    
662
            add_hook(hook);
663
        }
664
    }
665
}