Statistics
| Branch: | Tag: | Revision:

one / src / cluster / Cluster.cc @ 621a1869

History | View | Annotate | Download (12.6 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 <limits.h>
18
#include <string.h>
19

    
20
#include <iostream>
21
#include <sstream>
22

    
23
#include "Cluster.h"
24
#include "GroupPool.h"
25
#include "Nebula.h"
26

    
27
const char * Cluster::table = "cluster_pool";
28

    
29
const char * Cluster::db_names =
30
        "oid, name, body, uid, gid, owner_u, group_u, other_u";
31

    
32
const char * Cluster::db_bootstrap = "CREATE TABLE IF NOT EXISTS cluster_pool ("
33
    "oid INTEGER PRIMARY KEY, name VARCHAR(128), body MEDIUMTEXT, uid INTEGER, "
34
    "gid INTEGER, owner_u INTEGER, group_u INTEGER, other_u INTEGER, "
35
    "UNIQUE(name))";
36

    
37
const char * Cluster::host_table = "cluster_host_relation";
38
const char * Cluster::host_db_names = "cid, oid";
39
const char * Cluster::host_db_bootstrap =
40
    "CREATE TABLE IF NOT EXISTS cluster_host_relation ("
41
    "cid INTEGER, oid INTEGER, PRIMARY KEY(cid, oid))";
42

    
43
const char * Cluster::datastore_table = "cluster_datastore_relation";
44
const char * Cluster::datastore_db_names = "cid, oid";
45
const char * Cluster::datastore_db_bootstrap =
46
    "CREATE TABLE IF NOT EXISTS cluster_datastore_relation ("
47
    "cid INTEGER, oid INTEGER, PRIMARY KEY(cid, oid))";
48

    
49
const char * Cluster::network_table = "cluster_network_relation";
50
const char * Cluster::network_db_names = "cid, oid";
51
const char * Cluster::network_db_bootstrap =
52
    "CREATE TABLE IF NOT EXISTS cluster_network_relation ("
53
    "cid INTEGER, oid INTEGER, PRIMARY KEY(cid, oid))";
54

    
55
/* ************************************************************************** */
56
/* Cluster :: Constructor/Destructor                                          */
57
/* ************************************************************************** */
58

    
59
Cluster::Cluster(
60
        int id,
61
        const string& name,
62
        ClusterTemplate*  cl_template):
63
            PoolObjectSQL(id,CLUSTER,name,-1,-1,"","",table),
64
            hosts("HOSTS"),
65
            datastores("DATASTORES"),
66
            vnets("VNETS")
67
{
68
    if (cl_template != 0)
69
    {
70
        obj_template = cl_template;
71
    }
72
    else
73
    {
74
        obj_template = new ClusterTemplate;
75
    }
76

    
77
    string default_cpu; //TODO - Get these two from oned.conf
78
    string default_mem;
79

    
80
    add_template_attribute("RESERVED_CPU", default_cpu);
81
    add_template_attribute("RESERVED_MEM", default_cpu);
82
}
83

    
84
/* -------------------------------------------------------------------------- */
85
/* -------------------------------------------------------------------------- */
86

    
87
int Cluster::check_drop(string& error_msg)
88
{
89
    ostringstream oss;
90

    
91
    if ( hosts.size() > 0 )
92
    {
93
        oss << "Cluster " << oid << " is not empty, it contains "
94
            << hosts.size() << " hosts.";
95

    
96
        goto error_common;
97
    }
98

    
99
    if ( datastores.size() > 0 )
100
    {
101
        oss << "Cluster " << oid << " is not empty, it contains "
102
            << datastores.size() << " datastores.";
103

    
104
        goto error_common;
105
    }
106

    
107
    if ( vnets.size() > 0 )
108
    {
109
        oss << "Cluster " << oid << " is not empty, it contains "
110
            << vnets.size() << " vnets.";
111

    
112
        goto error_common;
113
    }
114

    
115
    return 0;
116

    
117
error_common:
118
    error_msg = oss.str();
119

    
120
    return -1;
121
}
122

    
123
/* -------------------------------------------------------------------------- */
124
/* -------------------------------------------------------------------------- */
125

    
126
string& Cluster::get_ds_location(string &ds_location)
127
{
128
    obj_template->get("DATASTORE_LOCATION", ds_location);
129

    
130
    if ( ds_location.empty() == true )
131
    {
132
        Nebula& nd = Nebula::instance();
133

    
134
        nd.get_configuration_attribute("DATASTORE_LOCATION", ds_location);
135
    }
136

    
137
    return ds_location;
138
}
139

    
140
/* -------------------------------------------------------------------------- */
141
/* -------------------------------------------------------------------------- */
142

    
143
int Cluster::add_datastore(int id, string& error_msg)
144
{
145
   int rc = datastores.add(id);
146

    
147
    if ( rc < 0 )
148
    {
149
        error_msg = "Datastore ID is already in the cluster set.";
150
    }
151

    
152
    return rc;
153
}
154

    
155
/* -------------------------------------------------------------------------- */
156
/* -------------------------------------------------------------------------- */
157

    
158
int Cluster::del_datastore(int id, string& error_msg)
159
{
160
    int rc = datastores.del(id);
161

    
162
    if ( rc < 0 )
163
    {
164
        error_msg = "Datastore ID is not part of the cluster set.";
165
    }
166

    
167
    return rc;
168
}
169

    
170
/* -------------------------------------------------------------------------- */
171
/* -------------------------------------------------------------------------- */
172

    
173
int Cluster::get_default_system_ds(const set<int>& ds_set)
174
{
175
    Nebula& nd = Nebula::instance();
176

    
177
    DatastorePool*  dspool = nd.get_dspool();
178
    Datastore*      ds;
179

    
180
    for (set<int>::const_iterator it = ds_set.begin(); it != ds_set.end(); it++)
181
    {
182
        ds = dspool->get(*it, true);
183

    
184
        if (ds == 0)
185
        {
186
            continue;
187
        }
188

    
189
        if (ds->get_type() == Datastore::SYSTEM_DS)
190
        {
191
            ds->unlock();
192

    
193
            return *it;
194
        }
195

    
196
        ds->unlock();
197
    }
198

    
199
    return -1;
200
}
201

    
202
/* ************************************************************************** */
203
/* Cluster :: Database Access Functions                                       */
204
/* ************************************************************************** */
205

    
206
int Cluster::insert_replace(SqlDB *db, bool replace, string& error_str)
207
{
208
    ostringstream   oss;
209

    
210
    int    rc;
211
    string xml_body;
212

    
213
    char * sql_name;
214
    char * sql_xml;
215

    
216
    // Set the owner and group to oneadmin
217
    set_user(0, "");
218
    set_group(GroupPool::ONEADMIN_ID, GroupPool::ONEADMIN_NAME);
219

    
220
    // Update the Cluster
221

    
222
    sql_name = db->escape_str(name.c_str());
223

    
224
    if ( sql_name == 0 )
225
    {
226
        goto error_name;
227
    }
228

    
229
    sql_xml = db->escape_str(to_xml(xml_body).c_str());
230

    
231
    if ( sql_xml == 0 )
232
    {
233
        goto error_body;
234
    }
235

    
236
    if ( validate_xml(sql_xml) != 0 )
237
    {
238
        goto error_xml;
239
    }
240

    
241
    if ( replace )
242
    {
243
        oss << "REPLACE";
244
    }
245
    else
246
    {
247
        oss << "INSERT";
248
    }
249

    
250
    // Construct the SQL statement to Insert or Replace
251

    
252
    oss <<" INTO "<<table <<" ("<< db_names <<") VALUES ("
253
        <<          oid                 << ","
254
        << "'" <<   sql_name            << "',"
255
        << "'" <<   sql_xml             << "',"
256
        <<          uid                 << ","
257
        <<          gid                 << ","
258
        <<          owner_u             << ","
259
        <<          group_u             << ","
260
        <<          other_u             << ")";
261

    
262

    
263
    rc = db->exec(oss);
264

    
265
    db->free_str(sql_name);
266
    db->free_str(sql_xml);
267

    
268
    if (rc == 0)
269
    {
270
        oss.str("");
271
        oss << "BEGIN TRANSACTION; "
272
            << "DELETE FROM " << host_table     << " WHERE cid = " << oid << "; "
273
            << "DELETE FROM " << network_table  << " WHERE cid = " << oid << "; "
274
            << "DELETE FROM " << datastore_table<< " WHERE cid = " << oid << "; ";
275

    
276
        // TODO
277
        //if (db->multiple_values_support())
278
        if (false)
279
        {
280
        }
281
        else
282
        {
283
            set<int>::iterator i;
284

    
285
            set<int> host_set = hosts.get_collection();
286

    
287
            for(i = host_set.begin(); i != host_set.end(); i++)
288
            {
289
                oss << "INSERT INTO " << host_table
290
                    << " (" << host_db_names << ") VALUES ("
291
                    << oid  << ","
292
                    << *i   << "); ";
293
            }
294

    
295
            set<int> datastore_set = datastores.get_collection();
296

    
297
            for(i = datastore_set.begin(); i != datastore_set.end(); i++)
298
            {
299
                oss << "INSERT INTO " << datastore_table
300
                    << " (" << datastore_db_names << ") VALUES ("
301
                    << oid  << ","
302
                    << *i   << "); ";
303
            }
304

    
305
            set<int> vnet_set = vnets.get_collection();
306

    
307
            for(i = vnet_set.begin(); i != vnet_set.end(); i++)
308
            {
309
                oss << "INSERT INTO " << network_table
310
                    << " (" << network_db_names << ") VALUES ("
311
                    << oid  << ","
312
                    << *i   << "); ";
313
            }
314
        }
315

    
316
        oss << "COMMIT";
317

    
318
        rc = db->exec(oss);
319
    }
320

    
321
    return rc;
322

    
323
error_xml:
324
    db->free_str(sql_name);
325
    db->free_str(sql_xml);
326

    
327
    error_str = "Error transforming the Cluster to XML.";
328

    
329
    goto error_common;
330

    
331
error_body:
332
    db->free_str(sql_name);
333
    goto error_generic;
334

    
335
error_name:
336
    goto error_generic;
337

    
338
error_generic:
339
    error_str = "Error inserting Cluster in DB.";
340
error_common:
341
    return -1;
342
}
343

    
344
/* -------------------------------------------------------------------------- */
345
/* -------------------------------------------------------------------------- */
346

    
347
string& Cluster::to_xml(string& xml) const
348
{
349
    ostringstream   oss;
350
    string          host_collection_xml;
351
    string          ds_collection_xml;
352
    string          vnet_collection_xml;
353
    string          template_xml;
354

    
355
    oss <<
356
    "<CLUSTER>"  <<
357
        "<ID>"          << oid          << "</ID>"          <<
358
        "<NAME>"        << name         << "</NAME>"        <<
359
        hosts.to_xml(host_collection_xml)    <<
360
        datastores.to_xml(ds_collection_xml) <<
361
        vnets.to_xml(vnet_collection_xml)    <<
362
        obj_template->to_xml(template_xml)   <<
363
    "</CLUSTER>";
364

    
365
    xml = oss.str();
366

    
367
    return xml;
368
}
369

    
370
/* -------------------------------------------------------------------------- */
371
/* -------------------------------------------------------------------------- */
372

    
373
int Cluster::from_xml(const string& xml)
374
{
375
    int rc = 0;
376
    vector<xmlNodePtr> content;
377

    
378
    // Initialize the internal XML object
379
    update_from_str(xml);
380

    
381
    // Get class base attributes
382
    rc += xpath(oid,        "/CLUSTER/ID",          -1);
383
    rc += xpath(name,       "/CLUSTER/NAME",        "not_found");
384

    
385
    // Set oneadmin as the owner
386
    set_user(0,"");
387

    
388
    // Set the Cluster ID as the cluster it belongs to
389
    set_group(oid, name);
390

    
391
    // -------------------------------------------------------------------------
392
    // Get associated hosts
393
    // -------------------------------------------------------------------------
394
    ObjectXML::get_nodes("/CLUSTER/HOSTS", content);
395

    
396
    if (content.empty())
397
    {
398
        return -1;
399
    }
400

    
401
    // Set of IDs
402
    rc += hosts.from_xml_node(content[0]);
403

    
404
    ObjectXML::free_nodes(content);
405
    content.clear();
406

    
407
    // -------------------------------------------------------------------------
408
    // Get associated datastores
409
    // -------------------------------------------------------------------------
410
    ObjectXML::get_nodes("/CLUSTER/DATASTORES", content);
411

    
412
    if (content.empty())
413
    {
414
        return -1;
415
    }
416

    
417
    // Set of IDs
418
    rc += datastores.from_xml_node(content[0]);
419

    
420
    ObjectXML::free_nodes(content);
421
    content.clear();
422

    
423
    // -------------------------------------------------------------------------
424
    // Get associated vnets
425
    // -------------------------------------------------------------------------
426
    ObjectXML::get_nodes("/CLUSTER/VNETS", content);
427

    
428
    if (content.empty())
429
    {
430
        return -1;
431
    }
432

    
433
    // Set of IDs
434
    rc += vnets.from_xml_node(content[0]);
435

    
436
    ObjectXML::free_nodes(content);
437
    content.clear();
438

    
439
    // Get associated classes
440
    ObjectXML::get_nodes("/CLUSTER/TEMPLATE", content);
441

    
442
    if (content.empty())
443
    {
444
        return -1;
445
    }
446

    
447
    rc += obj_template->from_xml_node(content[0]);
448

    
449
    ObjectXML::free_nodes(content);
450

    
451
    if (rc != 0)
452
    {
453
        return -1;
454
    }
455

    
456
    return 0;
457
}
458

    
459
/* -------------------------------------------------------------------------- */
460
/* -------------------------------------------------------------------------- */
461