mirror of
https://github.com/OpenNebula/one.git
synced 2025-01-08 21:17:43 +03:00
Feature #3175: New Security Group pool in the core
This commit is contained in:
parent
ffd3f1e99f
commit
00990b33a1
@ -82,6 +82,7 @@ main_env.Append(LIBPATH=[
|
||||
cwd+'/src/document',
|
||||
cwd+'/src/zone',
|
||||
cwd+'/src/client',
|
||||
cwd+'/src/secgroup',
|
||||
])
|
||||
|
||||
# Compile flags
|
||||
@ -237,6 +238,7 @@ build_scripts=[
|
||||
'src/xml/SConstruct',
|
||||
'src/document/SConstruct',
|
||||
'src/zone/SConstruct',
|
||||
'src/secgroup/SConstruct',
|
||||
'share/man/SConstruct',
|
||||
'src/sunstone/locale/languages/SConstruct',
|
||||
'share/rubygems/SConstruct',
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "ClusterPool.h"
|
||||
#include "DocumentPool.h"
|
||||
#include "ZonePool.h"
|
||||
#include "SecurityGroupPool.h"
|
||||
|
||||
#include "VirtualMachineManager.h"
|
||||
#include "LifeCycleManager.h"
|
||||
@ -124,6 +125,11 @@ public:
|
||||
return zonepool;
|
||||
};
|
||||
|
||||
SecurityGroupPool * get_secgrouppool()
|
||||
{
|
||||
return secgrouppool;
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------
|
||||
// Manager Accessors
|
||||
// --------------------------------------------------------------
|
||||
@ -646,7 +652,7 @@ private:
|
||||
"/DEFAULT_GROUP_QUOTAS/VM_QUOTA"),
|
||||
system_db(0), db(0),
|
||||
vmpool(0), hpool(0), vnpool(0), upool(0), ipool(0), gpool(0), tpool(0),
|
||||
dspool(0), clpool(0), docpool(0), zonepool(0),
|
||||
dspool(0), clpool(0), docpool(0), zonepool(0), secgrouppool(0),
|
||||
lcm(0), vmm(0), im(0), tm(0), dm(0), rm(0), hm(0), authm(0),
|
||||
aclm(0), imagem(0)
|
||||
{
|
||||
@ -694,6 +700,7 @@ private:
|
||||
delete clpool;
|
||||
delete docpool;
|
||||
delete zonepool;
|
||||
delete secgrouppool;
|
||||
delete vmm;
|
||||
delete lcm;
|
||||
delete im;
|
||||
@ -771,6 +778,7 @@ private:
|
||||
ClusterPool * clpool;
|
||||
DocumentPool * docpool;
|
||||
ZonePool * zonepool;
|
||||
SecurityGroupPool * secgrouppool;
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Nebula Managers
|
||||
|
@ -60,7 +60,8 @@ public:
|
||||
DATASTORE = 0x0000100000000000LL,
|
||||
CLUSTER = 0x0000200000000000LL,
|
||||
DOCUMENT = 0x0000400000000000LL,
|
||||
ZONE = 0x0000800000000000LL
|
||||
ZONE = 0x0000800000000000LL,
|
||||
SECGROUP = 0x0001000000000000LL
|
||||
};
|
||||
|
||||
static string type_to_str(ObjectType ob)
|
||||
@ -79,6 +80,7 @@ public:
|
||||
case CLUSTER: return "CLUSTER" ; break;
|
||||
case DOCUMENT: return "DOCUMENT" ; break;
|
||||
case ZONE: return "ZONE" ; break;
|
||||
case SECGROUP: return "SECGROUP" ; break;
|
||||
default: return "";
|
||||
}
|
||||
};
|
||||
|
@ -512,6 +512,39 @@ public:
|
||||
RequestAttributes& att);
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
class SecurityGroupAllocate : public RequestManagerAllocate
|
||||
{
|
||||
public:
|
||||
SecurityGroupAllocate():
|
||||
RequestManagerAllocate("SecurityGroupAllocate",
|
||||
"Allocates a new security group",
|
||||
"A:ss",
|
||||
true)
|
||||
{
|
||||
Nebula& nd = Nebula::instance();
|
||||
pool = nd.get_secgrouppool();
|
||||
auth_object = PoolObjectSQL::SECGROUP;
|
||||
};
|
||||
|
||||
~SecurityGroupAllocate(){};
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
Template * get_object_template()
|
||||
{
|
||||
return new Template;
|
||||
};
|
||||
|
||||
int pool_allocate(xmlrpc_c::paramList const& _paramList,
|
||||
Template * tmpl,
|
||||
int& id,
|
||||
string& error_str,
|
||||
RequestAttributes& att);
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
@ -152,6 +152,25 @@ public:
|
||||
~DocumentChmod(){};
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
class SecurityGroupChmod: public RequestManagerChmod
|
||||
{
|
||||
public:
|
||||
SecurityGroupChmod():
|
||||
RequestManagerChmod("SecurityGroupChmod",
|
||||
"Changes permission bits of a security group")
|
||||
{
|
||||
Nebula& nd = Nebula::instance();
|
||||
pool = nd.get_secgrouppool();
|
||||
auth_object = PoolObjectSQL::SECGROUP;
|
||||
};
|
||||
|
||||
~SecurityGroupChmod(){};
|
||||
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
@ -246,6 +246,28 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
class SecurityGroupChown: public RequestManagerChown
|
||||
{
|
||||
public:
|
||||
SecurityGroupChown():
|
||||
RequestManagerChown("SecurityGroupChown",
|
||||
"Changes ownership of a security group")
|
||||
{
|
||||
Nebula& nd = Nebula::instance();
|
||||
pool = nd.get_secgrouppool();
|
||||
auth_object = PoolObjectSQL::SECGROUP;
|
||||
};
|
||||
|
||||
~SecurityGroupChown(){};
|
||||
|
||||
PoolObjectSQL * get(const string& name, int uid, bool lock)
|
||||
{
|
||||
return static_cast<SecurityGroupPool*>(pool)->get(name, uid, lock);
|
||||
};
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
@ -137,6 +137,45 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
class SecurityGroupClone : public RequestManagerClone
|
||||
{
|
||||
public:
|
||||
SecurityGroupClone():
|
||||
RequestManagerClone("SecurityGroupClone",
|
||||
"Clone an existing security group")
|
||||
{
|
||||
Nebula& nd = Nebula::instance();
|
||||
pool = nd.get_secgrouppool();
|
||||
|
||||
auth_object = PoolObjectSQL::SECGROUP;
|
||||
auth_op = AuthRequest::USE;
|
||||
};
|
||||
|
||||
~SecurityGroupClone(){};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
Template * clone_template(PoolObjectSQL* obj)
|
||||
{
|
||||
return static_cast<SecurityGroup*>(obj)->clone_template();
|
||||
};
|
||||
|
||||
int pool_allocate(
|
||||
int source_id,
|
||||
Template * tmpl,
|
||||
int& id,
|
||||
string& error_str,
|
||||
RequestAttributes& att)
|
||||
{
|
||||
SecurityGroupPool * secgrouppool = static_cast<SecurityGroupPool *>(pool);
|
||||
|
||||
return secgrouppool->allocate(att.uid, att.gid, att.uname, att.gname,
|
||||
att.umask, tmpl, &id, error_str);
|
||||
};
|
||||
};
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
@ -316,6 +316,24 @@ public:
|
||||
int drop(int oid, PoolObjectSQL * object, string& error_msg);
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
class SecurityGroupDelete : public RequestManagerDelete
|
||||
{
|
||||
public:
|
||||
SecurityGroupDelete():
|
||||
RequestManagerDelete("SecurityGroupDelete",
|
||||
"Deletes a security group")
|
||||
{
|
||||
Nebula& nd = Nebula::instance();
|
||||
pool = nd.get_secgrouppool();
|
||||
auth_object = PoolObjectSQL::SECGROUP;
|
||||
};
|
||||
|
||||
~SecurityGroupDelete(){};
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
@ -283,6 +283,24 @@ public:
|
||||
~ZoneInfo(){};
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
class SecurityGroupInfo : public RequestManagerInfo
|
||||
{
|
||||
public:
|
||||
SecurityGroupInfo():
|
||||
RequestManagerInfo("SecurityGroupInfo",
|
||||
"Returns security group information")
|
||||
{
|
||||
Nebula& nd = Nebula::instance();
|
||||
pool = nd.get_secgrouppool();
|
||||
auth_object = PoolObjectSQL::SECGROUP;
|
||||
};
|
||||
|
||||
~SecurityGroupInfo(){};
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
@ -404,6 +404,25 @@ public:
|
||||
xmlrpc_c::paramList const& paramList, RequestAttributes& att);
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
class SecurityGroupPoolInfo : public RequestManagerPoolInfoFilter
|
||||
{
|
||||
public:
|
||||
SecurityGroupPoolInfo():
|
||||
RequestManagerPoolInfoFilter("SecurityGroupPoolInfo",
|
||||
"Returns the security group pool",
|
||||
"A:siii")
|
||||
{
|
||||
Nebula& nd = Nebula::instance();
|
||||
pool = nd.get_secgrouppool();
|
||||
auth_object = PoolObjectSQL::SECGROUP;
|
||||
};
|
||||
|
||||
~SecurityGroupPoolInfo(){};
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
@ -295,6 +295,28 @@ public:
|
||||
~ZoneRename(){};
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
class SecurityGroupRename: public RequestManagerRename
|
||||
{
|
||||
public:
|
||||
SecurityGroupRename():
|
||||
RequestManagerRename("SecurityGroupRename", "Renames a security group")
|
||||
{
|
||||
Nebula& nd = Nebula::instance();
|
||||
pool = nd.get_secgrouppool();
|
||||
auth_object = PoolObjectSQL::SECGROUP;
|
||||
};
|
||||
|
||||
~SecurityGroupRename(){};
|
||||
|
||||
PoolObjectSQL * get(const string& name, int uid, bool lock)
|
||||
{
|
||||
return static_cast<SecurityGroupPool*>(pool)->get(name, uid, lock);
|
||||
};
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
@ -258,6 +258,24 @@ public:
|
||||
~GroupUpdateTemplate(){};
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
class SecurityGroupUpdateTemplate : public RequestManagerUpdateTemplate
|
||||
{
|
||||
public:
|
||||
SecurityGroupUpdateTemplate():
|
||||
RequestManagerUpdateTemplate("SecurityGroupUpdateTemplate",
|
||||
"Updates a security group template")
|
||||
{
|
||||
Nebula& nd = Nebula::instance();
|
||||
pool = nd.get_secgrouppool();
|
||||
auth_object = PoolObjectSQL::SECGROUP;
|
||||
};
|
||||
|
||||
~SecurityGroupUpdateTemplate(){};
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
133
include/SecurityGroup.h
Normal file
133
include/SecurityGroup.h
Normal file
@ -0,0 +1,133 @@
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs */
|
||||
/* */
|
||||
/* 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 SECURITYGROUP_H_
|
||||
#define SECURITYGROUP_H_
|
||||
|
||||
#include "PoolObjectSQL.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
* The SecurityGroup class.
|
||||
*/
|
||||
class SecurityGroup : public PoolObjectSQL
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Function to print the SecurityGroup object into a string in XML format
|
||||
* @param xml the resulting XML string
|
||||
* @return a reference to the generated string
|
||||
*/
|
||||
string& to_xml(string& xml) const;
|
||||
|
||||
/**
|
||||
* Rebuilds the object from an xml formatted string
|
||||
* @param xml_str The xml-formatted string
|
||||
*
|
||||
* @return 0 on success, -1 otherwise
|
||||
*/
|
||||
int from_xml(const string &xml_str);
|
||||
|
||||
/**
|
||||
* Returns a copy of the Template
|
||||
* @return A copy of the Template
|
||||
*/
|
||||
Template * clone_template() const
|
||||
{
|
||||
return new Template(obj_template);
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Friends
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
friend class SecurityGroupPool;
|
||||
|
||||
// *************************************************************************
|
||||
// Constructor
|
||||
// *************************************************************************
|
||||
|
||||
SecurityGroup( int _uid,
|
||||
int _gid,
|
||||
const string& _uname,
|
||||
const string& _gname,
|
||||
int _umask,
|
||||
Template* sgroup_template);
|
||||
|
||||
~SecurityGroup();
|
||||
|
||||
// *************************************************************************
|
||||
// DataBase implementation (Private)
|
||||
// *************************************************************************
|
||||
|
||||
static const char * db_names;
|
||||
|
||||
static const char * db_bootstrap;
|
||||
|
||||
static const char * table;
|
||||
|
||||
/**
|
||||
* Execute an INSERT or REPLACE Sql query.
|
||||
* @param db The SQL DB
|
||||
* @param replace Execute an INSERT or a REPLACE
|
||||
* @param error_str Returns the error reason, if any
|
||||
* @return 0 one success
|
||||
*/
|
||||
int insert_replace(SqlDB *db, bool replace, string& error_str);
|
||||
|
||||
/**
|
||||
* Bootstraps the database table(s) associated to the SecurityGroup
|
||||
* @return 0 on success
|
||||
*/
|
||||
static int bootstrap(SqlDB * db)
|
||||
{
|
||||
ostringstream oss(SecurityGroup::db_bootstrap);
|
||||
|
||||
return db->exec(oss);
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes the SecurityGroup in the database.
|
||||
* @param db pointer to the db
|
||||
* @return 0 on success
|
||||
*/
|
||||
int insert(SqlDB *db, string& error_str);
|
||||
|
||||
/**
|
||||
* Writes/updates the SecurityGroup's data fields in the database.
|
||||
* @param db pointer to the db
|
||||
* @return 0 on success
|
||||
*/
|
||||
int update(SqlDB *db)
|
||||
{
|
||||
string error_str;
|
||||
return insert_replace(db, true, error_str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for SecurityGroup templates
|
||||
*/
|
||||
Template * get_new_template() const
|
||||
{
|
||||
return new Template;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /*SECURITYGROUP_H_*/
|
130
include/SecurityGroupPool.h
Normal file
130
include/SecurityGroupPool.h
Normal file
@ -0,0 +1,130 @@
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs */
|
||||
/* */
|
||||
/* 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 SECURITYGROUP_POOL_H_
|
||||
#define SECURITYGROUP_POOL_H_
|
||||
|
||||
#include "PoolSQL.h"
|
||||
#include "SecurityGroup.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
class SecurityGroupPool : public PoolSQL
|
||||
{
|
||||
public:
|
||||
SecurityGroupPool(SqlDB * db);
|
||||
|
||||
~SecurityGroupPool(){};
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* Methods for DB management */
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Allocates a new SecurityGroup, writing it in the pool database. No memory is
|
||||
* allocated for the object.
|
||||
*
|
||||
* @param uid user identifier
|
||||
* @param gid the id of the group this object is assigned to
|
||||
* @param uname user name
|
||||
* @param gname group name
|
||||
* @param umask permissions umask
|
||||
* @param sgroup_template a Template object
|
||||
* @param oid the id assigned to the SecurityGroup
|
||||
* @param error_str Returns the error reason, if any
|
||||
*
|
||||
* @return the oid assigned to the object, -1 in case of failure
|
||||
* @return
|
||||
*/
|
||||
int allocate(
|
||||
int uid,
|
||||
int gid,
|
||||
const string& uname,
|
||||
const string& gname,
|
||||
int umask,
|
||||
Template * sgroup_template,
|
||||
int * oid,
|
||||
string& error_str);
|
||||
|
||||
/**
|
||||
* Function to get a SecurityGroup from the pool, if the object is not in memory
|
||||
* it is loaded from the DB
|
||||
* @param oid SecurityGroup unique id
|
||||
* @param lock locks the SecurityGroup mutex
|
||||
* @return a pointer to the SecurityGroup, 0 if the SecurityGroup could not be loaded
|
||||
*/
|
||||
SecurityGroup * get(int oid, bool lock)
|
||||
{
|
||||
return static_cast<SecurityGroup *>(PoolSQL::get(oid,lock));
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets an object from the pool (if needed the object is loaded from the
|
||||
* database).
|
||||
* @param name of the object
|
||||
* @param uid id of owner
|
||||
* @param lock locks the object if true
|
||||
*
|
||||
* @return a pointer to the object, 0 in case of failure
|
||||
*/
|
||||
SecurityGroup * get(const string& name, int uid, bool lock)
|
||||
{
|
||||
return static_cast<SecurityGroup *>(PoolSQL::get(name,uid,lock));
|
||||
};
|
||||
|
||||
/** Update a particular SecurityGroup
|
||||
* @param securitygroup pointer to SecurityGroup
|
||||
* @return 0 on success
|
||||
*/
|
||||
int update(SecurityGroup * securitygroup);
|
||||
|
||||
/**
|
||||
* Bootstraps the database table(s) associated to the SecurityGroup pool
|
||||
* @return 0 on success
|
||||
*/
|
||||
static int bootstrap(SqlDB * _db)
|
||||
{
|
||||
return SecurityGroup::bootstrap(_db);
|
||||
};
|
||||
|
||||
/**
|
||||
* Dumps the SecurityGroup pool in XML format. A filter can be also added to the
|
||||
* query
|
||||
* @param oss the output stream to dump the pool contents
|
||||
* @param where filter for the objects, defaults to all
|
||||
* @param limit parameters used for pagination
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
int dump(ostringstream& oss, const string& where, const string& limit)
|
||||
{
|
||||
return PoolSQL::dump(oss, "SECURITY_GROUP_POOL", SecurityGroup::table, where, limit);
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Factory method to produce objects
|
||||
* @return a pointer to the new object
|
||||
*/
|
||||
PoolObjectSQL * create()
|
||||
{
|
||||
return new SecurityGroup(-1,-1,"","",0,0);
|
||||
};
|
||||
};
|
||||
|
||||
#endif /*SECURITYGROUP_POOL_H_*/
|
@ -28,7 +28,7 @@ const long long AclRule::CLUSTER_ID = 0x0000000800000000LL;
|
||||
|
||||
const long long AclRule::NONE_ID = 0x1000000000000000LL;
|
||||
|
||||
const int AclRule::num_pool_objects = 11;
|
||||
const int AclRule::num_pool_objects = 12;
|
||||
const PoolObjectSQL::ObjectType AclRule::pool_objects[] = {
|
||||
PoolObjectSQL::VM,
|
||||
PoolObjectSQL::HOST,
|
||||
@ -40,7 +40,8 @@ const PoolObjectSQL::ObjectType AclRule::pool_objects[] = {
|
||||
PoolObjectSQL::DATASTORE,
|
||||
PoolObjectSQL::CLUSTER,
|
||||
PoolObjectSQL::DOCUMENT,
|
||||
PoolObjectSQL::ZONE
|
||||
PoolObjectSQL::ZONE,
|
||||
PoolObjectSQL::SECGROUP
|
||||
};
|
||||
|
||||
const int AclRule::num_auth_operations = 4;
|
||||
@ -54,7 +55,8 @@ const AuthRequest::Operation AclRule::auth_operations[] = {
|
||||
const long long AclRule::INVALID_CLUSTER_OBJECTS =
|
||||
PoolObjectSQL::VM | PoolObjectSQL::IMAGE | PoolObjectSQL::USER |
|
||||
PoolObjectSQL::TEMPLATE | PoolObjectSQL::GROUP | PoolObjectSQL::ACL |
|
||||
PoolObjectSQL::CLUSTER | PoolObjectSQL::DOCUMENT | PoolObjectSQL::ZONE;
|
||||
PoolObjectSQL::CLUSTER | PoolObjectSQL::DOCUMENT | PoolObjectSQL::ZONE |
|
||||
PoolObjectSQL::SECGROUP;
|
||||
|
||||
const long long AclRule::INVALID_GROUP_OBJECTS =
|
||||
PoolObjectSQL::HOST | PoolObjectSQL::GROUP | PoolObjectSQL::CLUSTER |
|
||||
@ -218,7 +220,7 @@ bool AclRule::malformed(string& error_str) const
|
||||
oss << "when using the ALL bit, [resource] ID must be 0";
|
||||
}
|
||||
|
||||
if ( (resource & 0xFFF000000000LL) == 0 )
|
||||
if ( (resource & 0xFFFF000000000LL) == 0 )
|
||||
{
|
||||
if ( error )
|
||||
{
|
||||
@ -229,7 +231,7 @@ bool AclRule::malformed(string& error_str) const
|
||||
oss << "[resource] type is missing";
|
||||
}
|
||||
|
||||
if ( (resource & 0xFFFF000000000000LL) != 0 )
|
||||
if ( (resource & 0xFFFE000000000000LL) != 0 )
|
||||
{
|
||||
if ( error )
|
||||
{
|
||||
|
@ -334,6 +334,7 @@ void Nebula::start(bool bootstrap_only)
|
||||
rc += DocumentPool::bootstrap(db);
|
||||
rc += UserQuotas::bootstrap(db);
|
||||
rc += GroupQuotas::bootstrap(db);
|
||||
rc += SecurityGroupPool::bootstrap(db);
|
||||
|
||||
// Create the system tables only if bootstrap went well
|
||||
if (rc == 0)
|
||||
@ -471,6 +472,7 @@ void Nebula::start(bool bootstrap_only)
|
||||
clpool = new ClusterPool(db);
|
||||
docpool = new DocumentPool(db);
|
||||
zonepool= new ZonePool(db, is_federation_slave());
|
||||
secgrouppool = new SecurityGroupPool(db);
|
||||
|
||||
nebula_configuration->get("VM_HOOK", vm_hooks);
|
||||
nebula_configuration->get("HOST_HOOK", host_hooks);
|
||||
|
@ -62,6 +62,7 @@ env.Prepend(LIBS=[
|
||||
'nebula_log',
|
||||
'nebula_client',
|
||||
'nebula_xml',
|
||||
'nebula_secgroup',
|
||||
'crypto',
|
||||
'xml2'
|
||||
])
|
||||
|
@ -556,6 +556,8 @@ string Request::object_name(PoolObjectSQL::ObjectType ob)
|
||||
return "document";
|
||||
case PoolObjectSQL::ZONE:
|
||||
return "zone";
|
||||
case PoolObjectSQL::SECGROUP:
|
||||
return "security group";
|
||||
default:
|
||||
return "-";
|
||||
}
|
||||
|
@ -293,6 +293,7 @@ void RequestManager::register_xml_methods()
|
||||
xmlrpc_c::methodPtr datastore_update(new DatastoreUpdateTemplate());
|
||||
xmlrpc_c::methodPtr doc_update(new DocumentUpdateTemplate());
|
||||
xmlrpc_c::methodPtr cluster_update(new ClusterUpdateTemplate());
|
||||
xmlrpc_c::methodPtr secg_update(new SecurityGroupUpdateTemplate());
|
||||
|
||||
// Allocate Methods
|
||||
xmlrpc_c::methodPtr vm_allocate(new VirtualMachineAllocate());
|
||||
@ -303,10 +304,12 @@ void RequestManager::register_xml_methods()
|
||||
xmlrpc_c::methodPtr datastore_allocate(new DatastoreAllocate());
|
||||
xmlrpc_c::methodPtr cluster_allocate(new ClusterAllocate());
|
||||
xmlrpc_c::methodPtr doc_allocate(new DocumentAllocate());
|
||||
xmlrpc_c::methodPtr secg_allocate(new SecurityGroupAllocate());
|
||||
|
||||
// Clone Methods
|
||||
xmlrpc_c::methodPtr template_clone(new VMTemplateClone());
|
||||
xmlrpc_c::methodPtr doc_clone(new DocumentClone());
|
||||
xmlrpc_c::methodPtr secg_clone(new SecurityGroupClone());
|
||||
|
||||
// Delete Methods
|
||||
xmlrpc_c::methodPtr host_delete(new HostDelete());
|
||||
@ -316,6 +319,7 @@ void RequestManager::register_xml_methods()
|
||||
xmlrpc_c::methodPtr datastore_delete(new DatastoreDelete());
|
||||
xmlrpc_c::methodPtr cluster_delete(new ClusterDelete());
|
||||
xmlrpc_c::methodPtr doc_delete(new DocumentDelete());
|
||||
xmlrpc_c::methodPtr secg_delete(new SecurityGroupDelete());
|
||||
|
||||
// Info Methods
|
||||
xmlrpc_c::methodPtr vm_info(new VirtualMachineInfo());
|
||||
@ -326,6 +330,7 @@ void RequestManager::register_xml_methods()
|
||||
xmlrpc_c::methodPtr datastore_info(new DatastoreInfo());
|
||||
xmlrpc_c::methodPtr cluster_info(new ClusterInfo());
|
||||
xmlrpc_c::methodPtr doc_info(new DocumentInfo());
|
||||
xmlrpc_c::methodPtr secg_info(new SecurityGroupInfo());
|
||||
|
||||
// PoolInfo Methods
|
||||
xmlrpc_c::methodPtr hostpool_info(new HostPoolInfo());
|
||||
@ -336,6 +341,7 @@ void RequestManager::register_xml_methods()
|
||||
xmlrpc_c::methodPtr imagepool_info(new ImagePoolInfo());
|
||||
xmlrpc_c::methodPtr clusterpool_info(new ClusterPoolInfo());
|
||||
xmlrpc_c::methodPtr docpool_info(new DocumentPoolInfo());
|
||||
xmlrpc_c::methodPtr secgpool_info(new SecurityGroupPoolInfo());
|
||||
|
||||
// Host Methods
|
||||
xmlrpc_c::methodPtr host_enable(new HostEnable());
|
||||
@ -355,6 +361,7 @@ void RequestManager::register_xml_methods()
|
||||
xmlrpc_c::methodPtr image_chown(new ImageChown());
|
||||
xmlrpc_c::methodPtr datastore_chown(new DatastoreChown());
|
||||
xmlrpc_c::methodPtr doc_chown(new DocumentChown());
|
||||
xmlrpc_c::methodPtr secg_chown(new SecurityGroupChown());
|
||||
|
||||
// Chmod Methods
|
||||
xmlrpc_c::methodPtr vm_chmod(new VirtualMachineChmod());
|
||||
@ -363,6 +370,7 @@ void RequestManager::register_xml_methods()
|
||||
xmlrpc_c::methodPtr image_chmod(new ImageChmod());
|
||||
xmlrpc_c::methodPtr datastore_chmod(new DatastoreChmod());
|
||||
xmlrpc_c::methodPtr doc_chmod(new DocumentChmod());
|
||||
xmlrpc_c::methodPtr secg_chmod(new SecurityGroupChmod());
|
||||
|
||||
// Cluster Methods
|
||||
xmlrpc_c::methodPtr cluster_addhost(new ClusterAddHost());
|
||||
@ -385,6 +393,7 @@ void RequestManager::register_xml_methods()
|
||||
xmlrpc_c::methodPtr cluster_rename(new ClusterRename());
|
||||
xmlrpc_c::methodPtr datastore_rename(new DatastoreRename());
|
||||
xmlrpc_c::methodPtr host_rename(new HostRename());
|
||||
xmlrpc_c::methodPtr secg_rename(new SecurityGroupRename());
|
||||
|
||||
/* VM related methods */
|
||||
RequestManagerRegistry.addMethod("one.vm.deploy", vm_deploy);
|
||||
@ -688,6 +697,20 @@ void RequestManager::register_xml_methods()
|
||||
|
||||
RequestManagerRegistry.addMethod("one.zonepool.info",zonepool_info);
|
||||
|
||||
/* Security Group objects related methods*/
|
||||
|
||||
RequestManagerRegistry.addMethod("one.secgroup.allocate",secg_allocate);
|
||||
RequestManagerRegistry.addMethod("one.secgroup.delete", secg_delete);
|
||||
RequestManagerRegistry.addMethod("one.secgroup.info", secg_info);
|
||||
RequestManagerRegistry.addMethod("one.secgroup.update", secg_update);
|
||||
RequestManagerRegistry.addMethod("one.secgroup.chown", secg_chown);
|
||||
RequestManagerRegistry.addMethod("one.secgroup.chmod", secg_chmod);
|
||||
RequestManagerRegistry.addMethod("one.secgroup.clone", secg_clone);
|
||||
RequestManagerRegistry.addMethod("one.secgroup.rename", secg_rename);
|
||||
|
||||
RequestManagerRegistry.addMethod("one.secgrouppool.info",secgpool_info);
|
||||
|
||||
|
||||
/* System related methods */
|
||||
RequestManagerRegistry.addMethod("one.system.version", system_version);
|
||||
RequestManagerRegistry.addMethod("one.system.config", system_config);
|
||||
|
@ -700,3 +700,19 @@ int ZoneAllocate::pool_allocate(
|
||||
|
||||
return zonepool->allocate(tmpl, &id, error_str);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int SecurityGroupAllocate::pool_allocate(
|
||||
xmlrpc_c::paramList const& paramList,
|
||||
Template * tmpl,
|
||||
int& id,
|
||||
string& error_str,
|
||||
RequestAttributes& att)
|
||||
{
|
||||
SecurityGroupPool * sgpool = static_cast<SecurityGroupPool *>(pool);
|
||||
|
||||
return sgpool->allocate(att.uid, att.gid, att.uname, att.gname, att.umask,
|
||||
tmpl, &id, error_str);
|
||||
}
|
||||
|
30
src/secgroup/SConstruct
Normal file
30
src/secgroup/SConstruct
Normal file
@ -0,0 +1,30 @@
|
||||
# SConstruct for src/secgroup
|
||||
|
||||
# -------------------------------------------------------------------------- #
|
||||
# Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs #
|
||||
# #
|
||||
# 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. #
|
||||
#--------------------------------------------------------------------------- #
|
||||
|
||||
Import('env')
|
||||
|
||||
lib_name='nebula_secgroup'
|
||||
|
||||
# Sources to generate the library
|
||||
source_files=[
|
||||
'SecurityGroupPool.cc',
|
||||
'SecurityGroup.cc'
|
||||
]
|
||||
|
||||
# Build library
|
||||
env.StaticLibrary(lib_name, source_files)
|
245
src/secgroup/SecurityGroup.cc
Normal file
245
src/secgroup/SecurityGroup.cc
Normal file
@ -0,0 +1,245 @@
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs */
|
||||
/* */
|
||||
/* 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 "SecurityGroup.h"
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
const char * SecurityGroup::table = "secgroup_pool";
|
||||
|
||||
const char * SecurityGroup::db_names =
|
||||
"oid, name, body, uid, gid, owner_u, group_u, other_u";
|
||||
|
||||
const char * SecurityGroup::db_bootstrap = "CREATE TABLE IF NOT EXISTS secgroup_pool ("
|
||||
"oid INTEGER PRIMARY KEY, name VARCHAR(128), body MEDIUMTEXT, uid INTEGER, "
|
||||
"gid INTEGER, owner_u INTEGER, group_u INTEGER, other_u INTEGER, "
|
||||
"UNIQUE(name,uid))";
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
SecurityGroup::SecurityGroup(
|
||||
int _uid,
|
||||
int _gid,
|
||||
const string& _uname,
|
||||
const string& _gname,
|
||||
int _umask,
|
||||
Template* sgroup_template):
|
||||
PoolObjectSQL(-1, SECGROUP, "", _uid,_gid,_uname,_gname,table)
|
||||
{
|
||||
if (sgroup_template != 0)
|
||||
{
|
||||
obj_template = sgroup_template;
|
||||
}
|
||||
else
|
||||
{
|
||||
obj_template = new Template;
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
SecurityGroup::~SecurityGroup()
|
||||
{
|
||||
delete obj_template;
|
||||
};
|
||||
|
||||
/* ************************************************************************ */
|
||||
/* SecurityGroup :: Database Access Functions */
|
||||
/* ************************************************************************ */
|
||||
|
||||
int SecurityGroup::insert(SqlDB *db, string& error_str)
|
||||
{
|
||||
erase_template_attribute("NAME",name);
|
||||
|
||||
if (name.empty())
|
||||
{
|
||||
goto error_name;
|
||||
}
|
||||
|
||||
if ( insert_replace(db, false, error_str) != 0 )
|
||||
{
|
||||
goto error_db;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_name:
|
||||
error_str = "No NAME in template for Security Group.";
|
||||
goto error_common;
|
||||
|
||||
error_db:
|
||||
error_common:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int SecurityGroup::insert_replace(SqlDB *db, bool replace, string& error_str)
|
||||
{
|
||||
ostringstream oss;
|
||||
|
||||
int rc;
|
||||
string xml_body;
|
||||
|
||||
char * sql_name;
|
||||
char * sql_xml;
|
||||
|
||||
// Update the security group
|
||||
|
||||
sql_name = db->escape_str(name.c_str());
|
||||
|
||||
if ( sql_name == 0 )
|
||||
{
|
||||
goto error_name;
|
||||
}
|
||||
|
||||
sql_xml = db->escape_str(to_xml(xml_body).c_str());
|
||||
|
||||
if ( sql_xml == 0 )
|
||||
{
|
||||
goto error_body;
|
||||
}
|
||||
|
||||
if ( validate_xml(sql_xml) != 0 )
|
||||
{
|
||||
goto error_xml;
|
||||
}
|
||||
|
||||
if ( replace )
|
||||
{
|
||||
oss << "REPLACE";
|
||||
}
|
||||
else
|
||||
{
|
||||
oss << "INSERT";
|
||||
}
|
||||
|
||||
// Construct the SQL statement to Insert or Replace
|
||||
|
||||
oss <<" INTO "<<table <<" ("<< db_names <<") VALUES ("
|
||||
<< oid << ","
|
||||
<< "'" << sql_name << "',"
|
||||
<< "'" << sql_xml << "',"
|
||||
<< uid << ","
|
||||
<< gid << ","
|
||||
<< owner_u << ","
|
||||
<< group_u << ","
|
||||
<< other_u << ")";
|
||||
|
||||
|
||||
rc = db->exec(oss);
|
||||
|
||||
db->free_str(sql_name);
|
||||
db->free_str(sql_xml);
|
||||
|
||||
return rc;
|
||||
|
||||
error_xml:
|
||||
db->free_str(sql_name);
|
||||
db->free_str(sql_xml);
|
||||
|
||||
error_str = "Error transforming the Security Group to XML.";
|
||||
|
||||
goto error_common;
|
||||
|
||||
error_body:
|
||||
db->free_str(sql_name);
|
||||
goto error_generic;
|
||||
|
||||
error_name:
|
||||
goto error_generic;
|
||||
|
||||
error_generic:
|
||||
error_str = "Error inserting Security Group in DB.";
|
||||
error_common:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
string& SecurityGroup::to_xml(string& xml) const
|
||||
{
|
||||
ostringstream oss;
|
||||
string template_xml;
|
||||
string perms_xml;
|
||||
|
||||
oss <<
|
||||
"<SECURITY_GROUP>" <<
|
||||
"<ID>" << oid << "</ID>" <<
|
||||
"<UID>" << uid << "</UID>" <<
|
||||
"<GID>" << gid << "</GID>" <<
|
||||
"<UNAME>" << uname << "</UNAME>" <<
|
||||
"<GNAME>" << gname << "</GNAME>" <<
|
||||
"<NAME>" << name << "</NAME>" <<
|
||||
perms_to_xml(perms_xml) <<
|
||||
obj_template->to_xml(template_xml) <<
|
||||
"</SECURITY_GROUP>";
|
||||
|
||||
xml = oss.str();
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
int SecurityGroup::from_xml(const string& xml)
|
||||
{
|
||||
vector<xmlNodePtr> content;
|
||||
int rc = 0;
|
||||
|
||||
// Initialize the internal XML object
|
||||
update_from_str(xml);
|
||||
|
||||
// Get class base attributes
|
||||
rc += xpath(oid, "/SECURITY_GROUP/ID", -1);
|
||||
rc += xpath(uid, "/SECURITY_GROUP/UID", -1);
|
||||
rc += xpath(gid, "/SECURITY_GROUP/GID", -1);
|
||||
rc += xpath(uname, "/SECURITY_GROUP/UNAME","not_found");
|
||||
rc += xpath(gname, "/SECURITY_GROUP/GNAME","not_found");
|
||||
rc += xpath(name, "/SECURITY_GROUP/NAME", "not_found");
|
||||
|
||||
// Permissions
|
||||
rc += perms_from_xml();
|
||||
|
||||
// Get associated classes
|
||||
ObjectXML::get_nodes("/SECURITY_GROUP/TEMPLATE", content);
|
||||
|
||||
if (content.empty())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Template contents
|
||||
rc += obj_template->from_xml_node(content[0]);
|
||||
|
||||
ObjectXML::free_nodes(content);
|
||||
content.clear();
|
||||
|
||||
if (rc != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------------------ */
|
89
src/secgroup/SecurityGroupPool.cc
Normal file
89
src/secgroup/SecurityGroupPool.cc
Normal file
@ -0,0 +1,89 @@
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Copyright 2002-2014, OpenNebula Project (OpenNebula.org), C12G Labs */
|
||||
/* */
|
||||
/* 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 "SecurityGroupPool.h"
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
SecurityGroupPool::SecurityGroupPool(SqlDB * db)
|
||||
:PoolSQL(db, SecurityGroup::table, true, true)
|
||||
{}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int SecurityGroupPool::allocate(
|
||||
int uid,
|
||||
int gid,
|
||||
const string& uname,
|
||||
const string& gname,
|
||||
int umask,
|
||||
Template * sgroup_template,
|
||||
int * oid,
|
||||
string& error_str)
|
||||
{
|
||||
SecurityGroup * secgroup;
|
||||
SecurityGroup * secgroup_aux = 0;
|
||||
|
||||
string name;
|
||||
|
||||
ostringstream oss;
|
||||
|
||||
secgroup = new SecurityGroup(uid, gid, uname, gname, umask, sgroup_template);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Check name & duplicates
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
secgroup->get_template_attribute("NAME", name);
|
||||
|
||||
if ( !PoolObjectSQL::name_is_valid(name, error_str) )
|
||||
{
|
||||
goto error_name;
|
||||
}
|
||||
|
||||
secgroup_aux = get(name,uid,false);
|
||||
|
||||
if( secgroup_aux != 0 )
|
||||
{
|
||||
goto error_duplicated;
|
||||
}
|
||||
|
||||
*oid = PoolSQL::allocate(secgroup, error_str);
|
||||
|
||||
return *oid;
|
||||
|
||||
error_duplicated:
|
||||
oss << "NAME is already taken by SecurityGroup " << secgroup_aux->get_oid() << ".";
|
||||
error_str = oss.str();
|
||||
|
||||
error_name:
|
||||
delete secgroup;
|
||||
*oid = -1;
|
||||
|
||||
return *oid;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int SecurityGroupPool::update(SecurityGroup * securitygroup)
|
||||
{
|
||||
return securitygroup->update(db);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* -------------------------------------------------------------------------- */
|
Loading…
Reference in New Issue
Block a user