1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-01-07 17:17:41 +03:00

Merge remote branch 'origin/master' into feature-1223

This commit is contained in:
Carlos Martín 2012-06-12 15:41:36 +02:00
commit 17635e19c3
108 changed files with 4213 additions and 2079 deletions

View File

@ -18,6 +18,7 @@
#define ACL_MANAGER_H_
#include "AuthManager.h"
#include "AuthRequest.h"
#include "PoolObjectSQL.h"
#include "AclRule.h"

View File

@ -239,7 +239,10 @@ public:
};
/**
* Returns the string value
* @param name of the attribute
*
* @return the value of the attribute if found, empty otherwise
*/
string vector_value(const char *name) const;
@ -251,7 +254,18 @@ public:
*
* @return 0 on success, -1 otherwise
*/
int vector_value(const char *name, int & value) const;
int vector_value(const char *name, int& value) const;
/**
* Returns the integer value
*
* @param name Name of the attribute
* @param value Integer value, if an error ocurred the string returned is
* empty and value set to -1;
*
* @return the value in string form on success, "" otherwise
*/
string vector_value_str(const char *name, int& value) const;
/**
* Marshall the attribute in a single string. The string MUST be freed
@ -290,7 +304,19 @@ public:
* Replace the value of the given vector attribute
*/
void replace(const string& name, const string& value);
/**
* Replace the value of the given vector attribute
*/
void replace(const string& name, int value)
{
ostringstream oss;
oss << value;
replace(name, oss.str());
}
/**
* Returns the attribute type
*/

View File

@ -21,11 +21,8 @@
#include "MadManager.h"
#include "ActionManager.h"
#include "SSLTools.h"
#include "AuthManagerDriver.h"
#include "PoolObjectSQL.h"
#include "PoolObjectAuth.h"
using namespace std;
@ -43,16 +40,11 @@ class AuthManager : public MadManager, public ActionListener
public:
AuthManager(
time_t timer,
time_t __time_out,
vector<const Attribute*>& _mads):
time_t timer,
vector<const Attribute*>& _mads):
MadManager(_mads), timer_period(timer)
{
_time_out = __time_out;
am.addListener(this);
pthread_mutex_init(&mutex,0);
};
~AuthManager(){};
@ -99,32 +91,6 @@ public:
return authm_thread;
};
/**
* Notify the result of an auth request
*/
void notify_request(int auth_id, bool result, const string& message);
/**
* Discards a pending request. Call this before freeing not notified or
* timeout requests.
*/
void discard_request(int auth_id)
{
lock();
auth_requests.erase(auth_id);
unlock();
}
/**
* Gets default timeout for Auth requests
*/
static time_t time_out()
{
return _time_out;
}
/**
* Returns true if there is an authorization driver enabled
*
@ -146,21 +112,6 @@ private:
*/
ActionManager am;
/**
* List of pending requests
*/
map<int, AuthRequest *> auth_requests;
/**
* Mutex to access the auth_requests
*/
pthread_mutex_t mutex;
/**
* Default timeout for Auth requests
*/
static time_t _time_out;
/**
* Timer for the Manager (periocally triggers timer action)
*/
@ -230,287 +181,6 @@ private:
* This function authorizes a user request
*/
void authorize_action(AuthRequest * ar);
/**
* This function is periodically executed to check time_outs on requests
*/
void timer_action();
/**
* Function to lock the pool
*/
void lock()
{
pthread_mutex_lock(&mutex);
};
/**
* Function to unlock the pool
*/
void unlock()
{
pthread_mutex_unlock(&mutex);
};
/**
* Add a new request to the Request map
* @param ar pointer to the AuthRequest
* @return the id for the request
*/
int add_request(AuthRequest *ar);
/**
* Gets request from the Request map
* @param id for the request
* @return pointer to the AuthRequest
*/
AuthRequest * get_request(int id);
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/**
* The AuthRequest class is used to pass an Authorization or Authentication
* request to the AuthManager. The result of the request will be stored
* in the result and message attributes of this class.
*/
class AuthRequest : public ActionListener
{
public:
AuthRequest(int _uid, int _gid):
result(false),
timeout(false),
uid(_uid),
gid(_gid),
time_out(0),
self_authorize(true)
{
am.addListener(this);
};
~AuthRequest(){};
/**
* Authorization Request Type
*/
enum Operation
{
USE = 0x1LL, /**< Auth. to use an object */
MANAGE = 0x2LL, /**< Auth. to perform management actions */
ADMIN = 0x4LL, /**< Auth. to perform administrative actions */
CREATE = 0x8LL /**< Auth. to create an object */
};
static string operation_to_str(Operation op)
{
switch (op)
{
case USE: return "USE";
case MANAGE: return "MANAGE";
case ADMIN: return "ADMIN";
case CREATE: return "CREATE";
default: return "";
}
};
/**
* Sets the challenge to authenticate an user
* @param challenge a driver specific authentication challenge
*/
void add_authenticate(const string &_driver,
const string &_username,
const string &_password,
const string &_session)
{
username = _username;
password = _password;
session = _session;
driver = _driver;
}
/**
* Adds a CREATE authorization request.
*
* OBJECT:<-1|OBJECT_TMPL_XML64>:CREATE:UID:AUTH
*
* @param type of the object to be created
* @param template (base64 encoded) of the new object
*/
void add_create_auth(PoolObjectSQL::ObjectType type, const string& txml_64)
{
PoolObjectAuth perms; //oid & gid set to -1
perms.uid = uid;
perms.obj_type = type;
add_auth(AuthRequest::CREATE, perms, txml_64);
}
/**
* Adds a new authorization item to this request
*
* OBJECT:OBJECT_ID:ACTION:OWNER:AUTH
*
* @param op the operation to be authorized
* @param ob_perms object's permission attributes
*/
void add_auth(Operation op,
const PoolObjectAuth& ob_perms)
{
add_auth(op, ob_perms, "");
}
/**
* Gets the authorization requests in a single string
* @return a space separated list of auth requests, or an empty string if
* no auth requests were added
*/
string get_auths()
{
ostringstream oss;
unsigned int i;
if ( auths.empty() )
{
return string();
}
for (i=0; i<auths.size()-1; i++)
{
oss << auths[i] << " ";
}
oss << auths[i];
return oss.str();
};
/**
* Notify client that we have an answer for the request
*/
void notify()
{
am.trigger(ActionListener::ACTION_FINALIZE,0);
};
/**
* Wait for the AuthRequest to be completed
*/
void wait()
{
time_out = time(0) + AuthManager::time_out();
am.loop(0,0);
};
bool core_authorize()
{
return ( uid == 0 || self_authorize );
}
bool core_authenticate()
{
string sha1_session = SSLTools::sha1_digest(session);
return (password == sha1_session);
}
/**
* The result of the request, true if authorized or authenticated
*/
bool result;
/**
* Error message for negative results
*/
string message;
/**
* Time out
*/
bool timeout;
/**
* Identification of this request
*/
int id;
private:
friend class AuthManager;
/**
* The ActionManager that will be notify when the request is ready.
*/
ActionManager am;
/**
* The user id for this request
*/
int uid;
/**
* The user group ID
*/
int gid;
/**
* Timeout for this request
*/
time_t time_out;
/**
* Username to authenticate the user
*/
string username;
/**
* User password to authenticate the user
*/
string password;
/**
* Authentication token as sent in the XML-RPC call (user:session)
*/
string session;
/**
* Authentication driver to be used with this request
*/
string driver;
/**
* A list of authorization requests
*/
vector<string> auths;
/**
* Plain authorization for the request
*/
bool self_authorize;
/**
* No actions defined for the Auth request, just FINALIZE when done
*/
void do_action(const string &name, void *args){};
/**
* Adds a new authorization item to this request, with a template for
* a new object
*
* OBJECT:<OBJECT_ID|OBJECT_TMPL_XML64>:ACTION:OWNER:AUTH
*
* @param op the operation to be authorized
* @param ob_perms object's permission attributes
* @param ob_template new object's template. If it is empty,
* it will be ignored
*/
void add_auth(Operation op,
const PoolObjectAuth& ob_perms,
string ob_template);
};
#endif /*AUTH_MANAGER_H*/

211
include/AuthRequest.h Normal file
View File

@ -0,0 +1,211 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#ifndef AUTH_REQUEST_H_
#define AUTH_REQUEST_H_
#include <time.h>
#include "ActionManager.h"
#include "PoolObjectAuth.h"
#include "SSLTools.h"
#include "AuthManager.h"
#include "SyncRequest.h"
using namespace std;
/**
* The AuthRequest class is used to pass an Authorization or Authentication
* request to the AuthManager. The result of the request will be stored
* in the result and message attributes of this class.
*/
class AuthRequest : public SyncRequest
{
public:
AuthRequest(int _uid, int _gid): uid(_uid),gid(_gid),self_authorize(true){};
~AuthRequest(){};
/**
* Authorization Request Type
*/
enum Operation
{
USE = 0x1LL, /**< Auth. to use an object */
MANAGE = 0x2LL, /**< Auth. to perform management actions */
ADMIN = 0x4LL, /**< Auth. to perform administrative actions */
CREATE = 0x8LL /**< Auth. to create an object */
};
static string operation_to_str(Operation op)
{
switch (op)
{
case USE: return "USE";
case MANAGE: return "MANAGE";
case ADMIN: return "ADMIN";
case CREATE: return "CREATE";
default: return "";
}
};
/**
* Sets the challenge to authenticate an user
* @param challenge a driver specific authentication challenge
*/
void add_authenticate(const string &_driver,
const string &_username,
const string &_password,
const string &_session)
{
username = _username;
password = _password;
session = _session;
driver = _driver;
}
/**
* Adds a CREATE authorization request.
*
* OBJECT:<-1|OBJECT_TMPL_XML64>:CREATE:UID:AUTH
*
* @param type of the object to be created
* @param template (base64 encoded) of the new object
*/
void add_create_auth(PoolObjectSQL::ObjectType type, const string& txml_64)
{
PoolObjectAuth perms; //oid & gid set to -1
perms.uid = uid;
perms.obj_type = type;
add_auth(AuthRequest::CREATE, perms, txml_64);
}
/**
* Adds a new authorization item to this request
*
* OBJECT:OBJECT_ID:ACTION:OWNER:AUTH
*
* @param op the operation to be authorized
* @param ob_perms object's permission attributes
*/
void add_auth(Operation op,
const PoolObjectAuth& ob_perms)
{
add_auth(op, ob_perms, "");
}
/**
* Gets the authorization requests in a single string
* @return a space separated list of auth requests, or an empty string if
* no auth requests were added
*/
string get_auths()
{
ostringstream oss;
unsigned int i;
if ( auths.empty() )
{
return string();
}
for (i=0; i<auths.size()-1; i++)
{
oss << auths[i] << " ";
}
oss << auths[i];
return oss.str();
};
bool core_authorize()
{
return ( uid == 0 || self_authorize );
}
bool core_authenticate()
{
string sha1_session = SSLTools::sha1_digest(session);
return (password == sha1_session);
}
private:
friend class AuthManager;
/**
* The user id for this request
*/
int uid;
/**
* The user group ID
*/
int gid;
/**
* Username to authenticate the user
*/
string username;
/**
* User password to authenticate the user
*/
string password;
/**
* Authentication token as sent in the XML-RPC call (user:session)
*/
string session;
/**
* Authentication driver to be used with this request
*/
string driver;
/**
* A list of authorization requests
*/
vector<string> auths;
/**
* Plain authorization for the request
*/
bool self_authorize;
/**
* Adds a new authorization item to this request, with a template for
* a new object
*
* OBJECT:<OBJECT_ID|OBJECT_TMPL_XML64>:ACTION:OWNER:AUTH
*
* @param op the operation to be authorized
* @param ob_perms object's permission attributes
* @param ob_template new object's template. If it is empty,
* it will be ignored
*/
void add_auth(Operation op,
const PoolObjectAuth& ob_perms,
string ob_template);
};
#endif

View File

@ -20,6 +20,7 @@
#include "PoolSQL.h"
#include "ObjectCollection.h"
#include "User.h"
#include "Quotas.h"
using namespace std;
@ -65,6 +66,11 @@ public:
return del_collection_id(id);
}
/**
* Object quotas, provides set and check interface
*/
Quotas quota;
private:
// -------------------------------------------------------------------------
@ -79,7 +85,11 @@ private:
Group(int id, const string& name):
PoolObjectSQL(id,GROUP,name,-1,-1,"","",table),
ObjectCollection("USERS")
ObjectCollection("USERS"),
quota("/GROUP/DATASTORE_QUOTA",
"/GROUP/NETWORK_QUOTA",
"/GROUP/IMAGE_QUOTA",
"/GROUP/VM_QUOTA")
{
// Allow users in this group to see it
group_u = 1;

View File

@ -55,6 +55,13 @@ public:
}
};
/**
* Return the string representation of an ImageType
* @param ob the type
* @return the string
*/
static ImageType str_to_type(string& str_type);
/**
* Type of Disks (used by the VMM_MAD). Values: BLOCK, CDROM or
* FILE

View File

@ -26,6 +26,7 @@ using namespace std;
extern "C" void * image_action_loop(void *arg);
class Image;
class Template;
class ImageManager : public MadManager, public ActionListener
{
@ -125,6 +126,18 @@ public:
*/
int delete_image(int iid, const string& ds_data);
/**
* Gets the size of an image by calling the STAT action of the associated
* datastore driver.
*
* @param img_tmpl the template for the image
* @param ds_tmpl the template for the datastore
* @oaram result with a string representation of the size or if an error
* occurred describing the error.
* @result 0 on success
*/
int stat_image(Template* img_tmpl, const string& ds_tmpl, string& res);
private:
/**
* Generic name for the Image driver

View File

@ -71,27 +71,26 @@ private:
//Template driver_conf;
/**
* Sends a copy request to the MAD
* Sends a copy request to the MAD.
* @param oid the image id.
* @param drv_msg xml data for the mad operation.
*/
void cp(int oid, const string& drv_msg) const;
/**
* Sends a move request to the MAD: "MV IMAGE_ID SRC_PATH DST_PATH"
* @param oid the image id.
* @param destination is a driver specific location or "-" if not
* initialized
* @param size_mb of the image to be created
* Sends a stat request to the MAD.
* @param oid the id of the stat request
* @param drv_msg xml data for the mad operation.
*/
void mv(int oid, const string& source, const string& destination) const;
void stat(int oid, const string& drv_msg) const;
/**
* Sends a make filesystem request to the MAD: "MKFS IMAGE_ID PATH SIZE_MB"
* Sends a make filesystem request to the MAD.
* @param oid the image id.
* @param drv_msg xml data for the mad operation.
*/
void mkfs(int oid, const string& drv_msg) const;
/**
* Sends a delete request to the MAD: "DELETE IMAGE_ID PATH"
* @param oid the image id.

View File

@ -30,6 +30,8 @@
using namespace std;
class SyncRequest;
extern "C" void * mad_manager_listener(void * _mm);
/**
@ -54,7 +56,12 @@ public:
* sudo application.
*/
virtual void load_mads(int uid) = 0;
/**
* Notify the result of an auth request
*/
void notify_request(int id, bool result, const string& message);
protected:
MadManager(vector<const Attribute *>& _mads);
@ -93,7 +100,28 @@ protected:
* @return 0 on success.
*/
int add(Mad *mad);
/**
* This function can be periodically executed to check time_outs on
* request. It will fail requests with an expired timeout and will notify
* the clients.
*/
void check_time_outs_action();
/**
* Add a new request to the Request map
* @param ar pointer to the request
* @return the id for the request
*/
void add_request(SyncRequest *ar);
/**
* Gets request from the Request map
* @param id for the request
* @return pointer to the Request
*/
SyncRequest * get_request(int id);
private:
/**
* Function to lock the Manager
@ -155,11 +183,16 @@ private:
* can be free upon listener thread cancellation.
*/
ostringstream buffer;
/**
* List of pending requests
*/
map<int, SyncRequest *> sync_requests;
/**
* Listener thread implementation.
*/
void listener();
void listener();
};
#endif /*MAD_MANAGER_H_*/

175
include/Quota.h Normal file
View File

@ -0,0 +1,175 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#ifndef QUOTA_H_
#define QUOTA_H_
#include "Template.h"
/**
* Base class for resource quotas, it provides basic storage and management of
* the quotas. Each resource MUST inherit from it to implement check and
* update methods. Quotas are stored in a template form, each class store the
* limits and usage in a resource specific format.
*/
class Quota: public Template
{
public:
/**
* Set the quotas. If the quota previously exists its limit is updated.
* @param quota_str the quota template in ASCII or XML formats
* @param error describe the error in case of error
* @return 0 on success -1 otherwise
*/
int set(vector<Attribute*> * quotas, string& error);
/**
* Check if the resource allocation will exceed the quota limits. If not
* the usage counters are updated
* @param tmpl template for the resource
* @param error string
* @return true if the operation can be performed
*/
virtual bool check(Template* tmpl, string& error) = 0;
/**
* Decrement usage counters when deallocating image
* @param tmpl template for the resource
*/
virtual void del(Template* tmpl) = 0;
/**
* Returns the name that identifies the quota in a template
*/
const char * get_quota_name()
{
return template_name;
}
protected:
Quota(const char * quota_name,
const char * _template_name,
const char ** _metrics,
int _num_metrics)
: Template(false, '=', quota_name),
template_name(_template_name),
metrics(_metrics),
num_metrics(_num_metrics){};
virtual ~Quota(){};
/**
* Generic Quota Names
*
* template_name = [
* ID = "ID to identify the resource",
* metrics[0] = "Limit for the first metric"
* metrics[0]_USED = "Usage for metric"
* ]
*
* ID & counter fields are optional
*/
/**
* Name of the quota used in the templates
*/
const char * template_name;
/**
* The name of the quota metrics
*/
const char ** metrics;
/**
* Length
*/
int num_metrics;
/**
* Check a given quota for an usage request and update counters if the
* request does not exceed quota limits
* @param qid id that identifies the quota, to be used by get_quota
* @param usage_req usage for each metric
* @return true if the request does not exceed current limits
*/
bool check_quota(const string& qid,
map<string, int>& usage_req,
string& error);
/**
* Reduce usage from a given quota based on the current consumption
* @param qid id that identifies the quota, to be used by get_quota
* @param usage_req usage for each metric
*/
void del_quota(const string& qid,
map<string, int>& usage_req);
/**
* Gets a quota identified by its ID.
* @param id of the quota
* @return a pointer to the quota or 0 if not found
*/
virtual int get_quota(const string& id, VectorAttribute **va);
private:
/**
* Creates an empty quota based on the given attribute. The attribute va
* contains the limits for the quota.
* @param va limits for the new quota if 0 limits will be 0
* @return a new attribute representing the quota
*/
VectorAttribute * new_quota(VectorAttribute* va);
/**
* Adds a new quota, it also updates an internal index for fast accessing
* the quotas
* @param quota is the new quota, allocated in the HEAP
*/
void add(VectorAttribute * nq)
{
attributes.insert(make_pair(nq->name(), nq));
}
/**
* Adds a given value to the current quota (vector)
* @param attr the quota;
* @param va_name name of the quota in the vector attribute
* @param num value to add to the current quota;
*/
void add_to_quota(VectorAttribute * attr, const string& va_name, int num);
/**
* Sets new limit values for the quota
* @param quota to be updated
* @param va attribute with the new limits
* @return 0 on success or -1 if wrong limits
*/
int update_limits(VectorAttribute* quota, const VectorAttribute* va);
/**
* Extract the limits for the defined quota metrics from a given attribute
* @param va the attribute with the limits
* @param limits stores the known limits
* @return 0 on success
*/
int get_limits(const VectorAttribute * va, map<string, string>& limits);
};
#endif /*QUOTA_H_*/

68
include/QuotaDatastore.h Normal file
View File

@ -0,0 +1,68 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#ifndef QUOTA_DATASTORE_H_
#define QUOTA_DATASTORE_H_
#include "Quota.h"
/**
* DataStore Quotas, defined as:
* DATASTORE = [
* ID = <ID of the datastore>
* IMAGES = <Max. number of images allowed in the datastore>
* SIZE = <Max. number of MB used in the datastore>
* IMAGES_USED = Current number of images in the datastore
* SIZE_USED = Current storage capacity un the datastore
* ]
*
* 0 = unlimited, default if missing
*/
class QuotaDatastore : public Quota
{
public:
QuotaDatastore():Quota("DATASTORE_QUOTA",
"DATASTORE",
DS_METRICS,
NUM_DS_METRICS)
{};
~QuotaDatastore(){};
/**
* Check if the resource allocation will exceed the quota limits. If not
* the usage counters are updated
* @param tmpl template for the resource
* @param error string
* @return true if the operation can be performed
*/
bool check(Template* tmpl, string& error);
/**
* Decrement usage counters when deallocating image
* @param tmpl template for the resource
*/
void del(Template* tmpl);
protected:
static const char * DS_METRICS[];
static const int NUM_DS_METRICS;
};
#endif /*QUOTA_DATASTORE_H_*/

66
include/QuotaImage.h Normal file
View File

@ -0,0 +1,66 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#ifndef QUOTA_IMAGE_H_
#define QUOTA_IMAGE_H_
#include "Quota.h"
/**
* Image Quotas, defined as:
* IMAGE = [
* ID = <ID of the image>
* RVMS = <Max. number times the image can be instantiated>
* RVMS _USED = Current number of VMs using the image
* ]
*
* 0 = unlimited, default if missing
*/
class QuotaImage : public Quota
{
public:
QuotaImage():Quota("IMAGE_QUOTA",
"IMAGE",
IMAGE_METRICS,
NUM_IMAGE_METRICS)
{};
~QuotaImage(){};
/**
* Check if the resource allocation will exceed the quota limits. If not
* the usage counters are updated
* @param tmpl template for the resource
* @param error string
* @return true if the operation can be performed
*/
bool check(Template* tmpl, string& error);
/**
* Decrement usage counters when deallocating image
* @param tmpl template for the resource
*/
void del(Template* tmpl);
protected:
static const char * IMAGE_METRICS[];
static const int NUM_IMAGE_METRICS;
};
#endif /*QUOTA_IMAGE_H_*/

66
include/QuotaNetwork.h Normal file
View File

@ -0,0 +1,66 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#ifndef QUOTA_NETWORK_H_
#define QUOTA_NETWORK_H_
#include "Quota.h"
/**
* DataStore Quotas, defined as:
* NETWORK = [
* ID = <ID of the datastore>
* LEASES = <Max. number of IPs that can be leased from net>
* LEASES_USED = Current number of IPs
* ]
*
* 0 = unlimited, default if missing
*/
class QuotaNetwork : public Quota
{
public:
QuotaNetwork():Quota("NETWORK_QUOTA",
"NETWORK",
NET_METRICS,
NUM_NET_METRICS)
{};
~QuotaNetwork(){};
/**
* Check if the resource allocation will exceed the quota limits. If not
* the usage counters are updated
* @param tmpl template for the resource
* @param error string
* @return true if the operation can be performed
*/
bool check(Template* tmpl, string& error);
/**
* Decrement usage counters when deallocating image
* @param tmpl template for the resource
*/
void del(Template* tmpl);
protected:
static const char * NET_METRICS[];
static const int NUM_NET_METRICS;
};
#endif /*QUOTA_NETWORK_H_*/

View File

@ -0,0 +1,76 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#ifndef QUOTA_VIRTUALMACHINE_H_
#define QUOTA_VIRTUALMACHINE_H_
#include "Quota.h"
/**
* VM Quotas, defined as:
* VM = [
* VMS = <Max. number of VMs>
* MEMORY = <Max. number of MB requested by VMs>
* CPU = <Max. number of CPU units requested by VMs>
* VMS_USED = Current number of VMs
* MEMORY_USED = Overall Memory requested
* CPU_USED = Overall CPU requested
* ]
*
* 0 = unlimited, default if missing
*/
class QuotaVirtualMachine : public Quota
{
public:
QuotaVirtualMachine():Quota("VM_QUOTA",
"VM",
VM_METRICS,
NUM_VM_METRICS)
{};
~QuotaVirtualMachine(){};
/**
* Check if the resource allocation will exceed the quota limits. If not
* the usage counters are updated
* @param tmpl template for the resource
* @param error string
* @return true if the operation can be performed
*/
bool check(Template* tmpl, string& error);
/**
* Decrement usage counters when deallocating image
* @param tmpl template for the resource
*/
void del(Template* tmpl);
/**
* Gets a quota, overrides base to not to use ID.
* @param id of the quota
* @return a pointer to the quota or 0 if not found
*/
int get_quota(const string& id, VectorAttribute **va);
protected:
static const char * VM_METRICS[];
static const int NUM_VM_METRICS;
};
#endif /*QUOTA_VIRTUALMACHINE_H_*/

284
include/Quotas.h Normal file
View File

@ -0,0 +1,284 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#ifndef QUOTAS_H_
#define QUOTAS_H_
#include "QuotaDatastore.h"
#include "QuotaNetwork.h"
#include "QuotaVirtualMachine.h"
#include "QuotaImage.h"
class Quotas
{
public:
Quotas(const char * _ds_xpath,
const char * _net_xpath,
const char * _img_xpath,
const char * _vm_xpath):
ds_xpath(_ds_xpath),
net_xpath(_net_xpath),
img_xpath(_img_xpath),
vm_xpath(_vm_xpath)
{};
virtual ~Quotas(){};
/**
* Set the quotas
* @param tmpl contains the user quota limits
* @param error describes error when setting the quotas
*
* @return 0 on success, -1 otherwise
*/
int set(Template *tmpl, string& error)
{
vector<Attribute *> vquotas;
if ( tmpl->get(datastore_quota.get_quota_name(), vquotas) > 0 )
{
if ( datastore_quota.set(&vquotas, error) != 0 )
{
return -1;
}
vquotas.clear();
}
if ( tmpl->get(network_quota.get_quota_name(), vquotas) > 0 )
{
if ( network_quota.set(&vquotas, error) != 0 )
{
return -1;
}
vquotas.clear();
}
if ( tmpl->get(image_quota.get_quota_name(), vquotas) > 0 )
{
if ( image_quota.set(&vquotas, error) != 0 )
{
return -1;
}
vquotas.clear();
}
if ( tmpl->get(vm_quota.get_quota_name(), vquotas) > 0 )
{
if ( vm_quota.set(&vquotas, error) != 0 )
{
return -1;
}
vquotas.clear();
}
return 0;
}
/**
* Check Datastore quotas, it updates usage counters if quotas are not
* exceeded.
* @param tmpl template for the image
* @param reason string describing the error
* @return true if image can be allocated, false otherwise
*/
bool ds_check(Template * tmpl, string& reason)
{
return datastore_quota.check(tmpl, reason);
}
/**
* Delete usage from quota counters.
* @param tmpl template for the image, with usage
*/
void ds_del(Template * tmpl)
{
return datastore_quota.del(tmpl);
}
/**
* Check Virtual Machine quotas (network, image and compute), it updates
* usage counters if quotas are not exceeded.
* @param tmpl template for the VirtualMachine
* @param error_str string describing the error
* @return true if VM can be allocated, false otherwise
*/
bool vm_check(Template * tmpl, string& error_str)
{
if ( network_quota.check(tmpl, error_str) == false )
{
return false;
}
if ( vm_quota.check(tmpl, error_str) == false )
{
network_quota.del(tmpl);
return false;
}
if ( image_quota.check(tmpl, error_str) == false )
{
network_quota.del(tmpl);
vm_quota.del(tmpl);
return false;
}
return true;
}
/**
* Delete VM related usage (network, image and compute) from quota counters.
* @param tmpl template for the image, with usage
*/
void vm_del(Template * tmpl)
{
network_quota.del(tmpl);
vm_quota.del(tmpl);
image_quota.del(tmpl);
}
/**
* Generates a string representation of the quotas in XML format
* @param xml the string to store the XML
* @return the same xml string to use it in << compounds
*/
string& to_xml(string& xml) const
{
ostringstream oss;
string ds_quota_xml;
string net_quota_xml;
string vm_quota_xml;
string image_quota_xml;
oss << datastore_quota.to_xml(ds_quota_xml)
<< network_quota.to_xml(net_quota_xml)
<< vm_quota.to_xml(vm_quota_xml)
<< image_quota.to_xml(image_quota_xml);
xml = oss.str();
return xml;
}
/**
* Builds quota object from an ObjectXML
* @param object_xml pointer to the ObjectXML
* @return 0 if success
*/
int from_xml(ObjectXML * object_xml)
{
vector<xmlNodePtr> content;
int rc = 0;
object_xml->get_nodes(ds_xpath, content);
if (!content.empty())
{
rc += datastore_quota.from_xml_node(content[0]);
}
object_xml->free_nodes(content);
content.clear();
object_xml->get_nodes(net_xpath, content);
if (!content.empty())
{
rc += network_quota.from_xml_node(content[0]);
}
object_xml->free_nodes(content);
content.clear();
object_xml->get_nodes(vm_xpath, content);
if (!content.empty())
{
rc += vm_quota.from_xml_node(content[0]);
}
object_xml->free_nodes(content);
content.clear();
object_xml->get_nodes(img_xpath, content);
if (!content.empty())
{
rc += image_quota.from_xml_node(content[0]);
}
object_xml->free_nodes(content);
return rc;
}
private:
//--------------------------------------------------------------------------
// Usage Counters and Quotas
//--------------------------------------------------------------------------
/**
* Datastore Quotas
*/
QuotaDatastore datastore_quota;
/**
* Network Quotas
*/
QuotaNetwork network_quota;
/**
* Image Quotas
*/
QuotaImage image_quota;
/**
* Virtual Machine Quotas
*/
QuotaVirtualMachine vm_quota;
//--------------------------------------------------------------------------
// XPaths
//--------------------------------------------------------------------------
/**
* Path for the datastore quota object
*/
const char * ds_xpath;
/**
* Path for the network quota object
*/
const char * net_xpath;
/**
* Path for the image quota object
*/
const char * img_xpath;
/**
* Path for the vm quota object
*/
const char * vm_xpath;
};
#endif /*QUOTABLE_H_*/

View File

@ -21,7 +21,7 @@
#include <xmlrpc-c/registry.hpp>
#include "RequestManager.h"
#include "AuthManager.h"
#include "AuthRequest.h"
#include "PoolObjectSQL.h"
using namespace std;
@ -75,6 +75,32 @@ protected:
string session; /**< Session from ONE XML-RPC API */
xmlrpc_c::value * retval; /**< Return value from libxmlrpc-c */
RequestAttributes(){};
RequestAttributes(const RequestAttributes& ra)
{
uid = ra.uid;
gid = ra.gid;
uname = ra.uname;
gname = ra.gname;
session = ra.session;
retval = ra.retval;
};
RequestAttributes(int _uid, int _gid, const RequestAttributes& ra)
{
uid = _uid;
gid = _gid;
uname = "";
gname = "";
session = ra.session;
retval = ra.retval;
};
};
/* -------- Static (shared among request of the same method) -------- */
@ -130,7 +156,54 @@ protected:
*/
bool basic_authorization(int oid, AuthRequest::Operation op,
RequestAttributes& att);
/**
* Performs a basic quota check for this request using the uid/gid and
* object type from the request. Usage counters are updated for the
* user/group.
* @param tmpl describing the object
* @param att the specific request attributes
*
* @return true if the user is authorized.
*/
bool quota_authorization(Template * tmpl, RequestAttributes& att)
{
return quota_authorization(tmpl, auth_object, att);
}
/**
* Performs a basic quota check for this request using the uid/gid
* from the request. Usage counters are updated for the user/group.
* @param tmpl describing the object
* @param object type of the object
* @param att the specific request attributes
*
* @return true if the user is authorized.
*/
bool quota_authorization(Template * tmpl,
PoolObjectSQL::ObjectType object,
RequestAttributes& att);
/**
* Performs rollback on usage counters for a previous quota check operation
* for the request.
* @param tmpl describing the object
* @param att the specific request attributes
*/
void quota_rollback(Template * tmpl, RequestAttributes& att)
{
quota_rollback(tmpl, auth_object, att);
}
/**
* Performs rollback on usage counters for a previous quota check operation
* for the request.
* @param tmpl describing the object
* @param att the specific request attributes
*/
void quota_rollback(Template * tmpl,
PoolObjectSQL::ObjectType object,
RequestAttributes& att);
/**
* Actual Execution method for the request. Must be implemented by the
* XML-RPC requests
@ -239,6 +312,27 @@ protected:
RequestAttributes& att,
PoolObjectAuth& perms,
string& name);
private:
/* ------------- Functions to manage user and group quotas -------------- */
bool user_quota_authorization(Template * tmpl,
PoolObjectSQL::ObjectType object,
RequestAttributes& att,
string& error_str);
bool group_quota_authorization(Template * tmpl,
PoolObjectSQL::ObjectType object,
RequestAttributes& att,
string& error_str);
void user_quota_rollback(Template * tmpl,
PoolObjectSQL::ObjectType object,
RequestAttributes& att);
void group_quota_rollback(Template * tmpl,
PoolObjectSQL::ObjectType object,
RequestAttributes& att);
};
/* -------------------------------------------------------------------------- */

View File

@ -52,6 +52,11 @@ protected:
virtual void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att);
PoolObjectSQL * get_and_quota(int oid,
int new_uid,
int new_gid,
RequestAttributes& att);
};
/* ------------------------------------------------------------------------- */

View File

@ -0,0 +1,72 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#ifndef REQUEST_MANAGER_GROUP_H
#define REQUEST_MANAGER_GROUP_H
#include "Request.h"
#include "Nebula.h"
using namespace std;
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class RequestManagerGroup: public Request
{
protected:
RequestManagerGroup(const string& method_name,
const string& help,
const string& params)
:Request(method_name,params,help)
{
Nebula& nd = Nebula::instance();
pool = nd.get_gpool();
auth_object = PoolObjectSQL::GROUP;
};
virtual ~RequestManagerGroup(){};
virtual void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att) = 0;
};
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class GroupSetQuota : public RequestManagerGroup
{
public:
GroupSetQuota():
RequestManagerGroup("GroupSetQuota",
"Sets group quota limits",
"A:sis")
{
auth_op = AuthRequest::ADMIN;
};
~GroupSetQuota(){};
void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att);
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
#endif

View File

@ -97,6 +97,27 @@ public:
string& err);
};
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class UserSetQuota : public RequestManagerUser
{
public:
UserSetQuota():
RequestManagerUser("UserSetQuota",
"Sets user quota limits",
"A:sis")
{
auth_op = AuthRequest::ADMIN;
};
~UserSetQuota(){};
int user_action(int user_id,
xmlrpc_c::paramList const& _paramList,
string& err);
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

101
include/SyncRequest.h Normal file
View File

@ -0,0 +1,101 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#ifndef SYNC_REQUEST_H_
#define SYNC_REQUEST_H_
#include <time.h>
#include "ActionManager.h"
/**
* Base class to implement synchronous operation in the MadManagers. This class
* cannot be directly instantiated.
*/
class SyncRequest: public ActionListener
{
public:
SyncRequest():
result(false),
message(""),
timeout(false),
id(-1),
time_out(0)
{
am.addListener(this);
};
virtual ~SyncRequest(){};
/**
* The result of the request, true if the operation succeeded
*/
bool result;
/**
* Error message for negative results
*/
string message;
/**
* Time out, true if the request ended because of a time out
*/
bool timeout;
/**
* Identification of this request
*/
int id;
/**
* Notify client that we have an answer for the request
*/
void notify()
{
am.trigger(ActionListener::ACTION_FINALIZE,0);
};
/**
* Wait for the AuthRequest to be completed
*/
void wait()
{
time_out = time(0) + 90;//Requests will expire in 1.5 minutes
am.loop(0,0);
};
protected:
friend class MadManager;
/**
* Time in seconds when this request will expire
*/
time_t time_out;
/**
* The ActionManager that will be notify when the request is ready.
*/
ActionManager am;
/**
* No actions defined for the request, just FINALIZE when done
*/
void do_action(const string &name, void *args){};
};
#endif /*SYNC_REQUEST_H_*/

View File

@ -134,6 +134,30 @@ public:
*/
virtual void set(Attribute * attr);
/**
* Adds a new single attribute to the template.
* @param name of the attribute
* @param value of the attribute
*/
void add(const string& name, const string& value)
{
set(new SingleAttribute(name, value));
}
/**
* Adds a new single attribute to the template.
* @param name of the attribute
* @param value of the attribute
*/
void add(const string& name, int value)
{
ostringstream oss;
oss << value;
set(new SingleAttribute(name, oss.str()));
}
/**
* Removes an attribute from the template. The attributes are returned. The
* attributes MUST be freed by the calling funtion

View File

@ -19,6 +19,7 @@
#include "PoolSQL.h"
#include "UserTemplate.h"
#include "Quotas.h"
using namespace std;
@ -166,7 +167,12 @@ public:
{
return new UserTemplate;
}
/**
* Object quotas, provides set and check interface
*/
Quotas quota;
private:
// -------------------------------------------------------------------------
// Friends
@ -289,6 +295,10 @@ protected:
const string& _auth_driver,
bool _enabled):
PoolObjectSQL(id,USER,_uname,-1,_gid,"",_gname,table),
quota("/USER/DATASTORE_QUOTA",
"/USER/NETWORK_QUOTA",
"/USER/IMAGE_QUOTA",
"/USER/VM_QUOTA"),
password(_password),
auth_driver(_auth_driver),
enabled(_enabled),

View File

@ -131,7 +131,8 @@ public:
string& uname,
string& gname);
/**
* Returns whether there is a user with given username/password or not
* Returns whether the operations described in a authorization request are
* authorized ot not.
* @param ar, an Authorization Request
* @return -1 if authz failed, 0 otherwise
*/

View File

@ -569,6 +569,17 @@ public:
return new VirtualMachineTemplate;
}
/**
* Returns a copy of the VirtualMachineTemplate
* @return A copy of the VirtualMachineTemplate
*/
VirtualMachineTemplate * clone_template() const
{
return new VirtualMachineTemplate(
*(static_cast<VirtualMachineTemplate *>(obj_template)));
};
// ------------------------------------------------------------------------
// States
// ------------------------------------------------------------------------

View File

@ -76,6 +76,26 @@ public:
return static_cast<VirtualMachine *>(PoolSQL::get(oid,lock));
};
/**
* Function to get a VM from the pool, string version for VM ID
*/
VirtualMachine * get(
const string& oid_s,
bool lock)
{
istringstream iss(oid_s);
int oid;
iss >> oid;
if ( iss.fail() )
{
return 0;
}
return static_cast<VirtualMachine *>(PoolSQL::get(oid,lock));
};
/**
* Function to get the IDs of running VMs
* @param oids a vector that contains the IDs

View File

@ -245,7 +245,6 @@ VAR_DIRS="$VAR_LOCATION/remotes \
$VAR_LOCATION/remotes/auth/ldap \
$VAR_LOCATION/remotes/auth/server_x509 \
$VAR_LOCATION/remotes/auth/server_cipher \
$VAR_LOCATION/remotes/auth/quota \
$VAR_LOCATION/remotes/auth/dummy"
SUNSTONE_DIRS="$SUNSTONE_LOCATION/models \
@ -392,7 +391,6 @@ INSTALL_FILES=(
AUTH_SERVER_CIPHER_FILES:$VAR_LOCATION/remotes/auth/server_cipher
AUTH_DUMMY_FILES:$VAR_LOCATION/remotes/auth/dummy
AUTH_PLAIN_FILES:$VAR_LOCATION/remotes/auth/plain
AUTH_QUOTA_FILES:$VAR_LOCATION/remotes/auth/quota
VMM_EXEC_KVM_SCRIPTS:$VAR_LOCATION/remotes/vmm/kvm
VMM_EXEC_XEN_SCRIPTS:$VAR_LOCATION/remotes/vmm/xen
VMM_EXEC_VMWARE_SCRIPTS:$VAR_LOCATION/remotes/vmm/vmware
@ -589,7 +587,6 @@ BIN_FILES="src/nebula/oned \
src/cli/onecluster \
src/onedb/onedb \
src/onedb/onezonedb/onezonedb \
src/authm_mad/remotes/quota/onequota \
src/mad/utils/tty_expect \
share/scripts/one"
@ -616,7 +613,6 @@ RUBY_LIB_FILES="src/mad/ruby/ActionManager.rb \
src/mad/ruby/Ganglia.rb \
src/oca/ruby/OpenNebula.rb \
src/authm_mad/remotes/ssh/ssh_auth.rb \
src/authm_mad/remotes/quota/quota.rb \
src/authm_mad/remotes/server_x509/server_x509_auth.rb \
src/authm_mad/remotes/server_cipher/server_cipher_auth.rb \
src/authm_mad/remotes/ldap/ldap_auth.rb \
@ -747,8 +743,6 @@ AUTH_DUMMY_FILES="src/authm_mad/remotes/dummy/authenticate"
AUTH_PLAIN_FILES="src/authm_mad/remotes/plain/authenticate"
AUTH_QUOTA_FILES="src/authm_mad/remotes/quota/authorize"
#-------------------------------------------------------------------------------
# Virtual Network Manager drivers to be installed under $REMOTES_LOCATION/vnm
#-------------------------------------------------------------------------------
@ -869,23 +863,28 @@ DATASTORE_DRIVER_COMMON_SCRIPTS="src/datastore_mad/remotes/xpath.rb \
DATASTORE_DRIVER_DUMMY_SCRIPTS="src/datastore_mad/remotes/dummy/cp \
src/datastore_mad/remotes/dummy/mkfs \
src/datastore_mad/remotes/dummy/stat \
src/datastore_mad/remotes/dummy/rm"
DATASTORE_DRIVER_FS_SCRIPTS="src/datastore_mad/remotes/fs/cp \
src/datastore_mad/remotes/fs/mkfs \
src/datastore_mad/remotes/fs/stat \
src/datastore_mad/remotes/fs/rm"
DATASTORE_DRIVER_VMWARE_SCRIPTS="src/datastore_mad/remotes/vmware/cp \
src/datastore_mad/remotes/vmware/mkfs \
src/datastore_mad/remotes/vmware/stat \
src/datastore_mad/remotes/vmware/rm"
DATASTORE_DRIVER_ISCSI_SCRIPTS="src/datastore_mad/remotes/iscsi/cp \
src/datastore_mad/remotes/iscsi/mkfs \
src/datastore_mad/remotes/iscsi/stat \
src/datastore_mad/remotes/iscsi/rm \
src/datastore_mad/remotes/iscsi/iscsi.conf"
DATASTORE_DRIVER_LVM_SCRIPTS="src/datastore_mad/remotes/lvm/cp \
src/datastore_mad/remotes/lvm/mkfs \
src/datastore_mad/remotes/lvm/stat \
src/datastore_mad/remotes/lvm/rm \
src/datastore_mad/remotes/lvm/lvm.conf"
@ -952,7 +951,6 @@ HM_ETC_FILES="src/hm_mad/hmrc"
#-------------------------------------------------------------------------------
AUTH_ETC_FILES="src/authm_mad/remotes/server_x509/server_x509_auth.conf \
src/authm_mad/remotes/quota/quota.conf \
src/authm_mad/remotes/ldap/ldap_auth.conf \
src/authm_mad/remotes/x509/x509_auth.conf"
@ -1124,6 +1122,7 @@ ONE_CLI_LIB_FILES="src/cli/one_helper/onegroup_helper.rb \
src/cli/one_helper/onehost_helper.rb \
src/cli/one_helper/oneimage_helper.rb \
src/cli/one_helper/onetemplate_helper.rb \
src/cli/one_helper/onequota_helper.rb \
src/cli/one_helper/oneuser_helper.rb \
src/cli/one_helper/onevm_helper.rb \
src/cli/one_helper/onevnet_helper.rb \

View File

@ -13,6 +13,63 @@
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="DATASTORE_QUOTA" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:element name="DATASTORE" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:string"/>
<xs:element name="IMAGES" type="xs:string"/>
<xs:element name="IMAGES_USED" type="xs:string"/>
<xs:element name="SIZE" type="xs:string"/>
<xs:element name="SIZE_USED" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:complexType>
</xs:element>
<xs:element name="VM_QUOTA" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:element name="VM" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element name="VMS" type="xs:string"/>
<xs:element name="VMS_USED" type="xs:string"/>
<xs:element name="MEMORY" type="xs:string"/>
<xs:element name="MEMORY_USED" type="xs:string"/>
<xs:element name="CPU" type="xs:string"/>
<xs:element name="CPU_USED" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:complexType>
</xs:element>
<xs:element name="NETWORK_QUOTA" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:element name="NETWORK" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:string"/>
<xs:element name="LEASES" type="xs:string"/>
<xs:element name="LEASES_USED" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:complexType>
</xs:element>
<xs:element name="IMAGE_QUOTA" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:element name="IMAGE" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:string"/>
<xs:element name="RVMS" type="xs:string"/>
<xs:element name="RVMS_USED" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>

View File

@ -12,6 +12,63 @@
<xs:element name="AUTH_DRIVER" type="xs:string"/>
<xs:element name="ENABLED" type="xs:integer"/>
<xs:element name="TEMPLATE" type="xs:anyType"/>
<xs:element name="DATASTORE_QUOTA" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:element name="DATASTORE" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:string"/>
<xs:element name="IMAGES" type="xs:string"/>
<xs:element name="IMAGES_USED" type="xs:string"/>
<xs:element name="SIZE" type="xs:string"/>
<xs:element name="SIZE_USED" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:complexType>
</xs:element>
<xs:element name="VM_QUOTA" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:element name="VM" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element name="VMS" type="xs:string"/>
<xs:element name="VMS_USED" type="xs:string"/>
<xs:element name="MEMORY" type="xs:string"/>
<xs:element name="MEMORY_USED" type="xs:string"/>
<xs:element name="CPU" type="xs:string"/>
<xs:element name="CPU_USED" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:complexType>
</xs:element>
<xs:element name="NETWORK_QUOTA" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:element name="NETWORK" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:string"/>
<xs:element name="LEASES" type="xs:string"/>
<xs:element name="LEASES_USED" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:complexType>
</xs:element>
<xs:element name="IMAGE_QUOTA" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:element name="IMAGE" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:string"/>
<xs:element name="RVMS" type="xs:string"/>
<xs:element name="RVMS_USED" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>

View File

@ -419,22 +419,20 @@ HM_MAD = [
# valid. During this time, the driver is not used. Use 0 to disable session
# caching
#
# ENABLE_OTHER_PERMISSIONS: Whether or not to enable the permissions for
# 'other'. Users in the oneadmin group will still be able to change
# these permissions. Values: YES or NO
# ENABLE_OTHER_PERMISSIONS: Whether or not users can set the permissions for
# 'other', so publishing or sharing resources with others. Users in the oneadmin
# group will still be able to change these permissions. Values: YES or NO.
#*******************************************************************************
AUTH_MAD = [
executable = "one_auth_mad",
authn = "ssh,x509,ldap,server_cipher,server_x509"
# , authz = "quota"
]
SESSION_EXPIRATION_TIME = 900
#ENABLE_OTHER_PERMISSIONS = "YES"
#*******************************************************************************
# Restricted Attributes Configuration
#*******************************************************************************

View File

@ -15,7 +15,7 @@
/* -------------------------------------------------------------------------- */
#include "AclRule.h"
#include "AuthManager.h"
#include "AuthRequest.h"
#include "PoolObjectSQL.h"
/* -------------------------------------------------------------------------- */

View File

@ -15,6 +15,7 @@
/* -------------------------------------------------------------------------- */
#include "AuthManager.h"
#include "AuthRequest.h"
#include "NebulaLog.h"
#include "SSLTools.h"
#include "PoolObjectAuth.h"
@ -23,8 +24,6 @@
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
time_t AuthManager::_time_out;
const char * AuthManager::auth_driver_name = "auth_exe";
/* -------------------------------------------------------------------------- */
@ -125,7 +124,7 @@ extern "C" void * authm_action_loop(void *arg)
NebulaLog::log("AuM",Log::INFO,"Authorization Manager started.");
authm->am.loop(authm->timer_period,0);
authm->am.loop(authm->timer_period, 0);
NebulaLog::log("AuM",Log::INFO,"Authorization Manager stopped.");
@ -203,7 +202,7 @@ void AuthManager::do_action(const string &action, void * arg)
}
else if (action == ACTION_TIMER)
{
timer_action();
check_time_outs_action();
}
else if (action == ACTION_FINALIZE)
{
@ -242,13 +241,12 @@ void AuthManager::authenticate_action(AuthRequest * ar)
// Queue the request
// ------------------------------------------------------------------------
ar->id = add_request(ar);
add_request(ar);
// ------------------------------------------------------------------------
// Make the request to the driver
// ---- --------------------------------------------------------------------
authm_md->authenticate(ar->id,
ar->uid,
ar->driver,
@ -287,7 +285,7 @@ void AuthManager::authorize_action(AuthRequest * ar)
// Queue the request
// ------------------------------------------------------------------------
ar->id = add_request(ar);
add_request(ar);
// ------------------------------------------------------------------------
// Make the request to the driver
@ -312,116 +310,6 @@ error:
return;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void AuthManager::timer_action()
{
map<int,AuthRequest *>::iterator it;
time_t the_time = time(0);
lock();
it = auth_requests.begin();
while ( it !=auth_requests.end())
{
if ((it->second->time_out != 0) && (the_time > it->second->time_out))
{
AuthRequest * ar = it->second;
auth_requests.erase(it++);
ar->result = false;
ar->timeout = true;
ar->message = "Auth request timeout";
ar->notify();
}
else
{
++it;
}
}
unlock();
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int AuthManager::add_request(AuthRequest *ar)
{
static int auth_id = 0;
int id;
lock();
id = auth_id++;
auth_requests.insert(auth_requests.end(),make_pair(id,ar));
unlock();
return id;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
AuthRequest * AuthManager::get_request(int id)
{
AuthRequest * ar = 0;
map<int,AuthRequest *>::iterator it;
ostringstream oss;
lock();
it=auth_requests.find(id);
if ( it != auth_requests.end())
{
ar = it->second;
auth_requests.erase(it);
}
unlock();
return ar;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void AuthManager::notify_request(int auth_id,bool result,const string& message)
{
AuthRequest * ar;
ar = get_request(auth_id);
if ( ar == 0 )
{
return;
}
ar->result = result;
if ( message != "-" )
{
if ( !ar->message.empty() )
{
ar->message.append("; ");
}
ar->message.append(message);
}
ar->notify();
}
/* ************************************************************************** */
/* MAD Loading */
/* ************************************************************************** */

View File

@ -65,7 +65,7 @@ public:
t->get("AUTH_MAD", am_mads);
return new AuthManager(1,3,am_mads);
return new AuthManager(1,am_mads);
};
};
@ -144,7 +144,7 @@ public:
/* ********************************************************************* */
/* ********************************************************************* */
//This test needs a driver that takes more than 3 secs to AUTHENTICATE
//This test needs a driver that takes more than 90 secs to AUTHENTICATE
void timeout()
{
AuthRequest ar(2, 2);
@ -157,8 +157,6 @@ public:
CPPUNIT_ASSERT(ar.result==false);
CPPUNIT_ASSERT(ar.timeout==true);
am->discard_request(ar.id);
}
void authenticate()

View File

@ -45,4 +45,6 @@ env.Prepend(LIBS=[
'crypto'
])
env.Program('test','AuthManagerTest.cc')
nt = env.Object('NebulaTemplate.o','../../nebula/NebulaTemplate.cc')
env.Program('test',[nt,'AuthManagerTest.cc'])

View File

@ -36,7 +36,7 @@ do
"AUTHENTICATE")
date 1>&2 >> mad.log
if [ "$ARG4" = "timeout" ] ; then
sleep 4
sleep 95
fi
date 1>&2 >> mad.log

View File

@ -1,189 +0,0 @@
#!/usr/bin/env ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
# not use this file except in compliance with the License. You may obtain #
# a copy of the License at #
# #
# http://www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
#--------------------------------------------------------------------------- #
ONE_LOCATION=ENV["ONE_LOCATION"]
if !ONE_LOCATION
RUBY_LIB_LOCATION="/usr/lib/one/ruby"
else
RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby"
end
$: << RUBY_LIB_LOCATION
$: << RUBY_LIB_LOCATION+"/cli"
require 'command_parser'
require 'cli_helper'
require 'one_helper'
require 'quota'
require 'pp'
QUOTA_KEYS = Quota::DB_QUOTA_SCHEMA.keys
def show_table(values, usage=nil)
size = usage ? 12 : 8
values.sort!{|v1, v2| v1[:UID]<=>v2[:UID] }
table=CLIHelper::ShowTable.new(nil, self) do
column :UID, "ONE identifier for the User", :size=>4 do |d|
d[:UID]
end
QUOTA_KEYS.each { |key|
column key, "#{key} quota", :size=>size do |d|
if usage
"#{usage[key].to_i}/#{d[key].to_i}"
else
"#{d[key].to_i}"
end
end
}
default :UID, *QUOTA_KEYS
end
table.show(values)
end
cmd=CommandParser::CmdParser.new(ARGV) do
usage "`onequota` <command> [<args>] [<options>]"
version OpenNebulaHelper::ONE_VERSION
quota = Quota.new
########################################################################
# Global Options
########################################################################
set :option, CommandParser::OPTIONS
########################################################################
# Argument Formats
########################################################################
quota_list_desc = <<-EOT.unindent
List of quota keys, comma separated.
Available quotas: #{QUOTA_KEYS.join(', ')}
EOT
set :format, :quota_list, quota_list_desc do |arg|
arg_list = arg.split(',')
rc = nil
arg_list.collect! do |elem|
sym = elem.upcase.to_sym
if !QUOTA_KEYS.include?(sym)
rc = -1, "#{elem} is not a valid quota"
break
end
sym
end
rc ? rc : [0, arg_list]
end
set :format, :value_list, "List of quota values, comma separated." do |arg|
arg_list = arg.split(',')
arg_list.map! {|a| a.to_i }
[0, arg_list]
end
set :format, :userid, OpenNebulaHelper.rname_to_id_desc("USER") do |arg|
OpenNebulaHelper.rname_to_id(arg, "USER")
end
########################################################################
# Commands
########################################################################
set_desc = <<-EOT.unindent
Set a quota for a given user.
Examples:
onequota set 3 cpu 12
onequota set 4 cpu,memory,storage 8,4096,10000
EOT
command :set, set_desc, :userid, :quota_list, :value_list do
user_id, keys, values = args
if keys.length != values.length
exit_with_code -1, "The number of keys and values does not match"
end
values_hash = Hash.new
keys.each_with_index { |k,i|
values_hash[k] = values[i]
}
quota.set_quota(user_id, values_hash)
exit_with_code 0
end
########################################################################
unset_desc = <<-EOT.unindent
Unset a quota for a given user.
Examples:
onequota unset 3 cpu
onequota unset 4 cpu,memory,storage
EOT
command :unset, unset_desc, :userid, :quota_list do
user_id, keys = args
values_hash = Hash.new
keys.each_with_index { |k,i|
values_hash[k] = 0
}
quota.set_quota(user_id, values_hash)
exit_with_code 0
end
########################################################################
delete_desc = "Delete the defined quotas for the given user"
command :delete, delete_desc, :userid do
quota.delete_quota(args[0])
exit_with_code 0
end
########################################################################
show_desc = "Show the user's quota and usage. (usage/quota)"
FORCE={
:name => "force",
:short => "-f",
:large => "--force",
:description => "Force the usage calculation instead of using the cache"
}
command :show, show_desc, :userid, :options=>[FORCE] do
user_usage = quota.get_usage(args[0],nil,options[:force])
user_quota = quota.get_quota(args[0])
show_table([user_quota], user_usage)
exit_with_code 0
end
########################################################################
list_desc = "List the defined quotas for all the users"
command :list, list_desc do
show_table(quota.get_quota)
exit_with_code 0
end
end

View File

@ -1,374 +0,0 @@
# -------------------------------------------------------------------------- #
# Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
# not use this file except in compliance with the License. You may obtain #
# a copy of the License at #
# #
# http://www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
#--------------------------------------------------------------------------- #
require 'sequel'
require 'base64'
require 'yaml'
require 'uri'
require 'net/http'
class Quota
###########################################################################
# Constants with paths to relevant files and defaults
###########################################################################
ONE_LOCATION=ENV["ONE_LOCATION"]
if !ONE_LOCATION
VAR_LOCATION = "/var/lib/one"
ETC_LOCATION = "/etc/one"
else
VAR_LOCATION = ONE_LOCATION + "/var"
ETC_LOCATION = ONE_LOCATION + "/etc"
end
CONF_FILE = ETC_LOCATION + "/auth/quota.conf"
CONF = {
:db => "sqlite://#{VAR_LOCATION}/onequota.db",
:defaults => {
:CPU => nil,
:MEMORY => nil,
:NUM_VMS => nil,
:STORAGE => nil
}
}
###########################################################################
# Schema for the USAGE and QUOTA tables
###########################################################################
DB_QUOTA_SCHEMA = {
:CPU => Float,
:MEMORY => Integer,
:NUM_VMS => Integer,
:STORAGE => Integer
}
QUOTA_TABLE = :quotas
USAGE_TABLE = :usage
###########################################################################
# Usage params to calculate each quota
###########################################################################
VM_USAGE = {
:CPU => {
:proc_info => lambda {|template| template['CPU']},
:xpath => 'TEMPLATE/CPU'
},
:MEMORY => {
:proc_info => lambda {|template| template['MEMORY']},
:xpath => 'TEMPLATE/MEMORY'
},
:NUM_VMS => {
:proc_info => lambda {|template| 1 },
:xpath => 'ID',
:count => true
}
}
IMAGE_USAGE = {
:STORAGE => {
:proc_info => lambda {|template|
if template['TYPE'] == 'DATABLOCK'
template['SIZE'].to_i
elsif template['PATH']
uri = URI.parse(template['PATH'])
size = if uri.scheme.nil?
File.size(template['PATH'])
else
Net::HTTP.start(uri.host,uri.port) { |http|
http.head(uri.path)
}.content_length
end
(size.to_f / 2**20).round
elsif template['SAVED_VM_ID']
vm_id = template['SAVED_VM_ID'].to_i
disk_id = template['SAVED_DISK_ID'].to_i
client = OpenNebula::Client.new
vm = OpenNebula::VirtualMachine.new_with_id(vm_id, client)
vm.info
im_id = vm["DISK[DISK_ID=#{disk_id}]/IMAGE_ID"].to_i
im = OpenNebula::Image.new_with_id(im_id, client)
im.info
im['SIZE'].to_i
else
0
end
},
:xpath => 'SIZE'
}
}
RESOURCES = ["VM", "IMAGE"]
###########################################################################
# DB handling
###########################################################################
def initialize
conf = YAML.load_file(CONF_FILE)
@conf=CONF.merge(conf) {|key,h1,h2|
if h1.instance_of?(Hash) && h2.instance_of?(Hash)
h1.merge(h2)
else
if h2
h2
else
h1
end
end
}
@client = OpenNebula::Client.new
@db=Sequel.connect(@conf[:db])
create_table(QUOTA_TABLE)
create_table(USAGE_TABLE)
end
# Creates database quota table if it does not exist
def create_table(table)
@db.create_table?(table) do
Integer :UID
DB_QUOTA_SCHEMA.each { |key,value|
column key, value
}
primary_key :UID
index :UID
end
end
# Adds new user limits
def set(table, uid, quota={})
data=quota.delete_if{|key,value| !DB_QUOTA_SCHEMA.keys.include?(key)}
quotas=@db[table].filter(:UID => uid)
if quotas.first
quotas.update(data)
else
@db[table].insert(data.merge!(:UID => uid))
end
end
# Gets user limits
def get(table, uid=nil)
if uid
@db[table].filter(:UID => uid).first
else
@db[table].all
end
end
# Delete user limits
def delete(table, uid)
quotas=@db[table].filter(:UID => uid)
if quotas.first
quotas.delete
end
end
###########################################################################
# Quota Client
###########################################################################
def set_quota(uid, quota={})
set(QUOTA_TABLE, uid, quota)
end
# Retrieves quota information for a given user
#
# @param [Integer, nil] uid the user id from which get the quota
# information, if nil will retrieve the quotas for all users.
# @return [Hash] Hash containing the quota information and the user id
#
# {
# :uid => 4,
# :cpu => 8,
# :memory => 8064,
# :num_vms => 4,
# :storage => 1240019
# }
def get_quota(uid=nil)
limit = get(QUOTA_TABLE, uid)
limit ? limit : @conf[:defaults].merge!(:UID => uid)
end
def delete_quota(uid)
delete(QUOTA_TABLE, uid)
end
###########################################################################
# Authorization
###########################################################################
def authorize(user_id, request)
obj, template_or_id, op, owner, acl_eval = request.split(':')
if acl_eval.to_i == 0
return "ACL evaluation denied"
end
# Check if this op needs to check the quota
return false unless with_quota?(obj, op)
template = ""
if ( obj == "TEMPLATE" )
obj = "VM"
vm_template = OpenNebula::Template.new_with_id(template_or_id, @client)
vm_template.info
vm_template.each("TEMPLATE") { |xml_elem|
template = xml_elem.to_xml
}
else
template = Base64::decode64(template_or_id)
end
check_quotas(user_id.to_i, obj, template)
end
def check_quotas(user_id, obj, template)
info = get_resources(obj, template)
total = get_usage(user_id, obj, true)
quota = get_quota(user_id)
msg = ""
separator = ""
info.each { |qname, quota_requested|
unless quota[qname] || quota[qname]==0
next
end
type = DB_QUOTA_SCHEMA[qname].name.to_sym
used = send(type, total[qname])
request = send(type, quota_requested)
limit = send(type, quota[qname])
spent = used + request
if spent > limit
msg << separator
msg << " #{qname.to_s.upcase} quota exceeded "
msg << "(Quota: #{limit}, "
msg << "Used: #{used}, "
msg << "Requested: #{request})"
separator = ";"
end
}
if msg==""
return false
else
return msg.strip
end
end
def with_quota?(obj, op)
return (obj == "VM" && op == "CREATE") ||
(obj == "IMAGE" && op == "CREATE") ||
(obj == "TEMPLATE" && op == "USE")
end
###########################################################################
# Usage
###########################################################################
# Retrieves usage information for a given user
#
# @param [Integer] uid the user id from which get the usage information.
# @param ["VM", "IMAGE"] resource kind of resource. If nil will return
# the usage for all kinds of resources
# @param [true, false] force If true will force the usage calculation
# instead of retrieving it from the cache
# @return [Hash] Hash containing the usage information and the user id
#
# {
# :uid => 4,
# :cpu => 8,
# :memory => 8064,
# :num_vms => 4,
# :storage => 1240019
# }
def get_usage(user_id, resource=nil, force=false)
if force
if RESOURCES.include?(resource)
resources = [resource]
else
resources = RESOURCES
end
usage = Hash.new
resources.each{ |res|
pool = get_pool(res, user_id)
base_xpath = "/#{res}_POOL/#{resource}"
Quota.const_get("#{res}_USAGE".to_sym).each { |key, params|
usage[key] ||= 0
pool.each_xpath("#{base_xpath}/#{params[:xpath]}") { |elem|
if elem
if params[:count]
usage[key] += 1
else
usage[key] += send(DB_QUOTA_SCHEMA[key].name.to_sym, elem)
end
end
}
}
set(USAGE_TABLE, user_id, usage) unless usage.empty?
usage.merge!(:UID => user_id)
}
else
usage = get(USAGE_TABLE, user_id)
usage ||= {:UID => user_id}
end
usage
end
# Retrieve the useful information of the template for the specified
# kind of resource
def get_resources(resource, xml_template)
template = OpenNebula::XMLElement.new
template.initialize_xml(xml_template, 'TEMPLATE')
info = Hash.new
self.class.const_get("#{resource}_USAGE").each { |key, params|
info[key] = params[:proc_info].call(template).to_i
}
info
end
# Returns a an Array than contains the elements of the resource Pool
def get_pool(resource, user_id)
pool = case resource
when "VM" then OpenNebula::VirtualMachinePool.new(@client, user_id)
when "IMAGE" then OpenNebula::ImagePool.new(@client, user_id)
end
rc = pool.info
return pool
end
end

View File

@ -1,26 +0,0 @@
<IMAGE_POOL>
<% images.each do |id,image| %>
<IMAGE>
<ID><%= id %></ID>
<UID><%= image[:uid] ? image[:uid] : 0 %></UID>
<GID><%= image[:gid] ? image[:gid] : 0 %></GID>
<UNAME><%= image[:uname] ? image[:uname] : 'oneadmin' %></UNAME>
<GNAME><%= image[:gname] ? image[:gname] : 'oneadmin' %></GNAME>
<NAME><%= image[:name] ? image[:name] : 'ttylinux' %></NAME>
<TYPE><%= image[:type] ? image[:type] : 0 %></TYPE>
<PUBLIC><%= image[:pub] ? image[:pub] : 0 %></PUBLIC>
<PERSISTENT><%= image[:persistent] ? image[:persistent] : 0 %></PERSISTENT>
<REGTIME>1314875019</REGTIME>
<SOURCE><%= image[:source] ? image[:source] : '/etc/hosts' %></SOURCE>
<STATE><%= image[:state] ? image[:state] : 1 %></STATE>
<SIZE><%= image[:size] ? image[:size] : 100 %></SIZE>
<RUNNING_VMS>0</RUNNING_VMS>
<TEMPLATE>
<DEV_PREFIX><![CDATA[hd]]></DEV_PREFIX>
<NAME><![CDATA[PEPE]]></NAME>
<PATH><![CDATA[/etc/hosts]]></PATH>
<TYPE><![CDATA[OS]]></TYPE>
</TEMPLATE>
</IMAGE>
<% end %>
</IMAGE_POOL>

View File

@ -1,46 +0,0 @@
<VM>
<ID><%= id %></ID>
<UID><%= vm[:uid] ? vm[:uid] : 0 %></UID>
<GID><%= vm[:gid] ? vm[:gid] : 0 %></GID>
<NAME><%= vm[:name] ? vm[:uid] : 'pepe' %></NAME>
<LAST_POLL><%= vm[:last_poll] ? vm[:last_poll] : '1309275256' %></LAST_POLL>
<STATE><%= vm[:state] ? vm[:state] : 3 %></STATE>
<LCM_STATE>3</LCM_STATE>
<STIME>1309275252</STIME>
<ETIME>0</ETIME>
<DEPLOY_ID>dummy</DEPLOY_ID>
<MEMORY><%= vm[:memory] ? vm[:memory] : 128 %></MEMORY>
<CPU><%= vm[:cpu] ? vm[:cpu] : 1 %></CPU>
<NET_TX><%= vm[:net_tx] ? vm[:net_tx] : 0 %></NET_TX>
<NET_RX><%= vm[:net_rx] ? vm[:net_rx] : 0 %></NET_RX>
<TEMPLATE>
<CPU><![CDATA[1]]></CPU>
<MEMORY><![CDATA[1024]]></MEMORY>
<NAME><![CDATA[PEPEPE]]></NAME>
<VCPU><![CDATA[1]]></VCPU>
<VMID><![CDATA[4]]></VMID>
</TEMPLATE>
<% if history = vm[:history] %>
<HISTORY_RECORDS>
<% history.each do |h| %>
<HISTORY>
<SEQ><%= h[:seq] ? h[:seq] : 0 %></SEQ>
<HOSTNAME><%= h[:hostname] ? h[:hostname] : "kvxen" %></HOSTNAME>
<VM_DIR>/Users/dmolina/trabajo/acctmoni/install/var/</VM_DIR>
<HID><%= h[:hid] ? h[:hid] : 0 %></HID>
<STIME>1309275256</STIME>
<ETIME>0</ETIME>
<VMMMAD>vmm_dummy</VMMMAD>
<TMMAD>tm_dummy</TMMAD>
<PSTIME><%= h[:pstime] ? h[:pstime] : 0 %></PSTIME>
<PETIME><%= h[:petime] ? h[:petime] : 0 %></PETIME>
<RSTIME><%= h[:rstime] ? h[:rstime] : 0 %></RSTIME>
<RETIME><%= h[:retime] ? h[:retime] : 0 %></RETIME>
<ESTIME><%= h[:estime] ? h[:estime] : 0 %></ESTIME>
<EETIME><%= h[:eetime] ? h[:eetime] : 0 %></EETIME>
<REASON><%= h[:reason] ? h[:reason] : 0 %></REASON>
</HISTORY>
<% end %>
</HISTORY_RECORDS>
<% end %>
</VM>

View File

@ -1,49 +0,0 @@
<VM_POOL>
<% vms.each do |id,vm| %>
<VM>
<ID><%= id %></ID>
<UID><%= vm[:uid] ? vm[:uid] : 0 %></UID>
<GID><%= vm[:gid] ? vm[:gid] : 0 %></GID>
<NAME><%= vm[:name] ? vm[:uid] : 'pepe' %></NAME>
<LAST_POLL><%= vm[:last_poll] ? vm[:last_poll] : '1309275256' %></LAST_POLL>
<STATE><%= vm[:state] ? vm[:state] : 3 %></STATE>
<LCM_STATE>3</LCM_STATE>
<STIME>1309275252</STIME>
<ETIME>0</ETIME>
<DEPLOY_ID>dummy</DEPLOY_ID>
<MEMORY><%= vm[:memory] ? vm[:memory] : 128 %></MEMORY>
<CPU><%= vm[:cpu] ? vm[:cpu] : 1 %></CPU>
<NET_TX><%= vm[:net_tx] ? vm[:net_tx] : 0 %></NET_TX>
<NET_RX><%= vm[:net_rx] ? vm[:net_rx] : 0 %></NET_RX>
<TEMPLATE>
<CPU><![CDATA[<%= vm[:cpu] ? vm[:cpu] : 1 %>]]></CPU>
<MEMORY><![CDATA[<%= vm[:memory] ? vm[:memory] : 128 %>]]></MEMORY>
<NAME><![CDATA[PEPEPE]]></NAME>
<VCPU><![CDATA[1]]></VCPU>
<VMID><![CDATA[4]]></VMID>
</TEMPLATE>
<% if history = vm[:history] %>
<HISTORY_RECORDS>
<% h = history.last %>
<HISTORY>
<SEQ><%= h[:seq] ? h[:seq] : 0 %></SEQ>
<HOSTNAME><%= h[:hostname] ? h[:hostname] : "kvxen" %></HOSTNAME>
<VM_DIR>/Users/dmolina/trabajo/acctmoni/install/var/</VM_DIR>
<HID><%= h[:hid] ? h[:hid] : 0 %></HID>
<STIME>1309275256</STIME>
<ETIME>0</ETIME>
<VMMMAD>vmm_dummy</VMMMAD>
<TMMAD>tm_dummy</TMMAD>
<PSTIME><%= h[:pstime] ? h[:pstime] : 0 %></PSTIME>
<PETIME><%= h[:petime] ? h[:petime] : 0 %></PETIME>
<RSTIME><%= h[:rstime] ? h[:rstime] : 0 %></RSTIME>
<RETIME><%= h[:retime] ? h[:retime] : 0 %></RETIME>
<ESTIME><%= h[:estime] ? h[:estime] : 0 %></ESTIME>
<EETIME><%= h[:eetime] ? h[:eetime] : 0 %></EETIME>
<REASON><%= h[:reason] ? h[:reason] : 0 %></REASON>
</HISTORY>
</HISTORY_RECORDS>
<% end %>
</VM>
<% end %>
</VM_POOL>

View File

@ -1,53 +0,0 @@
require 'erb'
FPATH = "./fixtures/"
class MockClient
def initialize
@vms = Hash.new
@done_vms = Hash.new
@images = Hash.new
end
def call(action, *args)
xmlrpc_action = "one."+action
case xmlrpc_action
when "one.vm.info"
id = args[0]
vm = @vms[id]
return ERB.new(File.read(FPATH+'vm.xml')).result(binding)
when "one.vmpool.info"
case args[3]
when -1
vms = @vms
return ERB.new(File.read(FPATH+'vmpool.xml')).result(binding)
when 6 then
vms = @done_vms
return ERB.new(File.read(FPATH+'vmpool.xml')).result(binding)
end
when "one.imagepool.info"
images = @images
return ERB.new(File.read(FPATH+'imagepool.xml')).result(binding)
end
end
def add_vm(id, values)
if values[:state] == 6
@done_vms[id] = values.clone
else
@vms[id] = values.clone
end
end
def delete_vm(id)
@vms.delete(id)
@vms_done.delete(id)
end
def add_image(id, values)
@images[id] = values
end
end

View File

@ -1,31 +0,0 @@
ONE_LOCATION = ENV['ONE_LOCATION']
if !ONE_LOCATION
RUBY_LIB_LOCATION="/usr/lib/one/ruby"
else
RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby"
end
$: << RUBY_LIB_LOCATION
$: << './helper'
$: << '.'
$: << '..'
require 'mock_client'
require 'OpenNebula'
require 'quota'
class Quota
def set_client(client)
@client = client
end
def rm_and_set_testdb
`rm -f /tmp/onequota_test.db`
@db=Sequel.connect("sqlite:///tmp/onequota_test.db")
create_table(QUOTA_TABLE)
create_table(USAGE_TABLE)
end
end

View File

@ -1,343 +0,0 @@
$: << '.'
require 'helper/test_helper'
describe "Quota testing" do
before(:all) do
@mock_client = MockClient.new
@quota = Quota.new
@quota.set_client(@mock_client)
@quota.rm_and_set_testdb
@uid1 = 0
@quota1 = {
:CPU => 2.4,
:MEMORY => 1024,
:NUM_VMS => 4,
:STORAGE => 10000
}
@uid2 = 1
@quota2 = {
:CPU => 1.2,
:MEMORY => 512,
:NUM_VMS => 2,
:STORAGE => 5000
}
# Generate VM ACL request
vm_template = <<-EOT
<TEMPLATE>
<CPU>2</CPU>
<MEMORY>128</MEMORY>
</TEMPLATE>
EOT
vm_base64 = Base64::encode64(vm_template)
@acl_vm_create = "VM:#{vm_base64}:CREATE:0:1:1"
# Generate IMAGE ACL request
image_template = <<-EOT
<TEMPLATE>
<PATH>/etc/hosts</PATH>
</TEMPLATE>
EOT
image_base64 = Base64::encode64(image_template)
@acl_image_create = "IMAGE:#{image_base64}:CREATE:0:1:1"
# Generate TEMPLATE ACL request
temp_template = <<-EOT
<TEMPLATE>
<CPU>2</CPU>
<MEMORY>128</MEMORY>
</TEMPLATE>
EOT
temp_base64 = Base64::encode64(temp_template)
@acl_template_instantiate = "TEMPLATE:#{temp_base64}:INSTANTIATE:0:1:1"
end
it "should check default quotas" do
quota1 = @quota.get_quota(@uid1)
quota1[:UID].should eql(0)
quota1[:NUM_VMS].should eql(nil)
quota1[:CPU].should eql(nil)
quota1[:MEMORY].should eql(nil)
quota1[:STORAGE].should eql(nil)
end
it "should check default usage cache" do
usage1cache = @quota.get_usage(@uid1)
usage1cache[:UID].should eql(0)
usage1cache[:NUM_VMS].should eql(nil)
usage1cache[:CPU].should eql(nil)
usage1cache[:MEMORY].should eql(nil)
usage1cache[:STORAGE].should eql(nil)
end
it "should check default cache (force)" do
usage1force = @quota.get_usage(@uid1, nil, true)
usage1force[:UID].should eql(0)
usage1force[:NUM_VMS].should eql(0)
usage1force[:CPU].should eql(0)
usage1force[:MEMORY].should eql(0)
usage1force[:STORAGE].should eql(0)
end
it "should authorize the user because there is no quota defined" do
@quota.authorize(@uid1, @acl_vm_create).should eql(false)
@quota.authorize(@uid1, @acl_image_create).should eql(false)
@quota.authorize(@uid1, @acl_template_instantiate).should eql(false)
end
it "should add a new VM" do
values = {
:CPU => 2,
:MEMORY => 128,
:UID => 2,
:GID => 4,
}
@mock_client.add_vm(0, values)
end
it "should check the usage cache is not updated" do
usage1cache = @quota.get_usage(@uid1)
usage1cache[:UID].should eql(0)
usage1cache[:NUM_VMS].should eql(0)
usage1cache[:CPU].should eql(0.0)
usage1cache[:MEMORY].should eql(0)
usage1cache[:STORAGE].should eql(0)
end
it "should check the cache (force)" do
usage1force = @quota.get_usage(@uid1, nil, true)
usage1force[:UID].should eql(0)
usage1force[:NUM_VMS].should eql(1)
usage1force[:CPU].should eql(2.0)
usage1force[:MEMORY].should eql(128)
usage1force[:STORAGE].should eql(0)
end
it "should check the usage cache is updated and contains the last usage" do
usage1cache = @quota.get_usage(@uid1)
usage1cache[:UID].should eql(0)
usage1cache[:NUM_VMS].should eql(1)
usage1cache[:CPU].should eql(2.0)
usage1cache[:MEMORY].should eql(128)
usage1cache[:STORAGE].should eql(0)
end
it "should add a new Image" do
values = {
:UID => 2,
:GID => 4,
:SIZE => 1000
}
@mock_client.add_image(0, values)
end
it "should check the usage cache is not updated" do
usage1cache = @quota.get_usage(@uid1)
usage1cache[:UID].should eql(0)
usage1cache[:NUM_VMS].should eql(1)
usage1cache[:CPU].should eql(2.0)
usage1cache[:MEMORY].should eql(128)
usage1cache[:STORAGE].should eql(0)
end
it "should check the cache (force)" do
usage1force = @quota.get_usage(@uid1, nil, true)
usage1force[:UID].should eql(0)
usage1force[:NUM_VMS].should eql(1)
usage1force[:CPU].should eql(2.0)
usage1force[:MEMORY].should eql(128)
usage1force[:STORAGE].should eql(1000)
end
it "should check the usage cache is updated and contains the last usage" do
usage1cache = @quota.get_usage(@uid1)
usage1cache[:UID].should eql(0)
usage1cache[:NUM_VMS].should eql(1)
usage1cache[:CPU].should eql(2.0)
usage1cache[:MEMORY].should eql(128)
usage1cache[:STORAGE].should eql(1000)
end
it "should add a second VM" do
values = {
:CPU => 2,
:MEMORY => 128,
:UID => 2,
:GID => 4,
}
@mock_client.add_vm(1, values)
end
it "should check the usage cache is not updated" do
usage1cache = @quota.get_usage(@uid1)
usage1cache[:UID].should eql(0)
usage1cache[:NUM_VMS].should eql(1)
usage1cache[:CPU].should eql(2.0)
usage1cache[:MEMORY].should eql(128)
usage1cache[:STORAGE].should eql(1000)
end
it "should check the cache (force)" do
usage1force = @quota.get_usage(@uid1, nil, true)
usage1force[:UID].should eql(0)
usage1force[:NUM_VMS].should eql(1*2)
usage1force[:CPU].should eql(2.0*2)
usage1force[:MEMORY].should eql(128*2)
usage1force[:STORAGE].should eql(1000)
end
it "should check the usage cache is updated and contains the last usage" do
usage1cache = @quota.get_usage(@uid1)
usage1cache[:UID].should eql(0)
usage1cache[:NUM_VMS].should eql(1*2)
usage1cache[:CPU].should eql(2.0*2)
usage1cache[:MEMORY].should eql(128*2)
usage1cache[:STORAGE].should eql(1000)
end
it "should add a second Image" do
values = {
:UID => 2,
:GID => 4,
:SIZE => 1000
}
@mock_client.add_image(1, values)
end
it "should check the usage cache is not updated" do
usage1cache = @quota.get_usage(@uid1)
usage1cache[:UID].should eql(0)
usage1cache[:NUM_VMS].should eql(1*2)
usage1cache[:CPU].should eql(2.0*2)
usage1cache[:MEMORY].should eql(128*2)
usage1cache[:STORAGE].should eql(1000)
end
it "should check the cache (force)" do
usage1force = @quota.get_usage(@uid1, nil, true)
usage1force[:UID].should eql(0)
usage1force[:NUM_VMS].should eql(1*2)
usage1force[:CPU].should eql(2.0*2)
usage1force[:MEMORY].should eql(128*2)
usage1force[:STORAGE].should eql(1000*2)
end
it "should check the usage cache is updated and contains the last usage" do
usage1cache = @quota.get_usage(@uid1)
usage1cache[:UID].should eql(0)
usage1cache[:NUM_VMS].should eql(1*2)
usage1cache[:CPU].should eql(2.0*2)
usage1cache[:MEMORY].should eql(128*2)
usage1cache[:STORAGE].should eql(1000*2)
end
it "should add a new quota and check it" do
@quota.set_quota(@uid1, @quota1)
quota = @quota.get_quota(@uid1)
@quota1.each{ |key,value|
quota[key].should eql(value)
}
end
it "should not authorize the user because the vm quota is spent" do
err_msg = "CPU quota exceeded (Quota: 2.4, Used: 4.0, Requested: 2.0)"
@quota.authorize(@uid1, @acl_vm_create).should eql(err_msg)
@quota.authorize(@uid1, @acl_template_instantiate).should eql(err_msg)
@quota.authorize(@uid1, @acl_image_create).should eql(false)
end
it "should add a new quota for another user and check it" do
@quota.set_quota(@uid2, @quota2)
quota = @quota.get_quota(@uid2)
@quota2.each{ |key,value|
quota[key].should eql(value)
}
end
it "should list all the defined quotas" do
quotas = @quota.get_quota
quotas.each { |quota|
if quota[:UID] == @uid1
@quota1.each{ |key,value|
quota[key].should eql(value)
}
elsif quota[:UID] == @uid2
@quota2.each{ |key,value|
quota[key].should eql(value)
}
end
}
end
it "should update the first user quota and check it" do
new_quota = Hash.new
@quota1.each { |key,value|
new_quota[key] = value*3
}
@quota.set_quota(@uid1, new_quota)
quota = @quota.get_quota(@uid1)
new_quota.each{ |key,value|
quota[key] == value
}
end
it "should authorize the user because the quota is not spent" do
@quota.authorize(@uid1, @acl_vm_create).should eql(false)
@quota.authorize(@uid1, @acl_image_create).should eql(false)
@quota.authorize(@uid1, @acl_template_instantiate).should eql(false)
end
it "should update the first user quota and check it" do
new_quota = {
:STORAGE => 0
}
@quota.set_quota(@uid1, new_quota)
quota = @quota.get_quota(@uid1)
quota[:STORAGE].should eql(new_quota[:STORAGE])
end
it "should not authorize the user because the image quota is spent" do
@quota.authorize(@uid1, @acl_vm_create).should eql(false)
@quota.authorize(@uid1, @acl_template_instantiate).should eql(false)
err_msg = "STORAGE quota exceeded (Quota: 0, Used: 2000, Requested: 271)"
@quota.authorize(@uid1, @acl_image_create).should eql(err_msg)
end
it "should delete the quota and check it" do
@quota.delete_quota(@uid1)
quota1 = @quota.get_quota(@uid1)
quota1[:UID].should eql(0)
quota1[:NUM_VMS].should eql(nil)
quota1[:CPU].should eql(nil)
quota1[:MEMORY].should eql(nil)
quota1[:STORAGE].should eql(nil)
end
it "should authorize the user because the quota was deleted" do
@quota.authorize(@uid1, @acl_vm_create).should eql(false)
@quota.authorize(@uid1, @acl_image_create).should eql(false)
@quota.authorize(@uid1, @acl_template_instantiate).should eql(false)
end
end

View File

@ -8,7 +8,21 @@
:size: 15
:left: true
:VMS:
:desc: Number of VMS
:size: 8
:MEMORY:
:desc: Total memory allocated to user VMs
:size: 8
:CPU:
:desc: Total CPU allocated to user VMs
:size: 8
:default:
- :ID
- :NAME
- :VMS
- :MEMORY
- :CPU

View File

@ -18,6 +18,18 @@
:size: 8
:left: true
:VMS:
:desc: Number of VMS
:size: 8
:MEMORY:
:desc: Total memory allocated to user VMs
:size: 8
:CPU:
:desc: Total CPU allocated to user VMs
:size: 8
:PASSWORD:
:desc: Password of the User
:size: 50
@ -27,4 +39,7 @@
- :GROUP
- :NAME
- :AUTH
- :PASSWORD
- :VMS
- :MEMORY
- :CPU

View File

@ -15,6 +15,7 @@
#--------------------------------------------------------------------------- #
require 'one_helper'
require 'one_helper/onequota_helper'
class OneGroupHelper < OpenNebulaHelper::OneHelper
def self.rname
@ -56,7 +57,31 @@ class OneGroupHelper < OpenNebulaHelper::OneHelper
d["NAME"]
end
default :ID, :NAME
column :VMS, "Total number of VMS", :size=>8 do |d|
if d.has_key?('VM_QUOTA') and d['VM_QUOTA'].has_key?('VM')
d['VM_QUOTA']['VM']['VMS']
else
"-"
end
end
column :MEMORY, "Total memory allocated to group VMs", :size=>8 do |d|
if d.has_key?('VM_QUOTA') and d['VM_QUOTA'].has_key?('VM')
d['VM_QUOTA']['VM']['MEMORY_USED']
else
"-"
end
end
column :CPU, "Total CPU allocated to group VMs", :size=>8 do |d|
if d.has_key?('VM_QUOTA') and d['VM_QUOTA'].has_key?('VM')
d['VM_QUOTA']['VM']['CPU_USED']
else
"-"
end
end
default :ID, :NAME, :VMS, :MEMORY, :CPU
end
table
@ -92,5 +117,9 @@ class OneGroupHelper < OpenNebulaHelper::OneHelper
group.user_ids.each do |uid|
puts "%-15s" % [uid]
end
group_hash = group.to_hash
OneQuotaHelper.format_quota(group_hash['GROUP'])
end
end

View File

@ -0,0 +1,209 @@
# -------------------------------------------------------------------------- #
# Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
# not use this file except in compliance with the License. You may obtain #
# a copy of the License at #
# #
# http://www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
#--------------------------------------------------------------------------- #
require 'cli_helper'
class OneQuotaHelper
#---------------------------------------------------------------------------
# Tables to format user quotas
#---------------------------------------------------------------------------
TABLE_DS = CLIHelper::ShowTable.new(nil, self) do
column :"DATASTORE ID", "", :left, :size=>12 do |d|
d["ID"] if !d.nil?
end
column :"IMAGES (used)", "", :right, :size=>14 do |d|
d["IMAGES_USED"] if !d.nil?
end
column :"IMAGES (limit)", "", :right, :size=>14 do |d|
d["IMAGES"] if !d.nil?
end
column :"SIZE (used)", "", :right, :size=>14 do |d|
d["SIZE_USED"] if !d.nil?
end
column :"SIZE (limit)", "", :right, :size=>14 do |d|
d["SIZE"] if !d.nil?
end
end
TABLE_NET = CLIHelper::ShowTable.new(nil, self) do
column :"NETWORK ID", "", :left, :size=>12 do |d|
d["ID"] if !d.nil?
end
column :"LEASES (used)", "", :right, :size=>14 do |d|
d["LEASES_USED"] if !d.nil?
end
column :"LEASES (limit)", "", :right, :size=>14 do |d|
d["LEASES"] if !d.nil?
end
end
TABLE_VM = CLIHelper::ShowTable.new(nil, self) do
column :"VMS", "", :left, :size=>12 do |d|
d["VMS"] if !d.nil?
end
column :"MEMORY (used)", "", :right, :size=>14 do |d|
d["MEMORY_USED"] if !d.nil?
end
column :"MEMORY (limit)", "", :right, :size=>14 do |d|
d["MEMORY"] if !d.nil?
end
column :"CPU (used)", "", :right, :size=>14 do |d|
d["CPU_USED"] if !d.nil?
end
column :"CPU (limit)", "", :right, :size=>14 do |d|
d["CPU"] if !d.nil?
end
end
TABLE_IMG = CLIHelper::ShowTable.new(nil, self) do
column :"IMAGE ID", "", :left, :size=>12 do |d|
d["ID"] if !d.nil?
end
column :"RVMS (used)", "", :right, :size=>14 do |d|
d["RVMS_USED"] if !d.nil?
end
column :"RVMS (limit)", "", :right, :size=>14 do |d|
d["RVMS"] if !d.nil?
end
end
HELP_QUOTA = <<-EOT.unindent
#-----------------------------------------------------------------------
# Supported quota limits:
#
# DATASTORE = [
# ID = <ID of the datastore>
# IMAGES = <Max. number of images in the datastore>
# SIZE = <Max. storage capacity (Mb) used in the datastore>
# ]
#
# VM = [
# VMS = <Max. number of VMs>
# MEMORY = <Max. allocated memory (Mb)>
# CPU = <Max. allocated CPU>
# ]
#
# NETWORK = [
# ID = <ID of the network>
# LEASES = <Max. number of IP leases from the network>
# ]
#
# IMAGE = [
# ID = <ID of the image>
# RVMS = <Max. number of VMs using the image>
# ]
#
# In any quota 0 means unlimited. The usage counters "*_USED" are
# shown for information purposes and will NOT be modified.
#-----------------------------------------------------------------------
EOT
# Edits the quota template of a resource
# @param resource [PoolElement] to get the current info from
# @param path [String] path to the new contents. If nil a editor will be
# used
# @return [String] contents of the new quotas
def self.set_quota(resource, path)
str = ""
if path.nil?
require 'tempfile'
tmp = Tempfile.new('one-cli')
path = tmp.path
rc = resource.info
if OpenNebula.is_error?(rc)
puts rc.message
exit -1
end
tmp << HELP_QUOTA
tmp << resource.template_like_str("DATASTORE_QUOTA") << "\n"
tmp << resource.template_like_str("VM_QUOTA") << "\n"
tmp << resource.template_like_str("NETWORK_QUOTA") << "\n"
tmp << resource.template_like_str("IMAGE_QUOTA") << "\n"
tmp.close
editor_path = ENV["EDITOR"] ? ENV["EDITOR"] : EDITOR_PATH
system("#{editor_path} #{path}")
unless $?.exitstatus == 0
puts "Editor not defined"
exit -1
end
str = File.read(path)
File.unlink(path)
else
str = File.read(path)
end
str
end
# Outputs formated quota information to stdout
# @param qh [Hash] with the quotas for a given resource
#
def self.format_quota(qh)
str_h1="%-80s"
puts
CLIHelper.print_header(str_h1 % "RESOURCE USAGE & QUOTAS",false)
puts
ds_quotas = [qh['DATASTORE_QUOTA']['DATASTORE']].flatten
if !ds_quotas[0].nil?
TABLE_DS.show(ds_quotas, {})
puts
end
vm_quotas = [qh['VM_QUOTA']['VM']].flatten
if !vm_quotas[0].nil?
TABLE_VM.show(vm_quotas, {})
puts
end
net_quotas = [qh['NETWORK_QUOTA']['NETWORK']].flatten
if !net_quotas[0].nil?
TABLE_NET.show(net_quotas, {})
puts
end
image_quotas = [qh['IMAGE_QUOTA']['IMAGE']].flatten
if !image_quotas[0].nil?
TABLE_IMG.show(image_quotas, {})
end
end
end

View File

@ -15,6 +15,7 @@
#--------------------------------------------------------------------------- #
require 'one_helper'
require 'one_helper/onequota_helper'
class OneUserHelper < OpenNebulaHelper::OneHelper
def self.rname
@ -163,11 +164,35 @@ class OneUserHelper < OpenNebulaHelper::OneHelper
d["AUTH_DRIVER"]
end
column :VMS, "Number of VMS", :size=>8 do |d|
if d.has_key?('VM_QUOTA') and d['VM_QUOTA'].has_key?('VM')
d['VM_QUOTA']['VM']['VMS']
else
"-"
end
end
column :MEMORY, "Total memory allocated to user VMs", :size=>8 do |d|
if d.has_key?('VM_QUOTA') and d['VM_QUOTA'].has_key?('VM')
d['VM_QUOTA']['VM']['MEMORY_USED']
else
"-"
end
end
column :CPU, "Total CPU allocated to user VMs", :size=>8 do |d|
if d.has_key?('VM_QUOTA') and d['VM_QUOTA'].has_key?('VM')
d['VM_QUOTA']['VM']['CPU_USED']
else
"-"
end
end
column :PASSWORD, "Password of the User", :size=>50 do |d|
d['PASSWORD']
end
default :ID, :GROUP, :NAME, :AUTH, :PASSWORD
default :ID, :GROUP, :NAME, :AUTH, :VMS, :MEMORY, :CPU
end
table
@ -207,5 +232,9 @@ class OneUserHelper < OpenNebulaHelper::OneHelper
CLIHelper.print_header(str_h1 % "USER TEMPLATE",false)
puts user.template_str
user_hash = user.to_hash
OneQuotaHelper.format_quota(user_hash['USER'])
end
end

View File

@ -97,4 +97,20 @@ cmd=CommandParser::CmdParser.new(ARGV) do
helper.show_resource(group,options)
end
quota_desc = <<-EOT.unindent
Set the quota limits for the group. If a path is not provided the editor
will be launched to modify the current quotas.
EOT
command :quota, quota_desc, :groupid, [:file, nil] do
helper.perform_action(args[0], options, "modified") do |group|
str = OneQuotaHelper.set_quota(group, args[1])
rc = group.set_quota(str)
if OpenNebula.is_error?(rc)
puts rc.message
exit -1
end
end
end
end

View File

@ -29,6 +29,7 @@ $: << RUBY_LIB_LOCATION+"/cli"
require 'command_parser'
require 'one_helper/oneuser_helper'
require 'one_helper/onequota_helper'
require 'uri'
@ -196,6 +197,26 @@ cmd=CommandParser::CmdParser.new(ARGV) do
end
end
quota_desc = <<-EOT.unindent
Set the quota limits for the user. If a path is not provided the editor
will be launched to modify the current quotas.
EOT
command :quota, quota_desc, :userid, [:file, nil] do
helper = OneUserHelper.new
helper.perform_action(args[0], options, "modified") do |user|
str = OneQuotaHelper.set_quota(user, args[1])
rc = user.set_quota(str)
if OpenNebula.is_error?(rc)
puts rc.message
exit -1
end
end
end
login_desc = <<-EOT.unindent
Creates the Login token for authentication
Examples:
@ -237,7 +258,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do
command :delete, delete_desc, [:range, :userid_list] do
helper = OneUserHelper.new
helper.perform_actions(args[0],options,"deleted") do |user|
helper.perform_actions(args[0], options, "deleted") do |user|
user.delete
end
end

View File

@ -225,3 +225,39 @@ int VectorAttribute::vector_value(const char *name, int & value) const
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
string VectorAttribute::vector_value_str(const char *name, int& value) const
{
map<string,string>::const_iterator it;
it = attribute_value.find(name);
if ( it == attribute_value.end() )
{
value = -1;
return "";
}
if ( it->second.empty() )
{
value = -1;
return "";
}
istringstream iss(it->second);
iss >> value;
if (iss.fail() || !iss.eof())
{
value = -1;
return "";
}
return it->second;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -44,11 +44,11 @@ class DatastoreDriver < OpenNebulaDriver
# Image Driver Protocol constants
ACTION = {
:mv => "MV",
:cp => "CP",
:rm => "RM",
:mkfs => "MKFS",
:log => "LOG"
:log => "LOG",
:stat => "STAT"
}
# Register default actions for the protocol
@ -58,7 +58,7 @@ class DatastoreDriver < OpenNebulaDriver
:threaded => true,
:retries => 0,
:local_actions => {
ACTION[:mv] => nil,
ACTION[:stat] => nil,
ACTION[:cp] => nil,
ACTION[:rm] => nil,
ACTION[:mkfs] => nil
@ -77,19 +77,15 @@ class DatastoreDriver < OpenNebulaDriver
@types = ds_type
end
# register_action(ACTION[:mv].to_sym, method("mv"))
register_action(ACTION[:cp].to_sym, method("cp"))
register_action(ACTION[:rm].to_sym, method("rm"))
register_action(ACTION[:cp].to_sym, method("cp"))
register_action(ACTION[:rm].to_sym, method("rm"))
register_action(ACTION[:mkfs].to_sym, method("mkfs"))
register_action(ACTION[:stat].to_sym, method("stat"))
end
############################################################################
# Image Manager Protocol Actions (generic implementation)
############################################################################
# TODO: Integrate this with TM
# def mv(id, ds, src, dst)
# do_image_action(id, ds, :mv, "'#{src}' '#{dst}' '#{id}'")
# end
def cp(id, drv_message)
ds = get_ds_type(drv_message)
@ -106,6 +102,11 @@ class DatastoreDriver < OpenNebulaDriver
do_image_action(id, ds, :mkfs, "#{drv_message} #{id}")
end
def stat(id, drv_message)
ds = get_ds_type(drv_message)
do_image_action(id, ds, :stat, "#{drv_message} #{id}")
end
private
def is_available?(ds, id, action)
@ -130,8 +131,6 @@ class DatastoreDriver < OpenNebulaDriver
result, info = get_info_from_execution(rc)
PP.pp([ACTION[action], result, id, info],STDERR)
send_message(ACTION[action], result, id, info)
end

View File

@ -1,4 +1,4 @@
#!/usr/bin/env ruby
#!/bin/bash
# -------------------------------------------------------------------------- #
# Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) #
@ -16,54 +16,44 @@
# limitations under the License. #
#--------------------------------------------------------------------------- #
ONE_LOCATION=ENV["ONE_LOCATION"]
###############################################################################
# This script is used to copy a VM image (SRC) to the image repository as DST
# Several SRC types are supported
###############################################################################
if !ONE_LOCATION
RUBY_LIB_LOCATION="/usr/lib/one/ruby"
ETC_LOCATION="/etc/one/"
# -------- Set up the environment to source common tools & conf ------------
if [ -z "${ONE_LOCATION}" ]; then
LIB_LOCATION=/usr/lib/one
else
RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby"
ETC_LOCATION=ONE_LOCATION+"/etc/"
end
LIB_LOCATION=$ONE_LOCATION/lib
fi
$: << RUBY_LIB_LOCATION
. $LIB_LOCATION/sh/scripts_common.sh
require 'scripts_common'
require 'OpenNebula'
require 'quota'
DRIVER_PATH=$(dirname $0)
source ${DRIVER_PATH}/../libfs.sh
user_id = ARGV.shift
# -------- Get cp and datastore arguments from OpenNebula core ------------
overall_evalutation = ARGV.pop
exit -1 if overall_evalutation.to_i == 0
DRV_ACTION=$1
ID=$2
quota = Quota.new
XPATH="${DRIVER_PATH}/../xpath.rb -b $DRV_ACTION"
#q = {
# :cpu => 10,
# :memory => 2048,
# :storage => 100000,
# :num_vms => 5
#}
#
#quota.set(1, q)
#OpenNebula.log_debug("quotas: #{quota.get(1)}")
unset i XPATH_ELEMENTS
ARGV.each {|request|
obj, template_or_id, op, owner, acl_eval = request.split(':')
while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <($XPATH /DS_DRIVER_ACTION_DATA/IMAGE/PATH)
if ( obj == "TEMPLATE" && op == "USE" && ARGV.size == 1 )
rc = false
else
rc = quota.authorize(user_id, request)
end
if rc
OpenNebula.error_message rc
exit -1
end
}
SRC="${XPATH_ELEMENTS[0]}"
#OpenNebula.log_debug("AUTHORIZE ARGS: #{ARGV.join(' ')}")
SIZE=`fs_size $SRC`
exit 0
if [ "$SIZE" = "0" ]; then
log_error "Cannot determine size for $SRC"
exit -1
fi
echo "$SIZE"

View File

@ -16,4 +16,4 @@
# limitations under the License. #
#--------------------------------------------------------------------------- #
echo "dummy_path 1024"
echo "dummy_path"

View File

@ -16,4 +16,4 @@
# limitations under the License. #
#--------------------------------------------------------------------------- #
echo "dummy_path 1024"
echo "dummy_path"

View File

@ -1,3 +1,5 @@
#!/bin/sh
# -------------------------------------------------------------------------- #
# Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) #
# #
@ -14,16 +16,4 @@
# limitations under the License. #
#--------------------------------------------------------------------------- #
# Database URI
#:db: sqlite:///var/one/onequota.db
#-------------------------------------------------------------------------------
# Default quotas, these apply to all users. Leave empty to disable quota for
# a given metric.
#-------------------------------------------------------------------------------
:defaults:
:CPU:
:MEMORY:
:NUM_VMS:
:STORAGE:
echo "1024"

View File

@ -84,8 +84,4 @@ http://*)
;;
esac
# ---------------- Get the size of the image ------------
SIZE=`fs_du $DST`
echo "$DST $SIZE"
echo "$DST"

View File

@ -68,7 +68,7 @@ DST=`generate_image_path`
# ------------ Image to save_as disk, no need to create a FS ------------
if [ "$FSTYPE" = "save_as" ]; then
echo "$DST $SIZE"
echo "$DST"
exit 0
fi
@ -81,4 +81,4 @@ exec_and_log "$DD if=/dev/zero of=$DST bs=1 count=1 seek=${SIZE}M" \
exec_and_log "$MKFS_CMD" \
"Unable to create filesystem $FSTYPE in $DST"
echo "$DST $SIZE"
echo "$DST"

View File

@ -0,0 +1 @@
../common/stat

View File

@ -54,8 +54,8 @@ done < <($XPATH /DS_DRIVER_ACTION_DATA/DATASTORE/BASE_PATH \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VG_NAME \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/BASE_IQN \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/BASE_TID \
/DS_DRIVER_ACTION_DATA/IMAGE/PATH)
/DS_DRIVER_ACTION_DATA/IMAGE/PATH \
/DS_DRIVER_ACTION_DATA/IMAGE/SIZE)
BASE_PATH="${XPATH_ELEMENTS[0]}"
RESTRICTED_DIRS="${XPATH_ELEMENTS[1]}"
@ -66,10 +66,10 @@ VG_NAME="${XPATH_ELEMENTS[5]:-$VG_NAME}"
BASE_IQN="${XPATH_ELEMENTS[6]:-$BASE_IQN}"
BASE_TID="${XPATH_ELEMENTS[7]:-$BASE_TID}"
SRC="${XPATH_ELEMENTS[8]}"
SIZE="${XPATH_ELEMENTS[9]}"
set_up_datastore "$BASE_PATH" "$RESTRICTED_DIRS" "$SAFE_DIRS" "$UMASK"
SIZE=`fs_du $SRC`
LV_NAME="lv-one-${ID}"
IQN="$BASE_IQN:$DST_HOST.$VG_NAME.$LV_NAME"
DEV="/dev/$VG_NAME/$LV_NAME"
@ -110,4 +110,4 @@ ssh_exec_and_log "$DST_HOST" "$REGISTER_CMD" "Error registering $DST_HOST:$DEV"
exec_and_log "eval $DUMP | $SSH $DST_HOST $SUDO $DD of=$DEV bs=64k" \
"Error dumping $SRC to $DST_HOST:$DEV"
echo "$IQN $SIZE"
echo "$IQN"

View File

@ -90,7 +90,7 @@ EOF
# ------------ Image to save_as disk, no need to create a FS ------------
if [ "$FSTYPE" = "save_as" ]; then
echo "$DST $SIZE"
echo "$DST"
exit 0
fi
@ -99,4 +99,4 @@ fi
ssh_exec_and_log "$DST_HOST" "$REGISTER_CMD" \
"Error registering $DST_HOST:$DEV"
echo "$IQN $SIZE"
echo "$IQN"

View File

@ -0,0 +1 @@
../common/stat

View File

@ -88,14 +88,23 @@ EOF
# @param $1 - Path to the image
# @return size of the image in Mb
#-------------------------------------------------------------------------------
function fs_du {
if [ -d "$1" ]; then
SIZE=`du -sb "$1" | cut -f1`
function fs_size {
case $1 in
http://*)
SIZE=`curl --head $1 2>/dev/null | grep Length | cut -d: -f`
error=$?
else
SIZE=`stat -c %s "$1"`
error=$?
fi
;;
*)
if [ -d "$1" ]; then
SIZE=`du -sb "$1" | cut -f1`
error=$?
else
SIZE=`stat -c %s "$1"`
error=$?
fi
;;
esac
if [ $error -ne 0 ]; then
SIZE=0
@ -106,22 +115,6 @@ function fs_du {
echo "$SIZE"
}
#-------------------------------------------------------------------------------
# Computes the size of an image
# @param $1 - Path to the image
# @return size of the image in Mb
#-------------------------------------------------------------------------------
function qemu_size {
DISK="$1"
SIZE=`$QEMU_IMG info $DISK|grep "^virtual size:"|\
sed 's/^.*(\([0-9]\+\) bytes.*$/\1/g'`
SIZE=$((($SIZE+1048575)/1048576))
echo "$SIZE"
}
#-------------------------------------------------------------------------------
# Checks if a path is safe for copying the image from
# @param $1 - Path to the image

View File

@ -52,7 +52,8 @@ done < <($XPATH /DS_DRIVER_ACTION_DATA/DATASTORE/BASE_PATH \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/UMASK \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/HOST \
/DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/VG_NAME \
/DS_DRIVER_ACTION_DATA/IMAGE/PATH)
/DS_DRIVER_ACTION_DATA/IMAGE/PATH \
/DS_DRIVER_ACTION_DATA/IMAGE/SIZE)
BASE_PATH="${XPATH_ELEMENTS[0]}"
RESTRICTED_DIRS="${XPATH_ELEMENTS[1]}"
@ -61,11 +62,10 @@ UMASK="${XPATH_ELEMENTS[3]}"
DST_HOST="${XPATH_ELEMENTS[4]:-$HOST}"
VG_NAME="${XPATH_ELEMENTS[5]:-$VG_NAME}"
SRC="${XPATH_ELEMENTS[6]}"
SIZE="${XPATH_ELEMENTS[7]}"
set_up_datastore "$BASE_PATH" "$RESTRICTED_DIRS" "$SAFE_DIRS" "$UMASK"
SIZE=`fs_du $SRC`
LV_NAME="lv-one-${ID}"
LVM_SOURCE="$DST_HOST:$VG_NAME.$LV_NAME"
DEV="/dev/$VG_NAME/$LV_NAME"
@ -101,4 +101,4 @@ ssh_exec_and_log "$DST_HOST" "$REGISTER_CMD" "Error registering $DST_HOST:$DEV"
exec_and_log "eval $DUMP | $SSH $DST_HOST $SUDO $DD of=$DEV bs=64k" \
"Error dumping $SRC to $DST_HOST:$DEV"
echo "$LVM_SOURCE $SIZE"
echo "$LVM_SOURCE"

View File

@ -62,7 +62,7 @@ UMASK="${XPATH_ELEMENTS[3]}"
DST_HOST="${XPATH_ELEMENTS[4]:-$HOST}"
VG_NAME="${XPATH_ELEMENTS[5]:-$VG_NAME}"
FSTYPE="${XPATH_ELEMENTS[6]}"
SIZE="${XPATH_ELEMENTS[7]:-0}"
SIZE="${XPATH_ELEMENTS[7]}"
set_up_datastore "$BASE_PATH" "$RESTRICTED_DIRS" "$SAFE_DIRS" "$UMASK"
@ -80,7 +80,7 @@ EOF
# ------------ Image to save_as disk, no need to create a FS ------------
if [ "$FSTYPE" = "save_as" ]; then
echo "$LVM_SOURCE $SIZE"
echo "$LVM_SOURCE"
exit 0
fi
@ -89,4 +89,4 @@ fi
ssh_exec_and_log "$DST_HOST" "$REGISTER_CMD" \
"Error registering $DST_HOST:$DEV"
echo "$LVM_SOURCE $SIZE"
echo "$LVM_SOURCE"

View File

@ -0,0 +1 @@
../common/stat

View File

@ -87,8 +87,4 @@ case $SRC in
;;
esac
# ---------------- Get the size of the image ------------
SIZE=`fs_du $DST`
echo "$DST $SIZE"
echo "$DST"

View File

@ -67,7 +67,7 @@ DST=`generate_image_path`
# ------------ Image to save_as disk, no need to create a FS ------------
if [ "$FSTYPE" = "save_as" ]; then
echo "$DST $SIZE"
echo "$DST"
exit 0
fi
@ -91,8 +91,4 @@ exec_and_log "$QEMU_IMG convert -O $IMAGE_FORMAT $DISK_TMP $DISK" \
exec_and_log "rm -f $DISK_TMP" \
"Unable to remove temporary disk $DISK_TMP"
# ---------------- Get the size of the image ------------
SIZE=`qemu_size $DISK`
echo "$DST $SIZE"
echo "$DST"

View File

@ -0,0 +1 @@
../common/stat

View File

@ -683,7 +683,15 @@ int DispatchManager::finalize(
int vid)
{
VirtualMachine * vm;
ostringstream oss;
ostringstream oss;
Template * tmpl;
User * user;
Group * group;
int uid;
int gid;
VirtualMachine::VmState state;
vm = vmpool->get(vid,true);
@ -701,6 +709,8 @@ int DispatchManager::finalize(
Nebula& nd = Nebula::instance();
TransferManager * tm = nd.get_tm();
LifeCycleManager * lcm = nd.get_lcm();
UserPool * upool = nd.get_upool();
GroupPool * gpool = nd.get_gpool();
switch (state)
{
@ -722,17 +732,55 @@ int DispatchManager::finalize(
vmpool->update(vm);
vm->log("DiM", Log::INFO, "New VM state is DONE.");
uid = vm->get_uid();
gid = vm->get_gid();
tmpl = vm->clone_template();
vm->unlock();
if ( uid != UserPool::ONEADMIN_ID )
{
user = upool->get(uid, true);
if ( user != 0 )
{
user->quota.vm_del(tmpl);
upool->update(user);
user->unlock();
}
}
if ( gid != GroupPool::ONEADMIN_ID )
{
group = gpool->get(gid, true);
if ( group != 0 )
{
group->quota.vm_del(tmpl);
gpool->update(group);
group->unlock();
}
}
delete tmpl;
break;
case VirtualMachine::ACTIVE:
lcm->trigger(LifeCycleManager::DELETE,vid);
vm->unlock();
break;
case VirtualMachine::DONE:
vm->unlock();
break;
}
vm->unlock();
return 0;
}

View File

@ -17,6 +17,8 @@
#include "DispatchManager.h"
#include "NebulaLog.h"
#include "Nebula.h"
void DispatchManager::suspend_success_action(int vid)
{
VirtualMachine * vm;
@ -97,11 +99,22 @@ void DispatchManager::stop_success_action(int vid)
void DispatchManager::done_action(int vid)
{
VirtualMachine * vm;
VirtualMachine * vm;
Template * tmpl;
int uid;
int gid;
VirtualMachine::LcmState lcm_state;
VirtualMachine::VmState dm_state;
Nebula& nd = Nebula::instance();
UserPool * upool = nd.get_upool();
GroupPool* gpool = nd.get_gpool();
User * user;
Group * group;
vm = vmpool->get(vid,true);
if ( vm == 0 )
@ -130,6 +143,44 @@ void DispatchManager::done_action(int vid)
vm->release_network_leases();
vm->release_disk_images();
uid = vm->get_uid();
gid = vm->get_gid();
tmpl = vm->clone_template();
vm->unlock();
/* ---------------- Update Group & User quota counters -------------- */
if ( uid != UserPool::ONEADMIN_ID )
{
user = upool->get(uid, true);
if ( user != 0 )
{
user->quota.vm_del(tmpl);
upool->update(user);
user->unlock();
}
}
if ( gid != GroupPool::ONEADMIN_ID )
{
group = gpool->get(gid, true);
if ( group != 0 )
{
group->quota.vm_del(tmpl);
gpool->update(group);
group->unlock();
}
}
delete tmpl;
}
else
{
@ -137,10 +188,10 @@ void DispatchManager::done_action(int vid)
oss << "done action received but VM " << vid << " not in ACTIVE state";
NebulaLog::log("DiM",Log::ERROR,oss);
vm->unlock();
}
vm->unlock();
return;
}

View File

@ -130,14 +130,18 @@ string& Group::to_xml(string& xml) const
{
ostringstream oss;
string collection_xml;
string quota_xml;
ObjectCollection::to_xml(collection_xml);
quota.to_xml(quota_xml);
oss <<
"<GROUP>" <<
"<ID>" << oid << "</ID>" <<
"<NAME>" << name << "</NAME>" <<
collection_xml <<
quota_xml <<
"</GROUP>";
xml = oss.str();
@ -179,6 +183,8 @@ int Group::from_xml(const string& xml)
ObjectXML::free_nodes(content);
rc += quota.from_xml(this);
if (rc != 0)
{
return -1;

View File

@ -97,7 +97,9 @@ int Image::insert(SqlDB *db, string& error_str)
string dev_prefix;
string source_attr;
string saved_id;
string size_attr;
istringstream iss;
ostringstream oss;
// ---------------------------------------------------------------------
@ -141,6 +143,13 @@ int Image::insert(SqlDB *db, string& error_str)
obj_template->set(dev_att);
}
// ------------ SIZE --------------------
erase_template_attribute("SIZE", size_attr);
iss.str(size_attr);
iss >> size_mb;
// ------------ PATH & SOURCE --------------------
erase_template_attribute("PATH", path);
@ -150,26 +159,13 @@ int Image::insert(SqlDB *db, string& error_str)
{
if ( source.empty() && path.empty() )
{
string size_attr;
istringstream iss;
erase_template_attribute("SIZE", size_attr);
erase_template_attribute("FSTYPE", fs_type);
// DATABLOCK image needs SIZE and FSTYPE
if (type != DATABLOCK || size_attr.empty() || fs_type.empty())
// DATABLOCK image needs FSTYPE
if (type != DATABLOCK || fs_type.empty())
{
goto error_no_path;
}
iss.str(size_attr);
iss >> size_mb;
if (iss.fail() == true)
{
goto error_size_format;
}
}
else if ( !source.empty() && !path.empty() )
{
@ -178,20 +174,7 @@ int Image::insert(SqlDB *db, string& error_str)
}
else
{
string size_attr;
istringstream iss;
fs_type = "save_as";
erase_template_attribute("SIZE", size_attr);
iss.str(size_attr);
iss >> size_mb;
if (iss.fail() == true)
{
goto error_size_format;
}
}
state = LOCKED; //LOCKED till the ImageManager copies it to the Repository
@ -220,10 +203,6 @@ error_no_path:
}
goto error_common;
error_size_format:
error_str = "Wrong number in SIZE.";
goto error_common;
error_path_and_source:
error_str = "Template malformed, PATH and SOURCE are mutually exclusive.";
goto error_common;
@ -464,7 +443,7 @@ int Image::disk_attribute( VectorAttribute * disk,
get_template_attribute("DEV_PREFIX", dev_prefix);
if (dev_prefix.empty())//Removed from image template, get it again from defaults
if (dev_prefix.empty())//Removed from image template, get it again
{
dev_prefix = ImagePool::default_dev_prefix();
}
@ -561,3 +540,30 @@ int Image::set_type(string& _type)
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
Image::ImageType Image::str_to_type(string& str_type)
{
Image::ImageType it = OS;
if (str_type.empty())
{
str_type = ImagePool::default_type();
}
TO_UPPER(str_type);
if ( str_type == "OS" )
{
it = OS;
}
else if ( str_type == "CDROM" )
{
it = CDROM;
}
else if ( str_type == "DATABLOCK" )
{
it = DATABLOCK;
}
return it;
}

View File

@ -126,4 +126,3 @@ void ImageManager::do_action(const string &action, void * arg)
NebulaLog::log("ImM", Log::ERROR, oss);
}
}

View File

@ -18,6 +18,10 @@
#include "NebulaLog.h"
#include "ImagePool.h"
#include "SSLTools.h"
#include "SyncRequest.h"
#include "Template.h"
#include "Nebula.h"
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
@ -259,10 +263,23 @@ int ImageManager::enable_image(int iid, bool to_enable)
int ImageManager::delete_image(int iid, const string& ds_data)
{
Image * img;
string source;
string img_tmpl;
string * drv_msg;
Image * img;
string source;
string img_tmpl;
string * drv_msg;
int size;
int ds_id;
int uid;
int gid;
Group* group;
User * user;
Nebula& nd = Nebula::instance();
UserPool * upool = nd.get_upool();
GroupPool* gpool = nd.get_gpool();
img = ipool->get(iid,true);
@ -303,7 +320,11 @@ int ImageManager::delete_image(int iid, const string& ds_data)
drv_msg = format_message(img->to_xml(img_tmpl), ds_data);
source = img->get_source();
size = img->get_size();
ds_id = img->get_ds_id();
uid = img->get_uid();
gid = img->get_gid();
if (source.empty())
{
string err_str;
@ -326,6 +347,41 @@ int ImageManager::delete_image(int iid, const string& ds_data)
delete drv_msg;
/* -------------------- Update Group & User quota counters -------------- */
Template img_usage;
img_usage.add("DATASTORE", ds_id);
img_usage.add("SIZE", size);
if ( uid != UserPool::ONEADMIN_ID )
{
user = upool->get(uid, true);
if ( user != 0 )
{
user->quota.ds_del(&img_usage);
upool->update(user);
user->unlock();
}
}
if ( gid != GroupPool::ONEADMIN_ID )
{
group = gpool->get(gid, true);
if ( group != 0 )
{
group->quota.ds_del(&img_usage);
gpool->update(group);
group->unlock();
}
}
return 0;
}
@ -395,6 +451,80 @@ int ImageManager::register_image(int iid, const string& ds_data)
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int ImageManager::stat_image(Template* img_tmpl,
const string& ds_data,
string& res)
{
const ImageManagerDriver* imd = get();
string* drv_msg;
string type_att;
ostringstream img_data;
SyncRequest sr;
int rc = 0;
img_tmpl->get("TYPE", type_att);
switch (Image::str_to_type(type_att))
{
case Image::OS:
case Image::CDROM:
img_tmpl->get("SOURCE", res);
if (!res.empty())
{
res = "0";
return 0;
}
img_tmpl->get("PATH", res);
if (res.empty())
{
res = "Either PATH or SOURCE are required for " + type_att;
return -1;
}
img_data << "<IMAGE><PATH>" << res << "</PATH></IMAGE>";
break;
case Image::DATABLOCK:
img_tmpl->get("SIZE", res);
if (res.empty())
{
res = "SIZE attribute is mandatory for DATABLOCK.";
return -1;
}
return 0;
}
add_request(&sr);
drv_msg = format_message(img_data.str(), ds_data);
imd->stat(sr.id, *drv_msg);
sr.wait();
delete drv_msg;
res = sr.message;
if ( sr.result != true )
{
rc = -1;
}
return rc;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -38,13 +38,12 @@ void ImageManagerDriver::cp(int oid,
/* -------------------------------------------------------------------------- */
void ImageManagerDriver::mv(int oid,
const string& source,
const string& destination) const
void ImageManagerDriver::stat(int oid,
const string& drv_msg) const
{
ostringstream os;
os << "MV " << oid << " " << source << " " << destination << endl;
os << "STAT " << oid << " " << drv_msg << endl;
write(os);
}
@ -79,26 +78,329 @@ void ImageManagerDriver::rm(int oid, const string& drv_msg) const
/* MAD Interface */
/* ************************************************************************** */
static void stat_action(istringstream& is, int id, const string& result)
{
string size_mb;
string info;
Nebula& nd = Nebula::instance();
ImageManager * im = nd.get_imagem();
if ( result == "SUCCESS" )
{
if ( is.good() )
{
is >> size_mb >> ws;
}
if ( is.fail() )
{
im->notify_request(id, false, "Cannot get size from STAT");
}
im->notify_request(id, true, size_mb);
}
else
{
getline(is,info);
im->notify_request(id, false, info);
}
}
/* -------------------------------------------------------------------------- */
static void cp_action(istringstream& is,
ImagePool* ipool,
int id,
const string& result)
{
string source;
string info;
Image * image;
ostringstream oss;
image = ipool->get(id,true);
if ( image == 0 )
{
return;
}
if ( result == "FAILURE" )
{
goto error;
}
if ( is.good() )
{
is >> source >> ws;
}
if ( is.fail() )
{
goto error;
}
image->set_source(source);
image->set_state(Image::READY);
ipool->update(image);
image->unlock();
NebulaLog::log("ImM", Log::INFO, "Image copied and ready to use.");
return;
error:
oss << "Error copying image in the repository";
getline(is, info);
if (!info.empty() && (info[0] != '-'))
{
oss << ": " << info;
}
NebulaLog::log("ImM", Log::ERROR, oss);
image->set_template_error_message(oss.str());
image->set_state(Image::ERROR);
ipool->update(image);
image->unlock();
return;
}
/* -------------------------------------------------------------------------- */
static void mkfs_action(istringstream& is,
ImagePool* ipool,
int id,
const string& result)
{
string source;
Image * image;
bool is_saving;
string disk_id;
string vm_id;
string info;
int rc;
VirtualMachine * vm;
ostringstream oss;
Nebula& nd = Nebula::instance();
VirtualMachinePool * vmpool = nd.get_vmpool();
image = ipool->get(id, true);
if ( image == 0 )
{
return;
}
if ( result == "FAILURE" )
{
goto error_img;
}
if ( is.good() )
{
is >> source >> ws;
}
if ( is.fail() )
{
goto error_img;
}
is_saving = image->isSaving();
image->set_source(source);
if (is_saving)
{
image->get_template_attribute("SAVED_DISK_ID", disk_id);
image->get_template_attribute("SAVED_VM_ID", vm_id);
}
else
{
image->set_state(Image::READY);
NebulaLog::log("ImM", Log::INFO, "Image created and ready to use");
}
ipool->update(image);
image->unlock();
if ( ! is_saving )
{
return;
}
/* ---------------- Set up information for the Saved Image -------------- */
vm = vmpool->get(vm_id, true);
if ( vm == 0 )
{
goto error_save_get;
}
rc = vm->save_disk(disk_id, source, id);
if ( rc == -1 )
{
goto error_save_state;
}
vmpool->update(vm);
vm->unlock();
return;
error_img:
oss << "Error creating datablock";
goto error;
error_save_get:
oss << "Image created for SAVE_AS, but the associated VM does not exist.";
goto error_save;
error_save_state:
vm->unlock();
oss << "Image created for SAVE_AS, but VM is no longer running";
error_save:
image = ipool->get(id, true);
if ( image == 0 )
{
NebulaLog::log("ImM", Log::ERROR, oss);
return;
}
error:
getline(is,info);
if (!info.empty() && (info[0] != '-'))
{
oss << ": " << info;
}
NebulaLog::log("ImM", Log::ERROR, oss);
image->set_template_error_message(oss.str());
image->set_state(Image::ERROR);
ipool->update(image);
image->unlock();
return ;
}
/* -------------------------------------------------------------------------- */
static void rm_action(istringstream& is,
ImagePool* ipool,
int id,
const string& result)
{
int rc;
string tmp_error;
string source;
string info;
Image * image;
ostringstream oss;
image = ipool->get(id, true);
if ( image == 0 )
{
return;
}
source = image->get_source();
rc = ipool->drop(image, tmp_error);
image->unlock();
if ( result == "FAILURE" )
{
goto error;
}
else if ( rc < 0 )
{
goto error_drop;
}
NebulaLog::log("ImM", Log::INFO, "Image successfully removed.");
return;
error_drop:
oss << "Error removing image from DB: " << tmp_error
<< ". Remove image source " << source << " to completely delete image.";
NebulaLog::log("ImM", Log::ERROR, oss);
return;
error:
oss << "Error removing image from datastore. Manually remove image source "
<< source << " to completely delete the image";
getline(is,info);
if (!info.empty() && (info[0] != '-'))
{
oss << ": " << info;
}
NebulaLog::log("ImM", Log::ERROR, oss);
image->set_template_error_message(oss.str());
image->set_state(Image::ERROR);
ipool->update(image);
image->unlock();
return;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void ImageManagerDriver::protocol(
string& message)
{
istringstream is(message);
ostringstream os;
ostringstream oss;
string action;
string result;
string action;
string result;
string source;
string info;
int id;
oss << "Message received: " << message;
NebulaLog::log("ImG", Log::DEBUG, oss);
int id;
Image * image;
string source;
unsigned int size_mb;
// --------------------- Parse the driver message --------------------------
string info;
os << "Message received: " << message;
NebulaLog::log("ImG", Log::DEBUG, os);
// Parse the driver message
if ( is.good() )
is >> action >> ws;
else
@ -117,8 +419,6 @@ void ImageManagerDriver::protocol(
{
if ( action == "LOG" )
{
string info;
is.clear();
getline(is,info);
@ -131,145 +431,21 @@ void ImageManagerDriver::protocol(
else
return;
// Parse driver message for CP, MV and MKFS
// <CP|MV|MKFS> SUCESS IMAGE_ID SOURCE SIZE
if ( (result == "SUCCESS") && (action != "RM") )
if ( action == "STAT" )
{
if ( is.good() )
{
is >> source >> ws;
}
if ( is.good() )
{
is >> size_mb >> ws;
}
if ( is.fail() )
{
result = "FAILURE";
}
stat_action(is, id, result);
}
// Get the image from the pool
image = ipool->get(id,true);
if ( image == 0 )
else if ( action == "CP" )
{
return;
}
// Driver Actions
if ( action == "CP" )
{
if ( result == "SUCCESS" )
{
image->set_source(source);
image->set_size(size_mb);
image->set_state(Image::READY);
ipool->update(image);
NebulaLog::log("ImM", Log::INFO, "Image copied and ready to use.");
}
else
{
goto error_cp;
}
cp_action(is, ipool, id, result);
}
else if ( action == "MKFS" )
{
if ( result == "SUCCESS" )
{
bool is_saving = image->isSaving();
string disk_id;
string vm_id;
int rc;
image->set_source(source);
if (is_saving)
{
image->get_template_attribute("SAVED_DISK_ID",disk_id);
image->get_template_attribute("SAVED_VM_ID", vm_id);
}
else
{
image->set_size(size_mb);
image->set_state(Image::READY);
NebulaLog::log("ImM", Log::INFO,
"Image created and ready to use");
}
ipool->update(image);
image->unlock();
if (is_saving)
{
Nebula& nd = Nebula::instance();
VirtualMachinePool * vmpool = nd.get_vmpool();
VirtualMachine * vm;
istringstream iss(vm_id);
int vm_id_i;
iss >> vm_id_i;
vm = vmpool->get(vm_id_i, true);
if ( vm == 0 )
{
goto error_save_no_vm;
}
rc = vm->save_disk(disk_id, source, id);
if ( rc == -1 )
{
vm->unlock();
goto error_save_state_vm;
}
vmpool->update(vm);
vm->unlock();
}
return;
}
else
{
goto error_mkfs;
}
mkfs_action(is, ipool, id, result);
}
else if ( action == "RM" )
{
int rc;
string tmp_error;
rc = ipool->drop(image, tmp_error);
if ( rc < 0 )
{
NebulaLog::log("ImM",Log::ERROR,"Image could not be removed from DB");
}
if ( result == "SUCCESS" )
{
NebulaLog::log("ImM",Log::INFO,"Image successfully removed.");
}
else
{
goto error_rm;
}
rm_action(is, ipool, id, result);
}
else if (action == "LOG")
{
@ -277,72 +453,6 @@ void ImageManagerDriver::protocol(
NebulaLog::log("ImM", log_type(result[0]), info.c_str());
}
image->unlock();
return;
error_cp:
os.str("");
os << "Error copying image in the repository";
goto error_common;
error_mkfs:
os.str("");
os << "Error creating datablock";
goto error_common;
error_rm:
os.str("");
os << "Error removing image from repository. Remove file " << image->get_source()
<< " to completely delete image.";
image->unlock();
getline(is,info);
if (!info.empty() && (info[0] != '-'))
{
os << ": " << info;
}
NebulaLog::log("ImM", Log::ERROR, os);
return;
error_save_no_vm:
os.str("");
os << "Image created for SAVE_AS, but the associated VM does not exist.";
goto error_save_common;
error_save_state_vm:
os.str("");
os << "Image created for SAVE_AS, but VM is no longer running";
goto error_save_common;
error_save_common:
image = ipool->get(id, true);
if (image == 0 )
{
return;
}
error_common:
getline(is,info);
if (!info.empty() && (info[0] != '-'))
{
os << ": " << info;
image->set_template_error_message(os.str());
}
NebulaLog::log("ImM", Log::ERROR, os);
image->set_state(Image::ERROR);
ipool->update(image);
image->unlock();
return;
}

View File

@ -349,6 +349,11 @@ void ImagePool::authorize_disk(VectorAttribute * disk,int uid, AuthRequest * ar)
}
img = get(source , uiid, true);
if ( img != 0 )
{
disk->replace("IMAGE_ID", img->get_oid());
}
}
else if (!(source = disk->vector_value("IMAGE_ID")).empty())
{

View File

@ -22,6 +22,7 @@
#include <sstream>
#include "MadManager.h"
#include "SyncRequest.h"
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
@ -336,3 +337,110 @@ void MadManager::listener()
}
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void MadManager::check_time_outs_action()
{
map<int, SyncRequest *>::iterator it;
time_t the_time = time(0);
lock();
it = sync_requests.begin();
while ( it != sync_requests.end())
{
if ((it->second->time_out != 0) && (the_time > it->second->time_out))
{
SyncRequest * ar = it->second;
sync_requests.erase(it++);
ar->result = false;
ar->timeout = true;
ar->message = "Request timeout";
ar->notify();
}
else
{
++it;
}
}
unlock();
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void MadManager::add_request(SyncRequest *ar)
{
static int request_id = 0;
lock();
ar->id = request_id++;
sync_requests.insert(sync_requests.end(),make_pair(ar->id,ar));
unlock();
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
SyncRequest * MadManager::get_request(int id)
{
SyncRequest * ar = 0;
map<int,SyncRequest *>::iterator it;
ostringstream oss;
lock();
it = sync_requests.find(id);
if ( it != sync_requests.end())
{
ar = it->second;
sync_requests.erase(it);
}
unlock();
return ar;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void MadManager::notify_request(int id, bool result, const string& message)
{
SyncRequest * ar;
ar = get_request(id);
if ( ar == 0 )
{
return;
}
ar->result = result;
if ( message != "-" )
{
if ( !ar->message.empty() )
{
ar->message.append("; ");
}
ar->message.append(message);
}
ar->notify();
}

View File

@ -512,8 +512,7 @@ void Nebula::start()
if (!auth_mads.empty())
{
//Defaults 60s to timeout auth requests
authm = new AuthManager(timer_period,60,auth_mads);
authm = new AuthManager(timer_period, auth_mads);
}
else
{

View File

@ -23,11 +23,11 @@ module OpenNebula
# Constants and Class Methods
#######################################################################
GROUP_METHODS = {
:info => "group.info",
:allocate => "group.allocate",
:delete => "group.delete"
:info => "group.info",
:allocate => "group.allocate",
:delete => "group.delete",
:quota => "group.quota"
}
# Flag for requesting connected user's group info
@ -120,6 +120,20 @@ module OpenNebula
super(GROUP_METHODS[:delete])
end
# Sets the group quota limits
# @param quota [String] a template (XML or txt) with the new quota limits
#
# @return [nil, OpenNebula::Error] nil in case of success, Error
# otherwise
def set_quota(quota)
return Error.new('ID not defined') if !@pe_id
rc = @client.call(GROUP_METHODS[:quota],@pe_id, quota)
rc = nil if !OpenNebula.is_error?(rc)
return rc
end
# ---------------------------------------------------------------------
# Helpers to get information
# ---------------------------------------------------------------------

View File

@ -30,7 +30,8 @@ module OpenNebula
:passwd => "user.passwd",
:chgrp => "user.chgrp",
:update => "user.update",
:chauth => "user.chauth"
:chauth => "user.chauth",
:quota => "user.quota"
}
SELF = -1
@ -144,6 +145,20 @@ module OpenNebula
return rc
end
# Sets the user quota limits
# @param quota [String] a template (XML or txt) with the new quota limits
#
# @return [nil, OpenNebula::Error] nil in case of success, Error
# otherwise
def set_quota(quota)
return Error.new('ID not defined') if !@pe_id
rc = @client.call(USER_METHODS[:quota],@pe_id, quota)
rc = nil if !OpenNebula.is_error?(rc)
return rc
end
#######################################################################
# Helpers to get User information
#######################################################################

View File

@ -1,9 +1,52 @@
#!/bin/bash
if [ "$1" != "sqlite" -a "$1" != "mysql" -a "$1" != "postgres" ]; then
echo "$0: The first command needs to be one of {sqlite, mysql}"
exit 1
fi
usage()
{
cat << EOF
usage: $0 options
This script upgrades oZones DB from 3.4 to 3.6
OPTIONS:
-h Show this message
-t DB type, can be "mysql" or "sqlite". Compulsory
-s Server address (for mysql only, "localhost" if not defined)
-u User name (for mysql only, compulsory)
-p User password (for mysql only, compulsory)
-l DB path (for sqlite only, compulsory)
EOF
}
while getopts “t:u:p:s:l:h” OPTION
do
case $OPTION in
h)
usage
exit 1
;;
t)
TYPE=$OPTARG
;;
s)
SERVER=$OPTARG
;;
u)
USERNAME=$OPTARG
;;
p)
PASSWD=$OPTARG
;;
l)
DB_PATH=$OPTARG
;;
?)
usage
exit
;;
esac
done
MIGRATE_CMDS=$(cat <<EOF
drop table zones;
@ -20,33 +63,31 @@ drop table o_zones_vdcs;
EOF
)
if [ "$1" == "sqlite" ]; then
if [ ! -f $2 ]; then
echo "$0: A valid sqlite DB file needs to be provided as second argument"
if [ $TYPE == "sqlite" ]; then
if [ -z "$DB_PATH" -o ! -f "$DB_PATH" ]; then
usage
exit 1
fi
sqlite3 $2 < <(echo $MIGRATE_CMDS)
sqlite3 $DB_PATH < <(echo $MIGRATE_CMDS)
RC=$?
fi
if [ "$1" == "mysql" ]; then
if [ -z $2 -a -z $3 ]; then
echo "$0: A valid username and password for mysql server needs to be provided"
echo "Usage: $0 username password <mysql_server_location>"
echo " where <mysql_server_location> is optional and defaults to localhost"
if [ $TYPE == "mysql" ]; then
if [ -z $USERNAME -a -z $PASSWD ]; then
usage
exit 1
fi
if [ -z $4 ]; then
MYSQL_SERVER="localhost"
else
MYSQL_SERVER=$4
if [ -z $SERVER ]; then
SERVER="localhost"
fi
mysql -u $2 --password=$3 -h $MYSQL_SERVER ozones < <(echo $MIGRATE_CMDS)
mysql -u $USERNAME --password=$PASSWD -h $SERVER ozones < <(echo $MIGRATE_CMDS)
RC=$?
fi
if [ $? -ne 0 ]; then
if [ $RC -ne 0 ]; then
echo "There was an error during migration"
else
echo "Migration successful"

View File

@ -15,7 +15,7 @@
/* -------------------------------------------------------------------------- */
#include "PoolObjectAuth.h"
#include "AuthManager.h"
#include "AuthRequest.h"
#include "AclRule.h"
void PoolObjectAuth::get_acl_rules(AclRule& owner_rule,

View File

@ -112,6 +112,246 @@ bool Request::basic_authorization(int oid,
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool Request::user_quota_authorization (Template * tmpl,
PoolObjectSQL::ObjectType object,
RequestAttributes& att,
string& error_str)
{
Nebula& nd = Nebula::instance();
UserPool * upool = nd.get_upool();
User * user;
bool rc = false;
user = upool->get(att.uid, true);
if ( user == 0 )
{
error_str = "User not found";
return false;
}
switch (object)
{
case PoolObjectSQL::IMAGE:
rc = user->quota.ds_check(tmpl, error_str);
break;
case PoolObjectSQL::VM:
case PoolObjectSQL::TEMPLATE:
rc = user->quota.vm_check(tmpl, error_str);
break;
default:
break;
}
if (rc == true)
{
upool->update(user);
}
user->unlock();
return rc;
}
/* -------------------------------------------------------------------------- */
bool Request::group_quota_authorization (Template * tmpl,
PoolObjectSQL::ObjectType object,
RequestAttributes& att,
string& error_str)
{
Nebula& nd = Nebula::instance();
GroupPool * gpool = nd.get_gpool();
Group * group;
bool rc = false;
group = gpool->get(att.gid, true);
if ( group == 0 )
{
error_str = "Group not found";
return false;
}
switch (object)
{
case PoolObjectSQL::IMAGE:
rc = group->quota.ds_check(tmpl, error_str);
break;
case PoolObjectSQL::VM:
case PoolObjectSQL::TEMPLATE:
rc = group->quota.vm_check(tmpl, error_str);
break;
default:
break;
}
if (rc == true)
{
gpool->update(group);
}
group->unlock();
return rc;
}
/* -------------------------------------------------------------------------- */
void Request::user_quota_rollback(Template * tmpl,
PoolObjectSQL::ObjectType object,
RequestAttributes& att)
{
Nebula& nd = Nebula::instance();
UserPool * upool = nd.get_upool();
User * user;
user = upool->get(att.uid, true);
if ( user == 0 )
{
return;
}
switch (object)
{
case PoolObjectSQL::IMAGE:
user->quota.ds_del(tmpl);
break;
case PoolObjectSQL::VM:
case PoolObjectSQL::TEMPLATE:
user->quota.vm_del(tmpl);
break;
default:
break;
}
upool->update(user);
user->unlock();
}
/* -------------------------------------------------------------------------- */
void Request::group_quota_rollback(Template * tmpl,
PoolObjectSQL::ObjectType object,
RequestAttributes& att)
{
Nebula& nd = Nebula::instance();
GroupPool * gpool = nd.get_gpool();
Group * group;
group = gpool->get(att.gid, true);
if ( group == 0 )
{
return;
}
switch (object)
{
case PoolObjectSQL::IMAGE:
group->quota.ds_del(tmpl);
break;
case PoolObjectSQL::VM:
case PoolObjectSQL::TEMPLATE:
group->quota.vm_del(tmpl);
break;
default:
break;
}
gpool->update(group);
group->unlock();
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool Request::quota_authorization(Template * tmpl,
PoolObjectSQL::ObjectType object,
RequestAttributes& att)
{
string error_str;
if (object != PoolObjectSQL::IMAGE &&
object != PoolObjectSQL::VM &&
object != PoolObjectSQL::TEMPLATE)
{
return true;
}
// uid/gid == -1 means do not update user/group
if ( att.uid != UserPool::ONEADMIN_ID && att.uid != -1)
{
if ( user_quota_authorization(tmpl, object, att, error_str) == false )
{
failure_response(AUTHORIZATION,
authorization_error(error_str, att),
att);
return false;
}
}
if ( att.gid != GroupPool::ONEADMIN_ID && att.gid != -1)
{
if ( group_quota_authorization(tmpl, object, att, error_str) == false )
{
user_quota_rollback(tmpl, object, att);
failure_response(AUTHORIZATION,
authorization_error(error_str, att),
att);
return false;
}
}
return true;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void Request::quota_rollback(Template * tmpl,
PoolObjectSQL::ObjectType object,
RequestAttributes& att)
{
if (object != PoolObjectSQL::IMAGE &&
object != PoolObjectSQL::VM &&
object != PoolObjectSQL::TEMPLATE)
{
return;
}
// uid/gid == -1 means do not update user/group
if ( att.uid != UserPool::ONEADMIN_ID && att.uid != -1 )
{
user_quota_rollback(tmpl, object, att);
}
if ( att.gid != GroupPool::ONEADMIN_ID && att.gid != -1 )
{
group_quota_rollback(tmpl, object, att);;
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void Request::failure_response(ErrorCode ec, const string& str_val,
RequestAttributes& att)
{

View File

@ -34,6 +34,7 @@
#include "RequestManagerUser.h"
#include "RequestManagerAcl.h"
#include "RequestManagerCluster.h"
#include "RequestManagerGroup.h"
#include <sys/signal.h>
#include <sys/socket.h>
@ -233,6 +234,10 @@ void RequestManager::register_xml_methods()
// User Methods
xmlrpc_c::methodPtr user_change_password(new UserChangePassword());
xmlrpc_c::methodPtr user_change_auth(new UserChangeAuth());
xmlrpc_c::methodPtr user_set_quota(new UserSetQuota());
// Group Methods
xmlrpc_c::methodPtr group_set_quota(new GroupSetQuota());
// VMTemplate Methods
xmlrpc_c::methodPtr template_instantiate(new VMTemplateInstantiate());
@ -384,6 +389,7 @@ void RequestManager::register_xml_methods()
RequestManagerRegistry.addMethod("one.group.allocate", group_allocate);
RequestManagerRegistry.addMethod("one.group.delete", group_delete);
RequestManagerRegistry.addMethod("one.group.info", group_info);
RequestManagerRegistry.addMethod("one.group.quota", group_set_quota);
RequestManagerRegistry.addMethod("one.grouppool.info", grouppool_info);
@ -409,6 +415,7 @@ void RequestManager::register_xml_methods()
RequestManagerRegistry.addMethod("one.user.passwd", user_change_password);
RequestManagerRegistry.addMethod("one.user.chgrp", user_chown);
RequestManagerRegistry.addMethod("one.user.chauth", user_change_auth);
RequestManagerRegistry.addMethod("one.user.quota", user_set_quota);
RequestManagerRegistry.addMethod("one.userpool.info", userpool_info);

View File

@ -15,7 +15,6 @@
/* -------------------------------------------------------------------------- */
#include "RequestManagerAllocate.h"
#include "NebulaLog.h"
#include "Nebula.h"
#include "PoolObjectSQL.h"
@ -80,7 +79,7 @@ bool VirtualMachineAllocate::allocate_authorization(
VirtualMachineTemplate * ttmpl = static_cast<VirtualMachineTemplate *>(tmpl);
// Check template for restricted attributes
// ------------ Check template for restricted attributes -------------------
if ( att.uid != 0 && att.gid != GroupPool::ONEADMIN_ID )
{
@ -98,6 +97,8 @@ bool VirtualMachineAllocate::allocate_authorization(
}
}
// ------------------ Authorize VM create operation ------------------------
ar.add_create_auth(auth_object, tmpl->to_xml(t64));
VirtualMachine::set_auth_request(att.uid, ar, ttmpl);
@ -111,6 +112,13 @@ bool VirtualMachineAllocate::allocate_authorization(
return false;
}
// -------------------------- Check Quotas ----------------------------
if ( quota_authorization(tmpl, att) == false )
{
return false;
}
return true;
}
@ -266,8 +274,17 @@ int VirtualMachineAllocate::pool_allocate(xmlrpc_c::paramList const& paramList,
VirtualMachineTemplate * ttmpl= static_cast<VirtualMachineTemplate *>(tmpl);
VirtualMachinePool * vmpool = static_cast<VirtualMachinePool *>(pool);
return vmpool->allocate(att.uid, att.gid, att.uname, att.gname, ttmpl, &id,
error_str, false);
Template tmpl_back(*tmpl);
int rc = vmpool->allocate(att.uid, att.gid, att.uname, att.gname, ttmpl, &id,
error_str, false);
if ( rc < 0 )
{
quota_rollback(&tmpl_back, att);
}
return rc;
}
@ -297,8 +314,14 @@ void ImageAllocate::request_execute(xmlrpc_c::paramList const& params,
RequestAttributes& att)
{
string error_str;
string size_str;
int size_mb;
istringstream iss;
string ds_name;
string ds_data;
int rc, id;
PoolObjectAuth ds_perms;
@ -309,9 +332,12 @@ void ImageAllocate::request_execute(xmlrpc_c::paramList const& params,
Nebula& nd = Nebula::instance();
DatastorePool * dspool = nd.get_dspool();
ImagePool * ipool = static_cast<ImagePool *>(pool);
ImagePool * ipool = static_cast<ImagePool *>(pool);
ImageManager * imagem = nd.get_imagem();
ImageTemplate * tmpl = new ImageTemplate;
Template img_usage;
Datastore * ds;
Image::DiskType ds_disk_type;
@ -359,13 +385,45 @@ void ImageAllocate::request_execute(xmlrpc_c::paramList const& params,
ds->unlock();
// --------------- Get the SIZE for the Image, (DS driver) -----------------
rc = imagem->stat_image(tmpl, ds_data, size_str);
if ( rc == -1 )
{
failure_response(INTERNAL,
request_error("Cannot determine Image SIZE", size_str),
att);
delete tmpl;
return;
}
iss.str(size_str);
iss >> size_mb;
if ( iss.fail() )
{
failure_response(INTERNAL,
request_error("Cannot parse SIZE", size_str),
att);
delete tmpl;
return;
}
tmpl->erase("SIZE");
tmpl->add("SIZE", size_str);
// ------------- Set authorization request for non-oneadmin's --------------
img_usage.add("DATASTORE", ds_id);
img_usage.add("SIZE", size_str);
if ( att.uid != 0 )
{
AuthRequest ar(att.uid, att.gid);
string tmpl_str = "";
string tmpl_str;
// ------------------ Check permissions and ACLs ----------------------
tmpl->to_xml(tmpl_str);
ar.add_create_auth(auth_object, tmpl_str); // CREATE IMAGE
@ -381,6 +439,14 @@ void ImageAllocate::request_execute(xmlrpc_c::paramList const& params,
delete tmpl;
return;
}
// -------------------------- Check Quotas ----------------------------
if ( quota_authorization(&img_usage, att) == false )
{
delete tmpl;
return;
}
}
rc = ipool->allocate(att.uid,
@ -396,6 +462,8 @@ void ImageAllocate::request_execute(xmlrpc_c::paramList const& params,
error_str);
if ( rc < 0 )
{
quota_rollback(&img_usage, att);
failure_response(INTERNAL, allocate_error(error_str), att);
return;
}
@ -455,9 +523,6 @@ int HostAllocate::pool_allocate(
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -23,6 +23,94 @@
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
PoolObjectSQL * RequestManagerChown::get_and_quota(
int oid,
int new_uid,
int new_gid,
RequestAttributes& att)
{
Template * tmpl;
int old_uid;
int old_gid;
PoolObjectSQL * object;
object = pool->get(oid,true);
if ( object == 0 )
{
failure_response(NO_EXISTS,
get_error(object_name(auth_object), oid),
att);
return 0;
}
if ( auth_object == PoolObjectSQL::VM )
{
tmpl = (static_cast<VirtualMachine*>(object))->clone_template();
}
else
{
Image * img = static_cast<Image *>(object);
tmpl = new Template;
tmpl->add("DATASTORE", img->get_ds_id());
tmpl->add("SIZE", img->get_size());
}
if ( new_uid == -1 )
{
old_uid = -1;
}
else
{
old_uid = object->get_uid();
}
if ( new_gid == -1 )
{
old_gid = -1;
}
else
{
old_gid = object->get_gid();
}
object->unlock();
RequestAttributes att_new(new_uid, new_gid, att);
RequestAttributes att_old(old_uid, old_gid, att);
if ( quota_authorization(tmpl, att_new) == false )
{
delete tmpl;
return 0;
}
quota_rollback(tmpl, att_old);
object = pool->get(oid,true);
if ( object == 0 )
{
quota_rollback(tmpl, att_new);
quota_authorization(tmpl, att_old);
failure_response(NO_EXISTS,
get_error(object_name(auth_object), oid),
att);
}
delete tmpl;
return object;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void RequestManagerChown::request_execute(xmlrpc_c::paramList const& paramList,
RequestAttributes& att)
{
@ -102,13 +190,27 @@ void RequestManagerChown::request_execute(xmlrpc_c::paramList const& paramList,
}
}
// ------------- Update the object ---------------------
// --------------- Update the object and check quotas ----------------------
object = pool->get(oid,true);
if ( auth_object == PoolObjectSQL::VM ||
auth_object == PoolObjectSQL::IMAGE )
{
object = get_and_quota(oid, noid, ngid, att);
}
else
{
object = pool->get(oid,true);
if ( object == 0 )
{
failure_response(NO_EXISTS,get_error(object_name(auth_object),oid),att);
if ( object == 0 )
{
failure_response(NO_EXISTS,
get_error(object_name(auth_object), oid),
att);
}
}
if ( object == 0 )
{
return;
}
@ -118,7 +220,6 @@ void RequestManagerChown::request_execute(xmlrpc_c::paramList const& paramList,
old_uid = object->get_uid();
object->set_user(noid,nuname);
}
if ( ngid != -1 )

View File

@ -0,0 +1,83 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#include "RequestManagerGroup.h"
using namespace std;
void GroupSetQuota::
request_execute(xmlrpc_c::paramList const& paramList,
RequestAttributes& att)
{
int id = xmlrpc_c::value_int(paramList.getInt(1));
string quota_str = xmlrpc_c::value_string(paramList.getString(2));
Group * group;
string error_str;
Template quota_tmpl;
int rc;
if ( id == GroupPool::ONEADMIN_ID )
{
failure_response(ACTION,
request_error("Cannot set quotas for oneadmin group",""),
att);
return;
}
if ( basic_authorization(id, att) == false )
{
return;
}
rc = quota_tmpl.parse_str_or_xml(quota_str, error_str);
if ( rc != 0 )
{
failure_response(ACTION, request_error(error_str,""), att);
return;
}
group = static_cast<Group *>(pool->get(id,true));
if ( group == 0 )
{
failure_response(NO_EXISTS,
get_error(object_name(auth_object),id),
att);
return;
}
group->quota.set(&quota_tmpl, error_str);
pool->update(group);
group->unlock();
if ( rc != 0 )
{
failure_response(ACTION, request_error(error_str,""), att);
}
else
{
success_response(id, att);
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -44,7 +44,7 @@ void RequestManagerUser::
if ( user_action(id,paramList,error_str) < 0 )
{
failure_response(INTERNAL, request_error(error_str,""), att);
failure_response(ACTION, request_error(error_str,""), att);
return;
}
@ -133,6 +133,45 @@ int UserChangeAuth::user_action(int user_id,
return rc;
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int UserSetQuota::user_action(int user_id,
xmlrpc_c::paramList const& paramList,
string& error_str)
{
string quota_str = xmlrpc_c::value_string(paramList.getString(2));
Template quota_tmpl;
int rc;
User * user;
if ( user_id == UserPool::ONEADMIN_ID )
{
error_str = "Cannot set quotas for oneadmin user";
return -1;
}
rc = quota_tmpl.parse_str_or_xml(quota_str, error_str);
if ( rc != 0 )
{
return -1;
}
user = static_cast<User *>(pool->get(user_id,true));
if ( user == 0 )
{
return -1;
}
rc = user->quota.set(&quota_tmpl, error_str);
pool->update(user);
user->unlock();
return rc;
}

View File

@ -98,8 +98,16 @@ void VMTemplateInstantiate::request_execute(xmlrpc_c::paramList const& paramList
delete tmpl;
return;
}
if ( quota_authorization(tmpl, att) == false )
{
delete tmpl;
return;
}
}
Template tmpl_back(*tmpl);
rc = vmpool->allocate(att.uid, att.gid, att.uname, att.gname, tmpl, &vid,
error_str, false);
@ -109,6 +117,8 @@ void VMTemplateInstantiate::request_execute(xmlrpc_c::paramList const& paramList
allocate_error(PoolObjectSQL::VM,error_str),
att);
quota_rollback(&tmpl_back, att);
return;
}

View File

@ -518,33 +518,32 @@ void VirtualMachineSaveDisk::request_execute(xmlrpc_c::paramList const& paramLis
// -------------------------------------------------------------------------
// Create a template for the new Image
// -------------------------------------------------------------------------
ImageTemplate * itemplate;
ostringstream oss;
ImageTemplate * itemplate = new ImageTemplate;
Template img_usage;
oss << "NAME = \"" << img_name << "\"" << endl;
oss << "SIZE = " << size << endl;
itemplate->add("NAME", img_name);
itemplate->add("SIZE", size);
oss << "SAVED_IMAGE_ID = " << iid_orig << endl;
oss << "SAVED_DISK_ID = " << disk_id << endl;
oss << "SAVED_VM_ID = " << id << endl;
itemplate->add("SAVED_IMAGE_ID",iid_orig);
itemplate->add("SAVED_DISK_ID",disk_id);
itemplate->add("SAVED_VM_ID", id);
if ( img_type.empty() )
{
oss << "TYPE = " << Image::type_to_str(type) << endl;
itemplate->add("TYPE", Image::type_to_str(type));
}
else
{
oss << "TYPE = " << img_type << endl;
itemplate->add("TYPE", img_type);
}
itemplate = new ImageTemplate;
itemplate->parse_str_or_xml(oss.str(), error_str);
itemplate->set_saving();
img_usage.add("SIZE", size);
img_usage.add("DATASTORE", ds_id);
// -------------------------------------------------------------------------
// Authorize the operation
// Authorize the operation & check quotas
// -------------------------------------------------------------------------
if ( vm_authorization(id, itemplate, att, 0, &ds_perms, auth_op) == false )
@ -553,6 +552,12 @@ void VirtualMachineSaveDisk::request_execute(xmlrpc_c::paramList const& paramLis
return;
}
if ( quota_authorization(&img_usage, PoolObjectSQL::IMAGE, att) == false )
{
delete itemplate;
return;
}
// -------------------------------------------------------------------------
// Create the image
// -------------------------------------------------------------------------
@ -570,6 +575,8 @@ void VirtualMachineSaveDisk::request_execute(xmlrpc_c::paramList const& paramLis
error_str);
if (rc < 0)
{
quota_rollback(&img_usage, PoolObjectSQL::IMAGE, att);
failure_response(INTERNAL,
allocate_error(PoolObjectSQL::IMAGE, error_str), att);
return;

View File

@ -33,6 +33,7 @@ source_files=[
'RequestManagerVMTemplate.cc',
'RequestManagerUpdateTemplate.cc',
'RequestManagerUser.cc',
'RequestManagerGroup.cc',
'RequestManagerHost.cc',
'RequestManagerImage.cc',
'RequestManagerChown.cc',

361
src/um/Quota.cc Normal file
View File

@ -0,0 +1,361 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#include "Quota.h"
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int Quota::get_quota(const string& id, VectorAttribute ** va)
{
map<string, Attribute *>::iterator it;
VectorAttribute * q;
istringstream iss(id);
int id_i;
*va = 0;
if ( id.empty() )
{
return -1;
}
iss >> id_i;
if (iss.fail() || !iss.eof())
{
return -1;
}
for ( it = attributes.begin(); it != attributes.end(); it++)
{
q = static_cast<VectorAttribute *>(it->second);
if (q->vector_value("ID") == id)
{
*va = q;
return 0;
}
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void Quota::add_to_quota(VectorAttribute * attr, const string& va_name, int num)
{
istringstream iss;
ostringstream oss;
float total;
iss.str(attr->vector_value(va_name.c_str()));
iss >> total;
total += num;
oss << total;
attr->replace(va_name, oss.str());
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int Quota::set(vector<Attribute*> * new_quotas, string& error)
{
vector<Attribute *>::iterator it;
VectorAttribute * iq;
VectorAttribute * tq;
string id;
for ( it = new_quotas->begin(); it != new_quotas->end(); it++)
{
iq = dynamic_cast<VectorAttribute *>(*it);
if ( iq == 0 )
{
goto error_limits;
}
id = iq->vector_value("ID");
if ( get_quota(id, &tq) == -1 )
{
goto error_limits;
}
if ( tq == 0 )
{
VectorAttribute * nq;
if ((nq = new_quota(iq)) == 0)
{
goto error_limits;
}
add(nq);
}
else
{
if (update_limits(tq, iq) != 0)
{
goto error_limits;
}
}
}
return 0;
error_limits:
ostringstream oss;
oss << "Negative limits or bad format in quota " << template_name;
if ( iq != 0 )
{
string * quota_str = iq->marshall(",");
oss << " = [ " << *quota_str << " ]";
delete quota_str;
}
error = oss.str();
return -1;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool Quota::check_quota(const string& qid,
map<string, int>& usage_req,
string& error)
{
VectorAttribute * q;
map<string, int>::iterator it;
bool check;
int limit;
int usage;
if ( get_quota(qid, &q) == -1 )
{
return false;
}
// -------------------------------------------------------------------------
// Quota does not exist, create a new one
// -------------------------------------------------------------------------
if ( q == 0 )
{
map<string, string> values;
for (int i=0; i < num_metrics; i++)
{
ostringstream usage_req_str;
string metrics_used = metrics[i];
metrics_used += "_USED";
it = usage_req.find(metrics[i]);
if (it == usage_req.end())
{
usage_req_str << "0";
}
else
{
usage_req_str << it->second;
}
values.insert(make_pair(metrics[i], "0"));
values.insert(make_pair(metrics_used, usage_req_str.str()));
}
if (!qid.empty())
{
values.insert(make_pair("ID", qid));
}
add(new VectorAttribute(template_name, values));
return true;
}
// -------------------------------------------------------------------------
// Check the quotas for each usage request
// -------------------------------------------------------------------------
for (int i=0; i < num_metrics; i++)
{
string metrics_used = metrics[i];
metrics_used += "_USED";
it = usage_req.find(metrics[i]);
if (it == usage_req.end())
{
continue;
}
q->vector_value(metrics[i], limit);
q->vector_value(metrics_used.c_str(), usage);
check = ( limit == 0 ) || ( ( usage + it->second ) <= limit );
if ( !check )
{
ostringstream oss;
oss << "Limit of " << limit << " reached for " << metrics[i]
<< " quota in " << template_name;
if ( !qid.empty() )
{
oss << " with ID: " << qid;
}
error = oss.str();
return false;
}
}
// -------------------------------------------------------------------------
// Add resource usage to quotas
// -------------------------------------------------------------------------
for (int i=0; i < num_metrics; i++)
{
string metrics_used = metrics[i];
metrics_used += "_USED";
it = usage_req.find(metrics[i]);
if (it == usage_req.end())
{
continue;
}
add_to_quota(q, metrics_used, it->second);
}
return true;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void Quota::del_quota(const string& qid, map<string, int>& usage_req)
{
VectorAttribute * q;
map<string, int>::iterator it;
if ( get_quota(qid, &q) == -1)
{
return;
}
if ( q == 0 )
{
return;
}
for (int i=0; i < num_metrics; i++)
{
string metrics_used = metrics[i];
metrics_used += "_USED";
it = usage_req.find(metrics[i]);
if (it == usage_req.end())
{
continue;
}
add_to_quota(q, metrics_used, -it->second);
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int Quota::update_limits(VectorAttribute * quota, const VectorAttribute * va)
{
string limit;
int limit_i;
for (int i=0; i < num_metrics; i++)
{
limit = va->vector_value_str(metrics[i], limit_i);
if ( limit_i < 0 ) //No quota, NaN or negative
{
return -1;
}
else
{
quota->replace(metrics[i], limit);
}
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
VectorAttribute * Quota::new_quota(VectorAttribute * va)
{
map<string,string> limits;
string limit;
int limit_i;
for (int i=0; i < num_metrics; i++)
{
string metrics_used = metrics[i];
metrics_used += "_USED";
limit = va->vector_value_str(metrics[i], limit_i);
if ( limit_i < 0 ) //No quota, NaN or negative
{
limit = "0";
}
limits.insert(make_pair(metrics[i], limit));
limits.insert(make_pair(metrics_used, "0"));
}
string id = va->vector_value("ID");
if ( !id.empty() )
{
limits.insert(make_pair("ID", id));
}
return new VectorAttribute(template_name,limits);
}

85
src/um/QuotaDatastore.cc Normal file
View File

@ -0,0 +1,85 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#include "QuotaDatastore.h"
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
const char * QuotaDatastore::DS_METRICS[] = {"SIZE", "IMAGES"};
const int QuotaDatastore::NUM_DS_METRICS = 2;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool QuotaDatastore::check(Template * tmpl, string& error)
{
map<string, int> ds_request;
string ds_id;
int size;
tmpl->get("DATASTORE", ds_id);
if ( ds_id.empty() )
{
error = "Datastore not defined for image";
return false;
}
if ( tmpl->get("SIZE", size) == false )
{
error = "Size not defined for image";
return false;
}
ds_request.insert(make_pair("IMAGES",1));
ds_request.insert(make_pair("SIZE", size));
return check_quota(ds_id, ds_request, error);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void QuotaDatastore::del(Template * tmpl)
{
map<string, int> ds_request;
string ds_id;
int size;
tmpl->get("DATASTORE", ds_id);
if ( ds_id.empty() )
{
return;
}
if ( tmpl->get("SIZE", size) == false )
{
return;
}
ds_request.insert(make_pair("IMAGES",1));
ds_request.insert(make_pair("SIZE", size));
del_quota(ds_id, ds_request);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

97
src/um/QuotaImage.cc Normal file
View File

@ -0,0 +1,97 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#include "QuotaImage.h"
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
const char * QuotaImage::IMAGE_METRICS[] = {"RVMS"};
const int QuotaImage::NUM_IMAGE_METRICS = 1;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool QuotaImage::check(Template * tmpl, string& error)
{
vector<Attribute*> disks;
VectorAttribute * disk;
string image_id;
int num;
map<string, int> image_request;
image_request.insert(make_pair("RVMS",1));
num = tmpl->get("DISK", disks);
for (int i = 0 ; i < num ; i++)
{
disk = dynamic_cast<VectorAttribute *>(disks[i]);
if ( disk == 0 )
{
continue;
}
image_id = disk->vector_value("IMAGE_ID");
if ( !check_quota(image_id, image_request, error) )
{
return false;
}
}
return true;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void QuotaImage::del(Template * tmpl)
{
vector<Attribute*> disks;
VectorAttribute * disk;
string image_id;
int num;
map<string, int> image_request;
image_request.insert(make_pair("RVMS",1));
num = tmpl->get("DISK", disks);
for (int i = 0 ; i < num ; i++)
{
disk = dynamic_cast<VectorAttribute *>(disks[i]);
if ( disk == 0 )
{
continue;
}
image_id = disk->vector_value("IMAGE_ID");
del_quota(image_id, image_request);
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

97
src/um/QuotaNetwork.cc Normal file
View File

@ -0,0 +1,97 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#include "QuotaNetwork.h"
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
const char * QuotaNetwork::NET_METRICS[] = {"LEASES"};
const int QuotaNetwork::NUM_NET_METRICS = 1;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool QuotaNetwork::check(Template * tmpl, string& error)
{
vector<Attribute*> nics;
VectorAttribute * nic;
string net_id;
int num;
map<string, int> net_request;
net_request.insert(make_pair("LEASES",1));
num = tmpl->get("NIC", nics);
for (int i = 0 ; i < num ; i++)
{
nic = dynamic_cast<VectorAttribute *>(nics[i]);
if ( nic == 0 )
{
continue;
}
net_id = nic->vector_value("NETWORK_ID");
if ( !check_quota(net_id, net_request, error) )
{
return false;
}
}
return true;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void QuotaNetwork::del(Template * tmpl)
{
vector<Attribute*> nics;
VectorAttribute * nic;
string net_id;
int num;
map<string, int> net_request;
net_request.insert(make_pair("LEASES",1));
num = tmpl->get("NIC", nics);
for (int i = 0 ; i < num ; i++)
{
nic = dynamic_cast<VectorAttribute *>(nics[i]);
if ( nic == 0 )
{
continue;
}
net_id = nic->vector_value("NETWORK_ID");
del_quota(net_id, net_request);
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -0,0 +1,105 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2012, OpenNebula Project Leads (OpenNebula.org) */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#include "QuotaVirtualMachine.h"
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
const char * QuotaVirtualMachine::VM_METRICS[] = {"VMS", "CPU", "MEMORY"};
const int QuotaVirtualMachine::NUM_VM_METRICS = 3;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int QuotaVirtualMachine::get_quota(const string& id, VectorAttribute **va)
{
vector<Attribute*> values;
int num;
*va = 0;
num = get(template_name, values);
if ( num == 0 )
{
return 0;
}
*va = dynamic_cast<VectorAttribute *>(values[0]);
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool QuotaVirtualMachine::check(Template * tmpl, string& error)
{
map<string, int> vm_request;
int memory;
int cpu;
if ( tmpl->get("MEMORY", memory) == false )
{
error = "MEMORY not defined for VM";
return false;
}
if ( tmpl->get("CPU", cpu) == false )
{
error = "CPU not defined for VM";
return false;
}
vm_request.insert(make_pair("VMS",1));
vm_request.insert(make_pair("MEMORY", memory));
vm_request.insert(make_pair("CPU", cpu));
return check_quota("", vm_request, error);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void QuotaVirtualMachine::del(Template * tmpl)
{
map<string, int> vm_request;
int memory;
int cpu;
if ( tmpl->get("MEMORY", memory) == false )
{
return;
}
if ( tmpl->get("CPU", cpu) == false )
{
return;
}
vm_request.insert(make_pair("VMS",1));
vm_request.insert(make_pair("MEMORY", memory));
vm_request.insert(make_pair("CPU", cpu));
del_quota("", vm_request);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -23,7 +23,12 @@ lib_name='nebula_um'
# Sources to generate the library
source_files=[
'User.cc',
'UserPool.cc'
'UserPool.cc',
'Quota.cc',
'QuotaDatastore.cc',
'QuotaNetwork.cc',
'QuotaVirtualMachine.cc',
'QuotaImage.cc'
]
# Build library

View File

@ -136,8 +136,10 @@ error_common:
string& User::to_xml(string& xml) const
{
ostringstream oss;
string template_xml;
ostringstream oss;
string template_xml;
string quota_xml;
int enabled_int = enabled?1:0;
@ -151,6 +153,7 @@ string& User::to_xml(string& xml) const
"<AUTH_DRIVER>" << auth_driver <<"</AUTH_DRIVER>"<<
"<ENABLED>" << enabled_int <<"</ENABLED>" <<
obj_template->to_xml(template_xml) <<
quota.to_xml(quota_xml) <<
"</USER>";
xml = oss.str();
@ -194,6 +197,8 @@ int User::from_xml(const string& xml)
rc += obj_template->from_xml_node(content[0]);
ObjectXML::free_nodes(content);
rc += quota.from_xml(this);
if (rc != 0)
{

View File

@ -762,4 +762,3 @@ int UserPool::authorize(AuthRequest& ar)
return rc;
}

View File

@ -212,8 +212,8 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
int rc;
string name;
string value;
ostringstream oss;
string value;
ostringstream oss;
// ------------------------------------------------------------------------
// Set a name if the VM has not got one and VM_ID
@ -241,6 +241,24 @@ int VirtualMachine::insert(SqlDB * db, string& error_str)
this->name = name;
// ------------------------------------------------------------------------
// Check for CPU and MEMORY attributes
// ------------------------------------------------------------------------
get_template_attribute("MEMORY", value);
if ( value.empty())
{
goto error_no_memory;
}
get_template_attribute("CPU", value);
if ( value.empty())
{
goto error_no_cpu;
}
// ------------------------------------------------------------------------
// Get network leases
// ------------------------------------------------------------------------
@ -321,9 +339,16 @@ error_leases_rollback:
release_network_leases();
goto error_common;
error_no_cpu:
error_str = "CPU attribute missing.";
goto error_common;
error_no_memory:
error_str = "MEMORY attribute missing.";
goto error_common;
error_name_length:
oss << "NAME is too long; max length is 128 chars.";
error_str = oss.str();
error_str = "NAME is too long; max length is 128 chars.";
goto error_common;
error_common:

Some files were not shown because too many files have changed in this diff Show More