1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-23 22:50:09 +03:00

F #6063: Backup Jobs for OpenNebula

Includes the following changes:
- xml-schema for Backup Job and Scheduled Actions
- GO, Java api
- Deprecate onevm update-chart, delete-chart
    * The commands are replaced by sched-update and sched-delete
    * Refactor method deprecate_command, it's still possible to run the
    command
    * Delete 'shutdown' and 'delete' commands deprecated years ago
    * Fix --verbose option for sched-update and sched-delete
- Re-implementation of scheduled actions, now are managed and executed
  by oned
- Backup Job objects, API, and CLI commands
This commit is contained in:
Ruben S. Montero 2023-07-03 18:15:52 +02:00
parent 90585e42cf
commit 6bbfbb03e4
No known key found for this signature in database
GPG Key ID: A0CEA6FA880A1D87
116 changed files with 8303 additions and 2562 deletions

View File

@ -111,7 +111,8 @@ main_env.Append(LIBPATH=[
cwd+'/src/market',
cwd+'/src/ipamm',
cwd+'/src/data_model',
cwd+'/src/protocol'
cwd+'/src/protocol',
cwd+'/src/sam'
])
# Compile flags
@ -351,6 +352,7 @@ build_scripts = [
'src/monitor/SConstruct',
'src/onedb/SConstruct',
'src/protocol/SConstruct',
'src/sam/SConstruct',
svncterm_path,
'share/context/SConstruct'
]

View File

@ -255,16 +255,12 @@ private:
/**
* Array of PoolObjectSQL types to iterate over all types
*/
static const int num_pool_objects;
static const PoolObjectSQL::ObjectType pool_objects[];
static const std::array<PoolObjectSQL::ObjectType, 19> pool_objects;
/**
* Array of Auth operation types to iterate over all types
*/
static const int num_auth_operations;
static const AuthRequest::Operation auth_operations[];
static const std::array<AuthRequest::Operation, 4> auth_operations;
/**
* Objects that cannot be used with the CLUSTER(%) selector

363
include/BackupJob.h Normal file
View File

@ -0,0 +1,363 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2023, OpenNebula Project, OpenNebula Systems */
/* */
/* 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 BACKUP_JOB_H_
#define BACKUP_JOB_H_
#include "PoolObjectSQL.h"
#include "ObjectXML.h"
#include "ObjectCollection.h"
/**
* The BackuJob class, it organize backups of multiple VMs
*
* The schema is as follows:
* <BACKUPJOB>
*
* <!-- PoolObjectSQL attributes -->
*
* <PRIORITY> Of this backup job. BJ with higher priority are scheduled first
* <SCHED_ACTIONS> List of associated scheduled action
* <ID>
* <UPDATED_VMS> VMs with all backups up to date
* <ID>
* <OUTDATED_VMS> VMs that need a backup
* <ID>
* <BACKING_UP_VMS> VMs with an ongoing backup operation
* <ID>
* <ERROR_VMS> VMs that fail the last backup operation
* <ID>
* <LAST_BACKUP_TIME> Last time the backup job was triggered
* <LAST_BACKUP_DURATION> Time to backup all VMs int the backup job
* <TEMPLATE>
* <KEEP_LAST> Just keep the last N backups
* <BACKUP_VOLATILE> Backup volatile disks or not
* <FS_FREEZE> FS freeze operation to perform on the VM
* <MODE> Backup mode
* <BACKUP_VMS> comma separated list of VMs to backup, order is implicit
* <DATASTORE_ID> The dastore ID used to store the active backups
* <EXECUTION>
*/
class BackupJob : public PoolObjectSQL
{
public:
// *************************************************************************
// Priority Limits
// *************************************************************************
static const int MAX_PRIO;
static const int MIN_PRIO;
static const int MAX_USER_PRIO;
// *************************************************************************
// Backup modes
// *************************************************************************
enum Execution
{
SEQUENTIAL = 0, /** < Backup VMs one by one */
PARALLEL = 1, /** < Backup all VMs in parallel */
};
static std::string execution_to_str(Execution exec)
{
switch (exec)
{
case SEQUENTIAL: return "SEQUENTIAL";
case PARALLEL: return "PARALLEL";
default: return "";
}
};
static Execution str_to_execution(std::string& str_exec)
{
Execution exec = SEQUENTIAL;
one_util::toupper(str_exec);
if ( str_exec == "SEQUENTIAL" )
{
exec = SEQUENTIAL;
}
else if ( str_exec == "PARALELL" )
{
exec = PARALLEL;
}
return exec;
};
/**
* Function to print the BackuJob object into a string in
* XML format.
* @param xml the resulting XML string
* @return a reference to the generated string
*/
std::string& to_xml(std::string& xml) const override
{
return to_xml_extended(xml, false);
}
std::string& to_xml_extended(std::string& xml, bool do_sa) const;
/**
* Starts execution of the Backup Job
* Add VMs to WAITING_VMS list, the backup of individual VMs
* is managed by Scheduled Action Manager
*/
int execute(std::string& error);
/**
* Cancel pending Backup Job action, clear the waiting and pending list
*/
void cancel();
/**
* Retry Backup Job, move VMs from error list to outdated
*/
void retry();
/**
* Returns VMs waiting for a backup, the order define the priority
*/
std::vector<int> backup_vms() const
{
std::string vms_str;
std::vector<int> vms;
get_template_attribute("BACKUP_VMS", vms_str);
one_util::split(vms_str, ',', vms);
return vms;
}
/**
* Returns VMs waiting for a backup, the order define the priority
*/
const std::set<int>& outdated() const
{
return _outdated.get_collection();
}
/**
* Returns VMs that are currently being backed up
*/
const std::set<int>& backing_up() const
{
return _backing_up.get_collection();
}
/**
* Get priority
*/
int priority() const
{
return _priority;
}
/**
* Set priority
*/
void priority(int pr)
{
if ( pr >= MIN_PRIO && pr <= MAX_PRIO )
{
_priority = pr;
}
}
/**
* Returns execution mode: SEQUENTIAL or PARALLEL
*/
Execution exec_mode() const;
/**
* Returns Datastore ID, where to backup the VMs
*/
int ds_id() const;
/**
* Returns the 'reset' attribute for the Backup Config
*/
int reset() const;
/**
* VM backup started, move the VM from waiting to pending list
*/
void backup_started(int vm_id);
/**
* Remove Virtual Machine from outdated and VMS list
*/
void remove_vm(int vm_id);
/**
* VM backup finished, remove it from backing_up list
*/
void backup_finished(int vm_id, bool success);
/**
* Add Virtual Machine to error_vms list
*/
void add_error(int vm_id);
/**
* Return Backup Config in format for Virtual Machine
*/
void get_backup_config(Template &tmpl);
/**
* Get IDs of the associated scheduled actions
*/
ObjectCollection& sched_actions()
{
return _sched_actions;
}
const ObjectCollection& sched_actions() const
{
return _sched_actions;
}
friend class BackupJobPool;
friend class PoolSQL;
protected:
/**
* Child classes can process the new template set with replace_template or
* append_template with this method
* @param error string describing the error if any
* @return 0 on success
*/
int post_update_template(std::string& error) override
{
parse();
return 0;
}
// *************************************************************************
// Database implementation
// *************************************************************************
/**
* Bootstraps the database table(s) associated to the Backup Jobs
* @return 0 on success
*/
static int bootstrap(SqlDB * db);
/**
* Writes the BackupJob to the DB
* @param db pointer to the database.
* @return 0 on success.
*/
int insert(SqlDB * db, std::string& error_str) override;
/**
* Updates the BackupJob record
* @param db pointer to the database.
* @return 0 on success.
*/
int update(SqlDB * db) override;
/**
* Execute an INSERT or REPLACE Sql query.
* @param db The SQL DB
* @param replace Execute an INSERT or a REPLACE
* @return 0 on success
*/
int insert_replace(SqlDB *db, bool replace, std::string& error_str);
private:
/**
* Priority for this backup job [0, 99]
*/
int _priority;
/**
* Associated scheduled action for this backup job
*/
ObjectCollection _sched_actions;
/**
* These collections stores the collection of VMs in the Virtual
* Networks and manages the update process
* - updated VMs with not pending backups
* - outdated VMs that need backup
* - backing_up VMs with an ongoing backup operation
* - error VMs that fail the last backup operation
*/
ObjectCollection _updated;
ObjectCollection _outdated;
ObjectCollection _backing_up;
ObjectCollection _error;
/**
* Time stats for the last backup action (start - epoch, duration - sec)
*/
time_t _last_time;
time_t _last_duration;
/**
* @param uid
* @param id
* @param uname
* @param gname
* @param umask
* @param tmpl
*/
BackupJob(int uid,
int gid,
const std::string& uname,
const std::string& gname,
int umask,
std::unique_ptr<Template> templ);
/**
* Factory method for Hook templates
*/
std::unique_ptr<Template> get_new_template() const override
{
return std::make_unique<Template>(true);
}
/*
* Parse configuration attributes for the backup operation
* - KEEP_LAST
* - BACKUP_VOLATILE
* - FSFREEZE
* - MODE
* - BACKUP_VMS
*
* This method also updates the VMs collections removing those VMs no longer
* present in BACKUP_VMS
*/
void parse();
/**
* 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 std::string &xml_str) override;
};
#endif /*BACKUP_JOB_H_*/

186
include/BackupJobPool.h Normal file
View File

@ -0,0 +1,186 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2023, OpenNebula Project, OpenNebula Systems */
/* */
/* 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 BACKUP_JOB_POOL_H_
#define BACKUP_JOB_POOL_H_
#include "PoolSQL.h"
#include "BackupJob.h"
#include "OneDB.h"
/**
* The Backup Job Pool class.
*/
class BackupJobPool : public PoolSQL
{
public:
BackupJobPool(SqlDB *db)
: PoolSQL(db, one_db::backup_job_table)
{};
/**
* Function to allocate a new Image object
* @param uid the user id of the image's owner
* @param gid the id of the group this object is assigned to
* @param uname name of the user
* @param gname name of the group
* @param umask permissions umask
* @param template template associated with the Backup Job
* @param oid the id assigned to the Backup Job
* @param error_str Returns the error reason, if any
* @return the oid assigned to the object,
* -1 in case of failure
* -2 in case of template parse failure
*/
int allocate (
int uid,
int gid,
const std::string& uname,
const std::string& gname,
int umask,
std::unique_ptr<Template> templ,
int * oid,
std::string& error_str);
/**
* Updates an Image in the data base. It also updates the previous state
* after executing the hooks.
* @param objsql a pointer to the VM
*
* @return 0 on success.
*/
int update(PoolObjectSQL * objsql) override
{
auto bj = dynamic_cast<BackupJob*>(objsql);
if ( bj == nullptr )
{
return -1;
}
return bj->update(db);
}
/**
* Gets an object from the pool (if needed the object is loaded from the
* database). The object is locked, other threads can't access the same
* object. The lock is released by destructor.
* @param oid the Image unique identifier
* @return a pointer to the Image, nullptr in case of failure
*/
std::unique_ptr<BackupJob> get(int oid)
{
return PoolSQL::get<BackupJob>(oid);
}
/**
* Gets a read only object from the pool (if needed the object is loaded from the
* database). No object lock, other threads may work with the same object.
* @param oid the Image unique identifier
* @return a pointer to the Image, nullptr in case of failure
*/
std::unique_ptr<BackupJob> get_ro(int oid)
{
return PoolSQL::get_ro<BackupJob>(oid);
}
/**
* Gets an object from the pool (if needed the object is loaded from the
* database). The object is locked, other threads can't access the same
* object. The lock is released by destructor.
* @param name of the object
* @param uid id of owner
*
* @return a pointer to the object, 0 in case of failure
*/
std::unique_ptr<BackupJob> get(const std::string& name, int uid)
{
return PoolSQL::get<BackupJob>(name,uid);
}
/**
* Gets a read only object from the pool (if needed the object is loaded from the
* database). No object lock, other threads may work with the same object.
* @param name of the object
* @param uid id of owner
*
* @return a pointer to the object, 0 in case of failure
*/
std::unique_ptr<BackupJob> get_ro(const std::string& name, int uid)
{
return PoolSQL::get_ro<BackupJob>(name, uid);
}
/**
* Bootstraps the database table(s) associated to the Image pool
* @return 0 on success
*/
static int bootstrap(SqlDB *_db)
{
return BackupJob::bootstrap(_db);
}
/**
* Dumps the Image 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 sid first element used for pagination
* @param eid last element used for pagination, -1 to disable
* @param desc descending order of pool elements
*
* @return 0 on success
*/
int dump(std::string& oss, const std::string& where, int sid, int eid,
bool desc) override
{
return PoolSQL::dump(oss, "BACKUPJOB_POOL", "body", one_db::backup_job_table,
where, sid, eid, desc);
}
/**
* Returns Backup Jobs IDs with outdated VMs and max priority
*/
std::vector<int> active()
{
std::vector<int> oids;
search(oids, one_db::backup_job_table,
"outdated_vms > 0 AND priority = (SELECT MAX(priority) FROM backupjob_pool WHERE outdated_vms > 0)");
return oids;
}
private:
//--------------------------------------------------------------------------
// Configuration Attributes for Images
// -------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Pool Attributes
// -------------------------------------------------------------------------
/**
* Factory method to produce Image objects
* @return a pointer to the new Image
*/
PoolObjectSQL * create() override
{
return new BackupJob(-1, -1, "", "", 0, nullptr);
}
};
#endif /*BACKUP_JOB_POOL_H_*/

View File

@ -190,6 +190,11 @@ public:
config.replace("ACTIVE_FLATTEN", status);
}
void backup_job_id(int id)
{
config.replace("BACKUP_JOB_ID", id);
}
/* ---------------------------------------------------------------------- */
int last_datastore_id() const
@ -258,6 +263,18 @@ public:
return af;
}
int backup_job_id() const
{
int id;
if (!config.get("BACKUP_JOB_ID", id))
{
return -1;
}
return id;
}
/* ---------------------------------------------------------------------- */
void last_backup_clear()
@ -266,6 +283,8 @@ public:
config.erase("LAST_BACKUP_ID");
config.erase("LAST_BACKUP_SIZE");
config.erase("BACKUP_JOB_ID");
}
/**

View File

@ -25,6 +25,7 @@ class TransferManager;
class DispatchManager;
class VirtualMachineManager;
class ImageManager;
class BackupJobPool;
class ClusterPool;
class HostPool;
class ImagePool;
@ -217,6 +218,11 @@ private:
*/
SecurityGroupPool * sgpool = nullptr;
/**
* Pointer to the SecurityGroup Pool
*/
BackupJobPool * bjpool = nullptr;
/**
* Pointer to the Cluster Pool
*/

View File

@ -29,6 +29,7 @@ class LogDB;
class FedLogDB;
class User;
class BackupJobPool;
class ClusterPool;
class DatastorePool;
class DocumentPool;
@ -38,6 +39,7 @@ class HostPool;
class ImagePool;
class MarketPlacePool;
class MarketPlaceAppPool;
class ScheduledActionPool;
class SecurityGroupPool;
class VdcPool;
class VMGroupPool;
@ -61,6 +63,7 @@ class LifeCycleManager;
class MarketPlaceManager;
class RaftManager;
class RequestManager;
class ScheduledActionManager;
class TransferManager;
class VirtualMachineManager;
@ -180,6 +183,17 @@ public:
{
return hkpool;
}
BackupJobPool * get_bjpool() const
{
return bjpool;
}
ScheduledActionPool * get_sapool() const
{
return sapool;
}
// --------------------------------------------------------------
// Manager Accessors
// --------------------------------------------------------------
@ -259,6 +273,11 @@ public:
return rm;
};
ScheduledActionManager * get_sam() const
{
return sam;
}
// --------------------------------------------------------------
// Environment & Configuration
// --------------------------------------------------------------
@ -617,8 +636,10 @@ public:
, vmpool(0), hpool(0), vnpool(0), upool(0), ipool(0), gpool(0), tpool(0)
, dspool(0), clpool(0), docpool(0), zonepool(0), secgrouppool(0)
, vdcpool(0), vrouterpool(0), marketpool(0), apppool(0), vmgrouppool(0)
, vntpool(0), hkpool(0), lcm(0), vmm(0), im(0), tm(0), dm(0), rm(0), hm(0)
, vntpool(0), hkpool(0), bjpool(0), sapool(0)
, lcm(0), vmm(0), im(0), tm(0), dm(0), rm(0), hm(0)
, hl(0), authm(0), aclm(0), imagem(0), marketm(0), ipamm(0), raftm(0), frm(0)
, sam(0)
{
};
@ -690,6 +711,9 @@ private:
VMGroupPool * vmgrouppool;
VNTemplatePool * vntpool;
HookPool * hkpool;
BackupJobPool * bjpool;
ScheduledActionPool* sapool;
// ---------------------------------------------------------------
// Nebula Managers
// ---------------------------------------------------------------
@ -709,6 +733,7 @@ private:
IPAMManager * ipamm;
RaftManager * raftm;
FedReplicaManager * frm;
ScheduledActionManager *sam;
// ---------------------------------------------------------------
// Implementation functions

View File

@ -248,7 +248,7 @@ namespace one_util
* @return the joined strings
*/
template <class T>
std::string join(const std::set<T>& values, char delim)
std::string join(const T& values, char delim)
{
return join(values.begin(), values.end(), delim);
}
@ -361,6 +361,9 @@ namespace one_util
return true;
}
template <>
bool str_cast(const std::string& str, std::string& value);
} // namespace one_util
#endif /* _NEBULA_UTIL_H_ */

View File

@ -18,6 +18,7 @@
#define OBJECT_COLLECTION_H_
#include <set>
#include <vector>
#include <string>
#include <libxml/tree.h>
@ -36,6 +37,17 @@ public:
ObjectCollection(const std::string& cname, const std::set<int>& cset)
:collection_name(cname), collection_set(cset){};
template <typename T>
ObjectCollection(const std::string& cname, const std::vector<T>& cvector)
:collection_name(cname)
{
for (const auto& i: cvector)
{
collection_set.insert(static_cast<int>(i));
}
}
~ObjectCollection(){};
/**
@ -46,6 +58,15 @@ public:
*/
int add(int id);
template <typename T>
void add(const T& collection)
{
for (const auto& i: collection)
{
collection_set.insert(static_cast<int>(i));
}
}
/**
* Deletes an ID from the set.
* @param id The id
@ -54,6 +75,14 @@ public:
*/
int del(int id);
/**
* Deletes IDs not present in the base collection
* @param base the reference collection
*
* @return number of elements deleted
*/
int del_not_present(const ObjectCollection& base);
/**
* Deletes all IDs from the set.
*/

View File

@ -262,6 +262,24 @@ namespace one_db
extern const char * zone_db_bootstrap;
extern const char * zone_table;
/* ---------------------------------------------------------------------- */
/* Backup Job tables */
/* ---------------------------------------------------------------------- */
extern const char * backup_job_table;
extern const char * backup_job_db_names;
extern const char * backup_job_db_bootstrap;
/* ---------------------------------------------------------------------- */
/* Scheduled Action tables */
/* ---------------------------------------------------------------------- */
extern const char * scheduled_action_table;
extern const char * scheduled_action_db_names;
extern const char * scheduled_action_db_bootstrap;
}

View File

@ -67,7 +67,9 @@ public:
MARKETPLACEAPP = 0x0010000000000000LL,
VMGROUP = 0x0020000000000000LL,
VNTEMPLATE = 0x0040000000000000LL,
HOOK = 0x0080000000000000LL
HOOK = 0x0080000000000000LL,
BACKUPJOB = 0x0100000000000000LL,
SCHEDULEDACTION= 0x0200000000000000LL
};
/**
@ -107,6 +109,7 @@ public:
case VMGROUP: return "VMGROUP"; break;
case VNTEMPLATE: return "VNTEMPLATE"; break;
case HOOK: return "HOOK"; break;
case BACKUPJOB: return "BACKUPJOB"; break;
default: return "";
}
};
@ -133,6 +136,7 @@ public:
else if ( type == "VMGROUP" ) return VMGROUP;
else if ( type == "VNTEMPLATE" ) return VNTEMPLATE;
else if ( type == "HOOK" ) return HOOK;
else if ( type == "BACKUPJOB" ) return BACKUPJOB;
else return NONE;
};

View File

@ -75,6 +75,22 @@ public:
, success(false)
{}
RequestAttributes(AuthRequest::Operation api_auth_op,
int _uid,
int _gid,
PoolObjectSQL::ObjectType object_type)
: uid(_uid)
, gid(_gid)
, req_id(-1)
, umask(0)
, retval(nullptr)
, resp_obj(object_type)
, resp_id(-1)
, replication_idx(UINT64_MAX)
, auth_op(api_auth_op)
, success(false)
{}
RequestAttributes(const RequestAttributes& ra) = default;
RequestAttributes(int _uid, int _gid, const RequestAttributes& ra)
@ -249,6 +265,53 @@ public:
format_str = log_format;
}
/**
* Performs a basic quota check for this request using the uid/gid
* from the request. Usage counters are updated for the user/group.
* On case of error, the failure_response return values is not set, instead
* the error reason is returned in error_str
*
* @param tmpl describing the object
* @param object type of the object
* @param att the specific request attributes
*
* @param error_str Error reason, if any
* @return true if the user is authorized.
*/
static bool quota_authorization(Template * tmpl, Quotas::QuotaType qtype,
const RequestAttributes& att, std::string& error_str);
/**
* 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
*/
static void quota_rollback(Template * tmpl, Quotas::QuotaType qtype,
const RequestAttributes& att);
static std::string failure_message(ErrorCode ec, RequestAttributes& att,
const std::string& method_name,
PoolObjectSQL::ObjectType auth_object = PoolObjectSQL::NONE);
/**
* Performs a basic authorization for this request using the uid/gid
* from the request. The function gets the object from the pool to get
* the public attribute and its owner. The authorization is based on
* object and type of operation for the request.
* @param pool object pool
* @param oid of the object, can be -1 for objects to be created, or
* pools.
* @param att the specific request attributes
*
* @return SUCCESS if the user is authorized.
*/
static ErrorCode basic_authorization(
PoolSQL* pool,
int oid,
PoolObjectSQL::ObjectType auth_object,
RequestAttributes& att);
protected:
/* ---------------------------------------------------------------------- */
/* Global configuration attributes por API calls */
@ -409,24 +472,6 @@ protected:
*/
bool basic_authorization(int oid, RequestAttributes& att);
/**
* Performs a basic authorization for this request using the uid/gid
* from the request. The function gets the object from the pool to get
* the public attribute and its owner. The authorization is based on
* object and type of operation for the request.
* @param pool object pool
* @param oid of the object, can be -1 for objects to be created, or
* pools.
* @param att the specific request attributes
*
* @return SUCCESS if the user is authorized.
*/
static ErrorCode basic_authorization(
PoolSQL* pool,
int oid,
PoolObjectSQL::ObjectType auth_object,
RequestAttributes& att);
/**
* Performs a basic quota check for this request using the uid/gid
* from the request. Usage counters are updated for the user/group.
@ -441,31 +486,6 @@ protected:
bool quota_authorization(Template * tmpl, Quotas::QuotaType qtype,
RequestAttributes& att);
/**
* Performs a basic quota check for this request using the uid/gid
* from the request. Usage counters are updated for the user/group.
* On case of error, the failure_response return values is not set, instead
* the error reason is returned in error_str
*
* @param tmpl describing the object
* @param object type of the object
* @param att the specific request attributes
*
* @param error_str Error reason, if any
* @return true if the user is authorized.
*/
static bool quota_authorization(Template * tmpl, Quotas::QuotaType qtype,
const RequestAttributes& att, std::string& error_str);
/**
* 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
*/
static void quota_rollback(Template * tmpl, Quotas::QuotaType qtype,
const RequestAttributes& att);
/**
* @param tmpl describing the object
* @param att the specific request attributes

View File

@ -26,6 +26,7 @@
#include "DatastoreTemplate.h"
#include "MarketPlaceTemplate.h"
#include "BackupJobPool.h"
#include "ClusterPool.h"
#include "DatastorePool.h"
#include "DocumentPool.h"
@ -792,6 +793,38 @@ public:
RequestAttributes& att) override;
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
class BackupJobAllocate : public RequestManagerAllocate
{
public:
BackupJobAllocate():
RequestManagerAllocate("one.backupjob.allocate",
"Allocates a new Backup Job",
"A:ss",
true)
{
Nebula& nd = Nebula::instance();
pool = nd.get_bjpool();
auth_object = PoolObjectSQL::BACKUPJOB;
}
/* --------------------------------------------------------------------- */
std::unique_ptr<Template> get_object_template() const override
{
return std::make_unique<Template>();
}
Request::ErrorCode pool_allocate(xmlrpc_c::paramList const& _paramList,
std::unique_ptr<Template> tmpl,
int& id,
RequestAttributes& att) override;
};
#endif

View File

@ -0,0 +1,138 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2023, OpenNebula Project, OpenNebula Systems */
/* */
/* 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_BACKUPJOB_H
#define REQUEST_MANAGER_BACKUPJOB_H
#include "Request.h"
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class RequestManagerBackupJob: public Request
{
public:
RequestManagerBackupJob(const std::string& method_name,
const std::string& params,
const std::string& help);
};
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class BackupJobBackup: public RequestManagerBackupJob
{
public:
BackupJobBackup()
: RequestManagerBackupJob("one.backupjob.backup", "A:si", "Execute Backup Job")
{};
protected:
void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att) override;
};
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class BackupJobCancel: public RequestManagerBackupJob
{
public:
BackupJobCancel()
: RequestManagerBackupJob("one.backupjob.cancel", "A:si", "Cancel Backup Job execution")
{};
protected:
void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att) override;
};
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class BackupJobRetry: public RequestManagerBackupJob
{
public:
BackupJobRetry()
: RequestManagerBackupJob("one.backupjob.retry", "A:si", "Retry Backup Job")
{};
protected:
void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att) override;
};
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class BackupJobPriority: public RequestManagerBackupJob
{
public:
BackupJobPriority()
: RequestManagerBackupJob("one.backupjob.priority", "A:sii", "Set Backup Job priority")
{}
protected:
void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att) override;
};
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class BackupJobSchedAdd: public RequestManagerBackupJob
{
public:
BackupJobSchedAdd()
: RequestManagerBackupJob("one.backupjob.schedadd", "A:sis", "Create Scheduled Action")
{};
protected:
void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att) override;
};
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class BackupJobSchedDelete: public RequestManagerBackupJob
{
public:
BackupJobSchedDelete()
: RequestManagerBackupJob("one.backupjob.scheddelete", "A:sii", "Delete Scheduled Action")
{};
protected:
void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att) override;
};
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class BackupJobSchedUpdate: public RequestManagerBackupJob
{
public:
BackupJobSchedUpdate()
: RequestManagerBackupJob("one.backupjob.schedupdate", "A:siis", "Update Scheduled Action")
{};
protected:
void request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att) override;
};
#endif

View File

@ -20,6 +20,7 @@
#include "Request.h"
#include "Nebula.h"
#include "BackupJobPool.h"
#include "DatastorePool.h"
#include "DocumentPool.h"
#include "ImagePool.h"
@ -310,4 +311,20 @@ public:
~VMGroupChmod(){};
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
class BackupJobChmod: public RequestManagerChmod
{
public:
BackupJobChmod():
RequestManagerChmod("one.backupjob.chmod",
"Changes permission bits of a Backup Job")
{
Nebula& nd = Nebula::instance();
pool = nd.get_bjpool();
auth_object = PoolObjectSQL::BACKUPJOB;
}
};
#endif

View File

@ -20,6 +20,7 @@
#include "Request.h"
#include "Nebula.h"
#include "BackupJobPool.h"
#include "DatastorePool.h"
#include "DocumentPool.h"
#include "ImagePool.h"
@ -360,4 +361,21 @@ public:
~VMGroupChown(){};
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
class BackupJobChown: public RequestManagerChown
{
public:
BackupJobChown():
RequestManagerChown("one.backupjob.chown",
"Changes ownership of a Backup Job")
{
Nebula& nd = Nebula::instance();
pool = nd.get_bjpool();
auth_object = PoolObjectSQL::BACKUPJOB;
}
};
#endif

View File

@ -402,5 +402,20 @@ public:
~HookDelete() = default;
};
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class BackupJobDelete : public RequestManagerDelete
{
public:
BackupJobDelete();
protected:
int drop(std::unique_ptr<PoolObjectSQL> obj,
bool recursive,
RequestAttributes& att) override;
};
#endif

View File

@ -19,6 +19,7 @@
#include "Request.h"
#include "Nebula.h"
#include "BackupJobPool.h"
#include "ClusterPool.h"
#include "DatastorePool.h"
#include "DocumentPool.h"
@ -445,5 +446,27 @@ protected:
};
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
class BackupJobInfo : public RequestManagerInfo
{
public:
BackupJobInfo():
RequestManagerInfo("one.backupjob.info",
"Returns Backup Job information")
{
Nebula& nd = Nebula::instance();
pool = nd.get_bjpool();
auth_object = PoolObjectSQL::BACKUPJOB;
}
protected:
void to_xml(RequestAttributes& att, PoolObjectSQL * object,
std::string& str) override
{
static_cast<BackupJob *>(object)->to_xml_extended(str, true);
};
};
#endif

View File

@ -295,4 +295,23 @@ public:
~HookUnlock() = default;
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
class BackupJobLock: public RequestManagerLock
{
public:
BackupJobLock();
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
class BackupJobUnlock: public RequestManagerUnlock
{
public:
BackupJobUnlock();
};
#endif

View File

@ -393,4 +393,14 @@ public:
xmlrpc_c::paramList const& paramList, RequestAttributes& att) override;
};
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
class BackupJobPoolInfo : public RequestManagerPoolInfoFilter
{
public:
BackupJobPoolInfo();
};
#endif

View File

@ -19,6 +19,7 @@
#include "Request.h"
#include "Nebula.h"
#include "BackupJobPool.h"
#include "ClusterPool.h"
#include "DatastorePool.h"
#include "DocumentPool.h"
@ -521,4 +522,24 @@ public:
}
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
class BackupJobRename: public RequestManagerRename
{
public:
BackupJobRename():
RequestManagerRename("one.backupjob.rename", "Renames a Backup Job")
{
Nebula& nd = Nebula::instance();
pool = nd.get_bjpool();
auth_object = PoolObjectSQL::BACKUPJOB;
}
int exist(const std::string& name, int uid) override
{
return pool->exist(name, uid);
}
};
#endif

View File

@ -20,6 +20,7 @@
#include "Request.h"
#include "Nebula.h"
#include "BackupJobPool.h"
#include "ClusterPool.h"
#include "DatastorePool.h"
#include "DocumentPool.h"
@ -473,4 +474,29 @@ public:
~HookUpdateTemplate(){};
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
class BackupJobUpdateTemplate : public RequestManagerUpdateTemplate
{
public:
BackupJobUpdateTemplate():
RequestManagerUpdateTemplate("one.backupjob.update",
"Updates a Backup Job template")
{
Nebula& nd = Nebula::instance();
pool = nd.get_bjpool();
auth_object = PoolObjectSQL::BACKUPJOB;
}
//Always append to BackupJob templates (not duplicated attributes)
int replace_template(PoolObjectSQL * object,
const std::string & tmpl,
const RequestAttributes &att,
std::string &error_str) override
{
return RequestManagerUpdateTemplate::append_template(object, tmpl, att, error_str);
}
};
#endif

View File

@ -35,6 +35,7 @@ protected:
{
Nebula& nd = Nebula::instance();
pool = nd.get_vmpool();
dm = nd.get_dm();
auth_object = PoolObjectSQL::VM;
auth_op = AuthRequest::MANAGE;
@ -53,6 +54,15 @@ protected:
PoolObjectAuth * ds_perm,
PoolObjectAuth * img_perm);
// Authorize the request, do not set failure_response message
ErrorCode vm_authorization_no_response(int id,
ImageTemplate * tmpl,
VirtualMachineTemplate* vtmpl,
RequestAttributes& att,
PoolObjectAuth * host_perms,
PoolObjectAuth * ds_perm,
PoolObjectAuth * img_perm);
// Check user and group quotas. Do not set failure_response on failure
bool quota_resize_authorization(
Template * deltas,
@ -98,6 +108,8 @@ protected:
std::unique_ptr<VirtualMachine> get_vm(int id, RequestAttributes& att);
std::unique_ptr<VirtualMachine> get_vm_ro(int id, RequestAttributes& att);
DispatchManager * dm;
};
/* ------------------------------------------------------------------------- */
@ -110,7 +122,10 @@ public:
RequestManagerVirtualMachine("one.vm.action",
"Performs an action on a virtual machine",
"A:ssi") {}
~VirtualMachineAction() = default;
ErrorCode request_execute(RequestAttributes& att,
const std::string& action_str,
int vid);
protected:
void request_execute(xmlrpc_c::paramList const& _paramList,
@ -370,7 +385,7 @@ public:
vm_action = VMActions::SNAPSHOT_CREATE_ACTION;
}
~VirtualMachineSnapshotCreate() = default;
ErrorCode request_execute(RequestAttributes& att, int vid, std::string& name);
protected:
void request_execute(xmlrpc_c::paramList const& _paramList,
@ -391,7 +406,7 @@ public:
vm_action = VMActions::SNAPSHOT_REVERT_ACTION;
}
~VirtualMachineSnapshotRevert() = default;
ErrorCode request_execute(RequestAttributes& att, int vid, int snap_id);
protected:
void request_execute(xmlrpc_c::paramList const& _paramList,
@ -412,7 +427,7 @@ public:
vm_action = VMActions::SNAPSHOT_DELETE_ACTION;
}
~VirtualMachineSnapshotDelete() = default;
ErrorCode request_execute(RequestAttributes& att, int vid, int snap_id);
protected:
void request_execute(xmlrpc_c::paramList const& _paramList,
@ -478,7 +493,8 @@ public:
vm_action = VMActions::DISK_SNAPSHOT_CREATE_ACTION;
}
~VirtualMachineDiskSnapshotCreate() = default;
ErrorCode request_execute(RequestAttributes& att, int vid, int disk_id,
const std::string& name);
protected:
void request_execute(xmlrpc_c::paramList const& _paramList,
@ -502,7 +518,7 @@ public:
vm_action = VMActions::DISK_SNAPSHOT_REVERT_ACTION;
}
~VirtualMachineDiskSnapshotRevert() = default;
ErrorCode request_execute(RequestAttributes& att, int vid, int disk_id, int snap_id);
protected:
void request_execute(xmlrpc_c::paramList const& _paramList,
@ -526,7 +542,7 @@ public:
vm_action = VMActions::DISK_SNAPSHOT_DELETE_ACTION;
}
~VirtualMachineDiskSnapshotDelete() = default;
ErrorCode request_execute(RequestAttributes& att, int vid, int disk_id, int snap_id);
protected:
void request_execute(xmlrpc_c::paramList const& _paramList,
@ -658,6 +674,11 @@ public:
auth_op = AuthRequest::ADMIN;
}
ErrorCode request_execute(RequestAttributes& att,
int vm_id,
int backup_ds_id,
bool reset);
protected:
void request_execute(xmlrpc_c::paramList const& pl,
RequestAttributes& ra) override;

View File

@ -14,17 +14,16 @@
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
#ifndef SCHED_ACTION_ATTRIBUTE_H_
#define SCHED_ACTION_ATTRIBUTE_H_
#ifndef SCHEDULED_ACTION_H_
#define SCHEDULED_ACTION_H_
#include <set>
#include "VirtualMachineAttribute.h"
#include "PoolObjectSQL.h"
/**
* The VirtualMachine SCHED_ACTION attribute
* The Scheduled Action class,
* it represents planned actions fro Virtual Machine, Backup Jobs, ...
*/
class SchedAction: public VirtualMachineAttribute
class ScheduledAction : public PoolObjectSQL
{
public:
enum Repeat
@ -44,206 +43,193 @@ public:
DATE = 2
};
SchedAction(VectorAttribute *va, int id):VirtualMachineAttribute(va, id){};
virtual ~SchedAction(){};
int action_id()
{
return get_id();
}
ScheduledAction(PoolObjectSQL::ObjectType type, int parent_id);
/**
* Returns the REPEAT value of the SCHED_ACTION
* @param r repeat WEEKLY, MONTHLY, YEARLY or HOURLY
* @return -1 if REPEAT not found or in wrong format 0 on success
* Function to print the Scheduled Action into a string in
* XML format. String and StreamString versions
* @param xml the resulting XML string
* @return a reference to the generated string
*/
int repeat(Repeat& r);
std::string& to_xml(std::string& xml) const override;
/**
* Returns the END_TYPE value of the SCHED_ACTION
* @param eo ends on TIMES WEEKLY, MONTHLY, YEARLY or HOURLY
* @return -1 if REPEAT not found or in wrong format 0 on success
* Init the Scheduled Action from Template string
* @param str Template as a string
* @return 0 on success, -1 otherwise
*/
int endon(EndOn& eo);
/**
* Parse the DAYS attribute of the sched action
* @param d set of days (unique)
* @return -1 if not found (d will be empty) 0 otherwise
*/
int days(std::set<int>& _d);
int parse(const VectorAttribute * va, time_t origin, std::string& error_str);
/**
* This function checks that the DAYS attributes are in range
* according to the Repeat value:
* @param r repeat type (hourly, weekly...)
* @param error in case of error
*
* @return true if days are in range false (error) if not
*/
bool days_in_range(Repeat r, std::string& error);
bool days_in_range(std::string& error);
/**
* This function checks that END_VALUE is properly defined for the
* associated END_TYPE
* @param eo end type (date, times)
* @param error in case of error
*
* @return 0 if days are in range -1 (error) if not or -2 (not defined)
* @return 0 if days are in range, -1 error
*/
int ends_in_range(EndOn eo, std::string& error);
int ends_in_range(std::string& error);
/**
* This function parse and checks the sched action attributes: REPEAT, DAYS
* , END_TYPE, END_DATE. It also removed DONE and MESSAGE.
* @param error
* @param clean indicates if the user wants to remove DONE and MESSAGE
* @return 0 if success -1 otherwise
*/
int parse(std::string& error, bool clean);
/**
* @param stime time when the VM was started for relative time specs
* @return action execution time. Returns -1 on error
*/
time_t get_time(time_t stime);
/**
* @param stime time when the VM was started for relative time specs
* @return true if the action needs to be executed.
*/
bool is_due(time_t stime);
bool is_due();
/**
* Compute the next action, updating the TIME attribute for this action
* @return time for next action, if ended or error -1
*/
time_t next_action();
/**
* Set Scheduled Action error message
*/
void log_error(const std::string& error)
{
_message = error;
}
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
const std::string& action()
{
return _action;
}
const std::string& args()
{
return _args;
}
// Friends
friend class ScheduledActionPool;
friend class PoolSQL;
private:
/**
* Objects that can include scheduled actions
*/
static std::set<PoolObjectSQL::ObjectType> SCHED_OBJECTS;
/**
* Valid actions for VMs
*/
static std::set<std::string> VM_ACTIONS;
// ----------------------------------------
// Scheduled Action fields
// ----------------------------------------
/**
* Type of object associated to the Scheduled Action
*/
PoolObjectSQL::ObjectType _type;
/**
* ID of object associated to the Scheduled Action
*/
int _parent_id;
/**
* Action and arguments
*/
std::string _action;
std::string _args;
/**
* Date to perform the action
*/
time_t _time;
/**
* Repeat schedule for the action
*/
Repeat _repeat;
std::string _days;
EndOn _end_type;
time_t _end_value;
/**
*
*/
time_t _done;
std::string _message;
/**
* 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 std::string &xml_str) override
{
update_from_str(xml_str);
return rebuild_attributes();
}
/**
* Rebuilds the internal attributes using xpath
*/
int rebuild_attributes();
/**
* Parse string time
* @param str_time Time as string
* @return action execution time. Returns -1 on error
*/
time_t parse_time(std::string str_time, time_t origin);
/**
* Return number of days in the Repeat period
*/
int days_in_period(int month, int year);
// --------------- DB access methods ---------------
/**
* Write the Scheduled Action to the DB
* @param db pointer to the database.
* @return 0 on success.
*/
int insert(SqlDB * db, std::string& error_str) override;
/**
* Updates the Scheduled Action
* @param db pointer to the database.
* @return 0 on success.
*/
int update(SqlDB * db) override
{
std::string error;
return insert_replace(db, true, error);
}
/**
* Execute an INSERT or REPLACE Sql query.
* @param db The SQL DB
* @param replace Execute an INSERT or a REPLACE
* @return 0 on success
*/
int insert_replace(SqlDB *db, bool replace, std::string& error_str);
};
/**
* Set of VirtualMachine SCHED_ACTION attributes
*/
class SchedActions : public VirtualMachineAttributeSet
{
public:
/* ---------------------------------------------------------------------- */
/* Constructor and Initialization functions */
/* ---------------------------------------------------------------------- */
/**
* Creates the SchedAction set from a Template with SCHED_ACTION=[...]
* attributes, id's are auto-assigned for internal use
* @param tmpl template with DISK
*/
SchedActions(Template * tmpl): VirtualMachineAttributeSet(false)
{
std::vector<VectorAttribute *> vas;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
tmpl->get("SCHED_ACTION", vas);
init_attribute_map("ID", vas);
};
virtual ~SchedActions(){};
/**
* Parse the ScheduleActions of a template
* @param error
* @param clean indicates if the user wants to remove DONE and MESSAGE
* @return -1 in case of error 0 otherwise
*/
int parse(std::string& error, bool clean)
{
for ( schedaction_iterator action = begin(); action != end(); ++action)
{
if ( (*action)->parse(error, clean) == -1 )
{
return -1;
}
}
return 0;
}
bool empty()
{
return a_set.empty();
}
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
/* Raw VectorAttribute helpers */
/* ---------------------------------------------------------------------- */
/**
* Parse a set of scheduled actions and optionally assign them a valid id
* @param vas the vector of SCHED_ACTION
* @param err string in case of error
* @param clean remove DONE and MESSAGE attributes
* @param set_id to set ID for each action
*
* @return 0 on success -1 if error
*/
static int parse(std::vector<VectorAttribute *>& vas, std::string& err,
bool clean, bool set_id);
/**
* Adds a new SchedAction based on the provided VectorAttribute. The new
* attribute is check and parsed
* @param va VectorAttribute with the action
* @param err with description
*
* @return pointer to new attribute nullptr on error
*/
static VectorAttribute * new_action(
const std::vector<const VectorAttribute *>& vas,
VectorAttribute * va, std::string &err);
static VectorAttribute * get_action(
const std::vector<VectorAttribute *>& sched_actions, int id);
/* ---------------------------------------------------------------------- */
/* Iterators */
/* ---------------------------------------------------------------------- */
/**
* Generic iterator for the SchedActions set.
*/
class SchedActionIterator : public AttributeIterator
{
public:
SchedActionIterator():AttributeIterator(){};
SchedActionIterator(const AttributeIterator& i):AttributeIterator(i){};
virtual ~SchedActionIterator(){};
SchedAction * operator*() const
{
return static_cast<SchedAction *>(map_it->second);
}
};
SchedActionIterator begin()
{
SchedActionIterator it(ExtendedAttributeSet::begin());
return it;
}
SchedActionIterator end()
{
SchedActionIterator it(ExtendedAttributeSet::end());
return it;
}
typedef class SchedActionIterator schedaction_iterator;
protected:
VirtualMachineAttribute * attribute_factory(VectorAttribute * va,
int id) const
{
return new SchedAction(va, id);
};
};
#endif /*SCHED_ACTION_ATTRIBUTE_H_*/
#endif /*SCHEDULED_ACTION_H_*/

View File

@ -0,0 +1,99 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2023, OpenNebula Project, OpenNebula Systems */
/* */
/* 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 SCHEDULED_ACTION_MANAGER_H_
#define SCHEDULED_ACTION_MANAGER_H_
#include "Listener.h"
#include "ScheduledAction.h"
class BackupJob;
class BackupJobPool;
class ScheduledActionPool;
class VirtualMachinePool;
/**
* Scheduled Action Manager - launches scheduled actions, executes Backup Jobs
* This class should in future replace the standalone Scheduler
*/
class ScheduledActionManager
{
public:
ScheduledActionManager(time_t timer, int max_backups, int max_backups_host);
void finalize();
private:
friend class ScheduledActions;
Timer timer_thread;
BackupJobPool *bj_pool;
ScheduledActionPool *sa_pool;
VirtualMachinePool *vm_pool;
int _max_backups;
int _max_backups_host;
int active_backups;
/*
* Count backups per host map<host_id, backups_count>
*/
std::map<int,int> host_backups;
/*
* List of backups to run <sa_id, vm_id>
*/
std::vector<std::pair<int, int>> vm_backups;
// Periodically called method,
void timer_action();
/*
* Manages Virtual Machine scheduled actions
*/
void scheduled_vm_actions();
/*
*
*/
void update_backup_counters();
/*
* Run Virtual Machine Scheduled backups
*/
void run_vm_backups();
/*
* Manages Backup Job scheduled actions
*/
void scheduled_backup_jobs();
/*
* Manages backups created by BackupJob
*/
void backup_jobs();
void run_scheduled_action_vm(int vm_id, int sa_id, const std::string& aname);
int vm_action_call(int vmid, int sa_id, std::string& error);
};
#endif /*SCHEDULE_MANAGER_H_*/

View File

@ -0,0 +1,117 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2023, OpenNebula Project, OpenNebula Systems */
/* */
/* 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 SCHEDULED_ACTION_POOL_H_
#define SCHEDULED_ACTION_POOL_H_
#include "PoolSQL.h"
#include "OneDB.h"
#include "ScheduledAction.h"
class SqlDB;
class ScheduledActionPool : public PoolSQL
{
public:
ScheduledActionPool(SqlDB * db)
: PoolSQL(db, one_db::scheduled_action_table)
{}
/**
* Function to allocate a new Scheduled Action object
* @return the oid assigned to the object or -1 in case of failure
*/
int allocate(PoolObjectSQL::ObjectType type,
int parent_id,
time_t origin,
const VectorAttribute * va,
std::string& error_str);
/**
* Gets an object from the pool (if needed the object is loaded from the
* database). The object is locked, other threads can't access the same
* object. The lock is released by destructor.
* @param oid the Hook unique identifier
* @return a pointer to the Hook, nullptr in case of failure
*/
std::unique_ptr<ScheduledAction> get(int oid)
{
return PoolSQL::get<ScheduledAction>(oid);
}
/**
* Gets a read only object from the pool (if needed the object is loaded from the
* database). No object lock, other threads may work with the same object.
* @param oid the Hook unique identifier
* @return a pointer to the Scheduled Action, nullptr in case of failure
*/
std::unique_ptr<ScheduledAction> get_ro(int oid)
{
return PoolSQL::get_ro<ScheduledAction>(oid);
}
/**
* Bootstraps the database table(s) associated to the Scheduled Action pool
* @return 0 on success
*/
static int bootstrap(SqlDB *_db);
/**
* Dumps the HOOK 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 sid first element used for pagination
* @param eid last element used for pagination, -1 to disable
* @param desc descending order of pool elements
*
* @return 0 on success
*/
int dump(std::string& oss, const std::string& where, int sid, int eid,
bool desc) override
{
return PoolSQL::dump(oss, "SCHED_ACTION_POOL", "body",
one_db::scheduled_action_table, where, sid, eid, desc);
}
/**
* Prints a set of ScheduledActions into a string stream. The element
* is named <SCHEDULED_ACTIONS>
*
* @param actions set of ScheduledActions IDs to include
* @param oss the output stream
*
* @return -1 if any of the actions does not exist. The stream contains
* all the existing actions.
*/
int dump(const std::set<int> &actions, std::string& oss);
/**
* Factory method to produce Hook objects
* @return a pointer to the new VN
*/
PoolObjectSQL * create() override
{
return new ScheduledAction(PoolObjectSQL::NONE, -1);
}
/*
* Return list of due actions <sched_id, resource_id> for specific object type
*/
std::vector<std::pair<int, int>> get_is_due_actions(PoolObjectSQL::ObjectType ot);
};
#endif

View File

@ -22,6 +22,7 @@
#include <vector>
#include <string>
#include <functional>
#include <memory>
#include <libxml/tree.h>
#include <libxml/parser.h>
@ -186,6 +187,8 @@ public:
*/
std::string& to_xml(std::string& xml) const;
std::string& to_xml(std::string& xml, const std::string& extra) const;
std::string& to_json(std::string& xml) const;
std::string& to_token(std::string& xml) const;
@ -299,6 +302,24 @@ public:
return j;
}
template<typename T>
int remove(const std::string& name, std::vector<std::unique_ptr<T>>& values)
{
int j = 0;
auto index = attributes.equal_range(name);
for ( auto i = index.first; i != index.second; i++,j++ )
{
std::unique_ptr<T> va(static_cast<T *>(i->second));
values.push_back(std::move(va));
}
attributes.erase(index.first, index.second);
return j;
}
/**
* Removes an attribute from the template, but it DOES NOT free the
* attribute.

View File

@ -709,7 +709,7 @@ public:
{
load_monitoring();
to_xml_extended(history->vm_info, 0);
to_xml_extended(history->vm_info, 0, false);
};
/**
@ -717,7 +717,7 @@ public:
*/
void set_previous_vm_info()
{
to_xml_extended(previous_history->vm_info, 0);
to_xml_extended(previous_history->vm_info, 0, false);
};
/**
@ -728,7 +728,7 @@ public:
{
history->etime = _etime;
to_xml_extended(history->vm_info, 0);
to_xml_extended(history->vm_info, 0, false);
};
/**
@ -748,7 +748,7 @@ public:
{
previous_history->etime = _etime;
to_xml_extended(previous_history->vm_info, 0);
to_xml_extended(previous_history->vm_info, 0, false);
};
/**
@ -898,7 +898,7 @@ public:
*/
std::string& to_xml(std::string& xml) const override
{
return to_xml_extended(xml, 1);
return to_xml_extended(xml, 1, false);
}
/**
@ -917,7 +917,7 @@ public:
*/
std::string& to_xml_extended(std::string& xml) const
{
return to_xml_extended(xml, 2);
return to_xml_extended(xml, 2, true);
}
/**
@ -1724,42 +1724,9 @@ public:
*/
int check_shareable_disks(const std::string& vmm_mad, std::string& error);
/**
* Add scheduled actions
* @param sched_template Teplate with scheduled actions
* @param error Error string in case of failure
* @return 0 on success, -1 on failure
*/
int sched_action_add(const std::string& sched_template,
std::string& error);
/**
* Update one scheduled action
* @param sched_id ID of the scheduled action to delete
* @param error Error string in case of failure
* @return 0 on success, -1 on failure
*/
int sched_action_delete(int sched_id,
std::string& error);
/**
* Update one scheduled action
* @param sched_id ID of the scheduled action to update
* @param sched_template New value of scheduled action
* @param error Error string in case of failure
* @return 0 on success, -1 on failure
*/
int sched_action_update(int sched_id,
const std::string& sched_template,
std::string& error);
// ------------------------------------------------------------------------
// Backup related functions
// ------------------------------------------------------------------------
/**
*
*/
long long backup_size(Template &ds_quota)
{
return disks.backup_size(ds_quota, _backups.do_volatile());
@ -1770,6 +1737,19 @@ public:
return _backups;
}
// ------------------------------------------------------------------------
// Scheduled actions functions
// ------------------------------------------------------------------------
ObjectCollection& sched_actions()
{
return _sched_actions;
}
const ObjectCollection& sched_actions() const
{
return _sched_actions;
}
private:
static const int MAX_ERROR_MSG_LENGTH = 100;
@ -1876,6 +1856,11 @@ private:
*/
Backups _backups;
/**
* Associated scheduled action for this VM
*/
ObjectCollection _sched_actions;
// *************************************************************************
// DataBase implementation (Private)
// *************************************************************************
@ -1957,9 +1942,10 @@ private:
* 0: none
* 1: the last one
* 2: all
* @param sa include scheduled action information
* @return a reference to the generated string
*/
std::string& to_xml_extended(std::string& xml, int n_history) const;
std::string& to_xml_extended(std::string& xml, int n_history, bool sa) const;
std::string& to_json(std::string& json) const;
@ -2217,13 +2203,6 @@ private:
*/
int parse_public_clouds(const char *name, std::string& error);
/**
* This method removes sched_action DONE/MESSAGE attributes
* @param error_str with error description
* @return -1 in case of error 0 otherwise
*/
int parse_sched_action(std::string& error_str);
/**
* Encrypt all secret attributes
*/

View File

@ -165,6 +165,13 @@ public:
int get_pending(
std::vector<int>& oids);
/**
* Function to get the IDs of VMs in backup state
* @param oids a vector that contains the IDs
* @return 0 on success
*/
int get_backup(std::vector<int>& oids);
/**
* Gets the IDs of VMs matching the given SQL where string.
* @param oids a vector that contains the IDs

View File

@ -1014,6 +1014,7 @@ BIN_FILES="src/nebula/oned \
src/cli/onevcenter \
src/cli/onevntemplate \
src/cli/onehook \
src/cli/onebackupjob \
src/cli/onelog \
src/cli/oneirb \
src/onedb/onedb \
@ -2492,6 +2493,8 @@ RUBY_OPENNEBULA_LIB_FILES="src/oca/ruby/opennebula/acl_pool.rb \
src/oca/ruby/opennebula/vntemplate.rb \
src/oca/ruby/opennebula/hook_pool.rb \
src/oca/ruby/opennebula/hook.rb \
src/oca/ruby/opennebula/backupjob_pool.rb \
src/oca/ruby/opennebula/backupjob.rb \
src/oca/ruby/opennebula/hook_log.rb \
src/oca/ruby/opennebula/flow.rb"
@ -2548,6 +2551,7 @@ ONE_CLI_LIB_FILES="src/cli/one_helper/onegroup_helper.rb \
src/cli/one_helper/onemarket_helper.rb \
src/cli/one_helper/onevntemplate_helper.rb \
src/cli/one_helper/onehook_helper.rb \
src/cli/one_helper/onebackupjob_helper.rb \
src/cli/one_helper/oneflow_helper.rb \
src/cli/one_helper/oneflowtemplate_helper.rb"
@ -2575,7 +2579,8 @@ CLI_BIN_FILES="src/cli/onevm \
src/cli/onevntemplate \
src/cli/oneirb \
src/cli/onelog \
src/cli/onehook"
src/cli/onehook \
src/cli/onebackupjob"
CLI_CONF_FILES="src/cli/etc/onegroup.yaml \
src/cli/etc/onehost.yaml \
@ -2598,6 +2603,7 @@ CLI_CONF_FILES="src/cli/etc/onegroup.yaml \
src/cli/etc/onemarket.yaml \
src/cli/etc/onevntemplate.yaml \
src/cli/etc/onehook.yaml \
src/cli/etc/onebackupjob.yaml \
src/cli/etc/oneflow.yaml \
src/cli/etc/oneflowtemplate.yaml"
@ -3102,6 +3108,7 @@ MAN_FILES="share/man/oneacct.1.gz \
share/man/oneshowback.1.gz \
share/man/oneacl.1.gz \
share/man/onehook.1.gz \
share/man/onebackupjob.1.gz \
share/man/onelog.1.gz \
share/man/oneirb.1.gz \
share/man/onehost.1.gz \
@ -3163,6 +3170,8 @@ LIBVIRT_RNG_SHARE_MODULE_FILES="share/schemas/libvirt/basictypes.rng \
XSD_FILES="share/doc/xsd/acct.xsd \
share/doc/xsd/acl_pool.xsd
share/doc/xsd/api_info.xsd
share/doc/xsd/backupjob.xsd
share/doc/xsd/backupjob_pool.xsd
share/doc/xsd/cluster.xsd
share/doc/xsd/cluster_pool.xsd
share/doc/xsd/datastore.xsd
@ -3190,6 +3199,7 @@ XSD_FILES="share/doc/xsd/acct.xsd \
share/doc/xsd/raftstatus.xsd
share/doc/xsd/security_group.xsd
share/doc/xsd/security_group_pool.xsd
share/doc/xsd/shared.xsd
share/doc/xsd/showback.xsd
share/doc/xsd/user.xsd
share/doc/xsd/user_pool.xsd

View File

@ -124,25 +124,8 @@
<xs:element name="STIME" type="xs:integer"/>
<xs:element name="ETIME" type="xs:integer"/>
<xs:element name="DEPLOY_ID" type="xs:string"/>
<xs:element name="MONITORING">
<!--
<xs:complexType>
<xs:all>
<- Percentage of 1 CPU consumed (two fully consumed cpu is 200) ->
<xs:element name="CPU" type="xs:decimal" minOccurs="0" maxOccurs="1"/>
<- MEMORY consumption in kilobytes ->
<xs:element name="MEMORY" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<- NETTX: Sent bytes to the network ->
<xs:element name="NETTX" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<- NETRX: Received bytes from the network ->
<xs:element name="NETRX" type="xs:integer" minOccurs="0" maxOccurs="1"/>
</xs:all>
</xs:complexType>
-->
</xs:element>
<xs:element name="MONITORING"/>
<xs:element name="SCHED_ACTIONS" type="xs:anyType"/>
<xs:element name="TEMPLATE" type="xs:anyType"/>
<xs:element name="USER_TEMPLATE" type="xs:anyType"/>
<xs:element name="HISTORY_RECORDS">

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
targetNamespace="http://opennebula.org/XMLSchema" xmlns="http://opennebula.org/XMLSchema">
<xs:include schemaLocation="shared.xsd"/>
<xs:element name="BACKUPJOB">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:integer"/>
<xs:element name="UID" type="xs:integer"/>
<xs:element name="GID" type="xs:integer"/>
<xs:element name="UNAME" type="xs:string"/>
<xs:element name="GNAME" type="xs:string"/>
<xs:element name="NAME" type="xs:string"/>
<xs:element name="LOCK" type="LOCK" minOccurs="0" maxOccurs="1"/>
<xs:element name="PERMISSIONS" type="PERMISSIONS"/>
<xs:element name="PRIORITY" type="xs:integer"/>
<xs:element name="LAST_BACKUP_TIME" type="xs:integer"/>
<xs:element name="LAST_BACKUP_DURATION" type="xs:integer"/>
<xs:element name="SCHED_ACTIONS" type="IDS"/>
<xs:element name="UPDATED_VMS" type="IDS"/>
<xs:element name="OUTDATED_VMS" type="IDS"/>
<xs:element name="BACKING_UP_VMS" type="IDS"/>
<xs:element name="ERROR_VMS" type="IDS"/>
<xs:element name="TEMPLATE">
<xs:complexType>
<xs:sequence>
<xs:element name="BACKUP_VMS" type="xs:string"/>
<xs:element name="BACKUP_VOLATILE" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="DATASTORE_ID" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="EXECUTION" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="FS_FREEZE" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="KEEP_LAST" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<xs:element name="MODE" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="SCHED_ACTION" type="SCHED_ACTION" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
targetNamespace="http://opennebula.org/XMLSchema" xmlns="http://opennebula.org/XMLSchema">
<xs:include schemaLocation="backupjob.xsd"/>
<xs:element name="BACKUPJOB_POOL">
<xs:complexType>
<xs:sequence maxOccurs="1" minOccurs="1">
<xs:element ref="BACKUPJOB" maxOccurs="unbounded" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@ -4,6 +4,8 @@
<xs:include schemaLocation="acct.xsd"/>
<xs:include schemaLocation="acl_pool.xsd"/>
<xs:include schemaLocation="api_info.xsd"/>
<xs:include schemaLocation="backupjob_pool.xsd"/>
<xs:include schemaLocation="backupjob.xsd"/>
<xs:include schemaLocation="cluster_pool.xsd"/>
<xs:include schemaLocation="cluster.xsd"/>
<xs:include schemaLocation="datastore_pool.xsd"/>
@ -28,6 +30,7 @@
<xs:include schemaLocation="raftstatus.xsd"/>
<xs:include schemaLocation="security_group_pool.xsd"/>
<xs:include schemaLocation="security_group.xsd"/>
<xs:include schemaLocation="shared.xsd"/>
<xs:include schemaLocation="showback.xsd"/>
<xs:include schemaLocation="user_pool.xsd"/>
<xs:include schemaLocation="user.xsd"/>

View File

@ -244,6 +244,8 @@
</xs:complexType>
</xs:element>
<xs:element name="MAX_BACKUPS" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<xs:element name="MAX_BACKUPS_HOST" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<xs:element name="MAX_CONN" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<xs:element name="MAX_CONN_BACKLOG" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<xs:element name="MESSAGE_SIZE" type="xs:integer" minOccurs="0" maxOccurs="1"/>

46
share/doc/xsd/shared.xsd Normal file
View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
targetNamespace="http://opennebula.org/XMLSchema" xmlns="http://opennebula.org/XMLSchema">
<xs:complexType name="LOCK">
<xs:sequence>
<xs:element name="LOCKED" type="xs:integer"/>
<xs:element name="OWNER" type="xs:integer"/>
<xs:element name="TIME" type="xs:integer"/>
<xs:element name="REQ_ID" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="PERMISSIONS">
<xs:sequence>
<xs:element name="OWNER_U" type="xs:integer"/>
<xs:element name="OWNER_M" type="xs:integer"/>
<xs:element name="OWNER_A" type="xs:integer"/>
<xs:element name="GROUP_U" type="xs:integer"/>
<xs:element name="GROUP_M" type="xs:integer"/>
<xs:element name="GROUP_A" type="xs:integer"/>
<xs:element name="OTHER_U" type="xs:integer"/>
<xs:element name="OTHER_M" type="xs:integer"/>
<xs:element name="OTHER_A" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="IDS">
<xs:sequence>
<xs:element name="ID" type="xs:integer" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="SCHED_ACTION">
<xs:sequence>
<xs:element name="ID" type="xs:integer"/>
<xs:element name="PARENT_ID" type="xs:integer"/>
<xs:element name="TYPE" type="xs:string"/>
<xs:element name="ACTION" type="xs:string"/>
<xs:element name="ARGS" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="TIME" type="xs:string"/>
<xs:element name="REPEAT" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<xs:element name="DAYS" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="END_TYPE" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<xs:element name="END_VALUE" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<xs:element name="DONE" type="xs:integer" minOccurs="0" maxOccurs="1"/>
<xs:element name="MESSAGE" type="xs:string" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:complexType>
</xs:schema>

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
targetNamespace="http://opennebula.org/XMLSchema" xmlns="http://opennebula.org/XMLSchema">
<xs:include schemaLocation="shared.xsd"/>
<xs:element name="VM">
<xs:complexType>
<xs:sequence>
@ -10,21 +11,7 @@
<xs:element name="UNAME" type="xs:string"/>
<xs:element name="GNAME" type="xs:string"/>
<xs:element name="NAME" type="xs:string"/>
<xs:element name="PERMISSIONS" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element name="OWNER_U" type="xs:integer"/>
<xs:element name="OWNER_M" type="xs:integer"/>
<xs:element name="OWNER_A" type="xs:integer"/>
<xs:element name="GROUP_U" type="xs:integer"/>
<xs:element name="GROUP_M" type="xs:integer"/>
<xs:element name="GROUP_A" type="xs:integer"/>
<xs:element name="OTHER_U" type="xs:integer"/>
<xs:element name="OTHER_M" type="xs:integer"/>
<xs:element name="OTHER_A" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="PERMISSIONS" type="PERMISSIONS"/>
<xs:element name="LAST_POLL" type="xs:integer"/>
<!-- STATE and LCM_STATE values,
@ -38,16 +25,7 @@
<xs:element name="STIME" type="xs:integer"/>
<xs:element name="ETIME" type="xs:integer"/>
<xs:element name="DEPLOY_ID" type="xs:string"/>
<xs:element name="LOCK" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element name="LOCKED" type="xs:integer"/>
<xs:element name="OWNER" type="xs:integer"/>
<xs:element name="TIME" type="xs:integer"/>
<xs:element name="REQ_ID" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="LOCK" type="LOCK" minOccurs="0" maxOccurs="1"/>
<xs:element name="MONITORING">
<xs:complexType>
<xs:sequence>
@ -91,6 +69,7 @@
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="SCHED_ACTIONS" type="IDS"/>
<xs:element name="TEMPLATE">
<xs:complexType>
<xs:sequence>
@ -152,21 +131,6 @@
<xs:element name="OS" minOccurs="0" maxOccurs="1"/>
<xs:element name="PCI" minOccurs="0" maxOccurs="1"/>
<xs:element name="RAW" minOccurs="0" maxOccurs="1"/>
<xs:element name="SCHED_ACTION" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="ACTION" type="xs:string"/>
<xs:element name="ARGS" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="DAYS" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="END_TYPE" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="END_VALUE" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="ID" type="xs:string"/>
<xs:element name="REPEAT" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="TIME" type="xs:string"/>
<xs:element name="WARNING" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="SECURITY_GROUP_RULE" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="SNAPSHOT" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
@ -193,6 +157,7 @@
<xs:element name="VROUTER_ID" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="VROUTER_KEEPALIVED_ID" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="VROUTER_KEEPALIVED_PASSWORD" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="SCHED_ACTION" type="SCHED_ACTION" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
@ -331,13 +296,7 @@
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="BACKUP_IDS" minOccurs="1" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="BACKUP_IDS" type="IDS"/>
</xs:sequence>
</xs:complexType>
</xs:element>

View File

@ -42,6 +42,11 @@
# reserved: comma separated list of ports or ranges. Two numbers separated by
# a colon indicate a range.
#
# MAX_BACKUPS: Maximum number of concurrent backup operations in the cloud.
# The scheduler will not start pending scheduled backups beyond this limit
#
# MAX_BACKUPS_HOST: Maximum number of active backup operations per host.
#
# LOG: Configuration for the logging system
# system: defines the logging system:
# file to log in the oned.log file
@ -93,6 +98,9 @@ VNC_PORTS = [
# RESERVED = "6800, 6801, 6810:6820, 9869"
]
MAX_BACKUPS = 5
MAX_BACKUPS_HOST = 2
#*******************************************************************************
# Server network and connection
#-------------------------------------------------------------------------------

View File

@ -24,6 +24,7 @@ set -e
COMMANDS=(
'bin/oneacct' 'OpenNebula Accounting Tool'
'bin/oneacl' 'manages OpenNebula ACLs'
'bin/onebackupjob' 'manages OpenNebula Backup Jobs'
'bin/onecfg' 'OpenNebula configuration management tool'
'bin/onedb' 'OpenNebula database migration tool'
'bin/onegroup' 'manages OpenNebula groups'

31
share/shell/bash_completion Normal file → Executable file
View File

@ -148,6 +148,36 @@ _oneacl() {
fi
}
_onebackupjob() {
local cur prev opts cmd
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
if [ "${#COMP_WORDS[@]}" -gt "2" ]; then
pprev="${COMP_WORDS[COMP_CWORD-2]}"
fi
opts="create delete list show lock unlock chgrp chown chmod rename
update execute cancel sched-delete sched-update"
cmd=onebackupjob
if [ "$COMP_CWORD" == 1 ]; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
elif [ "$COMP_CWORD" == 2 ]; then
case "$prev" in
delete|show|lock|unlock|chgrp|chown|chmod|rename| \
update|execute|cancel|sched-update|sched-delete)
_complete $cmd
;;
create)
COMPREPLY=( $(compgen -A file -- "${cur}") )
return 0
;;
esac
elif [ "$COMP_CWORD" == 3 ]; then
_one_owner_update "$pprev"
fi
}
_onecluster() {
local cur prev opts cmd
COMPREPLY=()
@ -875,6 +905,7 @@ _onezone() {
}
complete -F _oneacl oneacl
complete -F _onebackupjob onebackupjob
complete -F _onecluster onecluster
complete -F _onedatastore onedatastore
complete -F _onedb onedb

View File

@ -80,5 +80,9 @@
<id>noConstructor</id>
<fileName>include/Callbackable.h</fileName>
</suppress>
<suppress>
<id>knownEmptyContainer</id>
<fileName>src/schedule/ScheduledActionManager.cc</fileName>
</suppress>
</suppressions>

View File

@ -96,7 +96,8 @@ AclManager::AclManager(
PoolObjectSQL::TEMPLATE |
PoolObjectSQL::DOCUMENT |
PoolObjectSQL::SECGROUP |
PoolObjectSQL::VMGROUP,
PoolObjectSQL::VMGROUP |
PoolObjectSQL::BACKUPJOB,
AuthRequest::CREATE,
AclRule::ALL_ID,
error_str);

View File

@ -23,15 +23,14 @@ using namespace std;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
const long long AclRule::INDIVIDUAL_ID = 0x0000000100000000LL;
const long long AclRule::GROUP_ID = 0x0000000200000000LL;
const long long AclRule::ALL_ID = 0x0000000400000000LL;
const long long AclRule::CLUSTER_ID = 0x0000000800000000LL;
const long long AclRule::INDIVIDUAL_ID = 0x0000000100000000LL;
const long long AclRule::GROUP_ID = 0x0000000200000000LL;
const long long AclRule::ALL_ID = 0x0000000400000000LL;
const long long AclRule::CLUSTER_ID = 0x0000000800000000LL;
const long long AclRule::NONE_ID = 0x1000000000000000LL;
const long long AclRule::NONE_ID = 0x1000000000000000LL;
const int AclRule::num_pool_objects = 18;
const PoolObjectSQL::ObjectType AclRule::pool_objects[] = {
const std::array<PoolObjectSQL::ObjectType, 19> AclRule::pool_objects = {
PoolObjectSQL::VM,
PoolObjectSQL::HOST,
PoolObjectSQL::NET,
@ -49,11 +48,11 @@ const PoolObjectSQL::ObjectType AclRule::pool_objects[] = {
PoolObjectSQL::MARKETPLACE,
PoolObjectSQL::MARKETPLACEAPP,
PoolObjectSQL::VMGROUP,
PoolObjectSQL::VNTEMPLATE
PoolObjectSQL::VNTEMPLATE,
PoolObjectSQL::BACKUPJOB
};
const int AclRule::num_auth_operations = 4;
const AuthRequest::Operation AclRule::auth_operations[] = {
const std::array<AuthRequest::Operation, 4> AclRule::auth_operations = {
AuthRequest::USE,
AuthRequest::MANAGE,
AuthRequest::ADMIN,
@ -242,7 +241,7 @@ bool AclRule::malformed(string& error_str) const
oss << "[resource] type is missing";
}
if ( (resource & 0xFF80000000000000LL) != 0 )
if ( (resource & 0xFE80000000000000LL) != 0 )
{
if ( error )
{
@ -382,16 +381,16 @@ void AclRule::build_str()
bool prefix = false;
for ( int i = 0; i < num_pool_objects; i++ )
for (const auto& pobject: pool_objects)
{
if ( (resource & pool_objects[i]) != 0 )
if ( (resource & pobject) != 0 )
{
if ( prefix )
{
oss << "+";
}
oss << PoolObjectSQL::type_to_str( pool_objects[i] );
oss << PoolObjectSQL::type_to_str(pobject);
prefix = true;
}
}
@ -423,16 +422,16 @@ void AclRule::build_str()
prefix = false;
for ( int i = 0; i < num_auth_operations; i++ )
for (const auto &aoperation : auth_operations)
{
if ( (rights & auth_operations[i]) != 0 )
if ( (rights & aoperation) != 0 )
{
if ( prefix )
{
oss << "+";
}
oss << AuthRequest::operation_to_str( auth_operations[i] );
oss << AuthRequest::operation_to_str(aoperation);
prefix = true;
}
}

View File

@ -312,15 +312,9 @@ module CommandParser
end
def deprecated_command(name, new_command)
cmd = Hash.new
cmd[:desc] = "Deprecated, use #{new_command} instead"
cmd[:arity] = 0
cmd[:options] = []
cmd[:args_format] = [[:string, nil]] * 20
cmd = @commands[name.to_sym] || Hash.new
cmd[:desc] += "\nDeprecated, use #{new_command} instead"
cmd[:deprecated] = new_command
cmd[:proc] = lambda do
print_deprecated(new_command)
end
@commands[name.to_sym] = cmd
end
@ -800,7 +794,6 @@ module CommandParser
def print_deprecated(new_command)
puts "This command is deprecated, use instead:"
puts " $ #{File.basename $0} #{new_command}"
exit(-1)
end
def word_wrap(size, text, first_size=nil)

View File

@ -10,9 +10,9 @@
:size: 8
:right: true
:RES_VHNIUTGDCOZSvRMAPt:
:RES_VHNIUTGDCOZSvRMAPtB:
:desc: Which resource the rule applies to
:size: 22
:size: 23
:RID:
:desc: Resource ID
@ -37,7 +37,7 @@
:default:
- :ID
- :USER
- :RES_VHNIUTGDCOZSvRMAPt
- :RES_VHNIUTGDCOZSvRMAPtB
- :RID
- :OPE_UMAC
- :ZONE

View File

@ -0,0 +1,49 @@
---
:ID:
:desc: ONE identifier for Backup Job
:size: 4
:adjust: true
:USER:
:desc: Username of the Backup Job owner
:size: 8
:left: true
:GROUP:
:desc: Group of the Backup Job
:size: 8
:left: true
:PRIO:
:desc: Priority of the Backup Job
:size: 4
:left: true
:NAME:
:desc: Name of the Backup Job
:size: 15
:left: true
:expand: true
:LAST:
:desc: Date for the last backup operation
:size: 15
:left: true
:expand: true
:VMS:
:desc: VM IDs part of this backup job
:size: 15
:left: true
:expand: true
# todo Add more columns
:default:
- :ID
- :USER
- :GROUP
- :PRIO
- :NAME
- :LAST
- :VMS

View File

@ -17,6 +17,7 @@
require 'cli_helper'
require 'open3'
require 'io/console'
require 'time'
begin
require 'opennebula'
@ -440,6 +441,73 @@ module OpenNebulaHelper
:description => 'Get decrypted attributes'
}
SCHEDULE_OPTIONS=[
SCHEDULE = {
:name => 'schedule',
:large => '--schedule TIME',
:description => 'Schedules this action to be executed after' \
'the given time. For example: onevm resume 0 --schedule "09/23 14:15"',
:format => String,
:proc => lambda {|o, options|
if o[0] == '+'
options[:schedule] = o
elsif o == 'now'
options[:schedule] = Time.now.to_i
else
begin
options[:schedule] = Time.parse(o).to_i
rescue StandardError
STDERR.puts "Error parsing time spec: #{o}"
exit(-1)
end
end
}
},
WEEKLY = {
:name => 'weekly',
:large => '--weekly days',
:description => 'Repeats the schedule action the days of the week ' \
'specified, it can be a number between 0 (Sunday) to 6 (Saturday) ' \
'separated with commas. ' \
'For example: onevm resume 0 --schedule "09/23 14:15" --weekly 0,2,4',
:format => String
},
MONTHLY = {
:name => 'monthly',
:large => '--monthly days',
:description => 'Repeats the schedule action the days of the month ' \
'specified, it can be a number between 1,31 separated with commas. ' \
'For example: onevm resume 0 --schedule "09/23 14:15" --monthly 1,14',
:format => String
},
YEARLY = {
:name => 'yearly',
:large => '--yearly days',
:description => 'Repeats the schedule action the days of the year ' \
'specified, it can be a number between 0,365 separated with commas. ' \
'For example: onevm resume 0 --schedule "09/23 14:15" --yearly 30,60',
:format => String
},
HOURLY = {
:name => 'hourly',
:large => '--hourly hour',
:description => 'Repeats the schedule action with the given hourly frequency. ' \
'For example (every 5 hours): onevm resume 0 --schedule "09/23 14:15" --hourly 5',
:format => Numeric
},
END_TIME = {
:name => 'end',
:large => '--end number|TIME',
:description => '----',
:format => String
}
]
TEMPLATE_OPTIONS_VM = [TEMPLATE_NAME_VM] + TEMPLATE_OPTIONS + [DRY]
CAPACITY_OPTIONS_VM = [TEMPLATE_OPTIONS[0], TEMPLATE_OPTIONS[1],
@ -2349,4 +2417,148 @@ module OpenNebulaHelper
end
end
def self.schedule_action_tmpl(options, action, warning = nil)
str_periodic = ''
if options.key?(:weekly)
str_periodic << ", REPEAT = 0, DAYS = \"#{options[:weekly]}\""
elsif options.key?(:monthly)
str_periodic << ", REPEAT = 1, DAYS = \"#{options[:monthly]}\""
elsif options.key?(:yearly)
str_periodic << ", REPEAT = 2, DAYS = \"#{options[:yearly]}\""
elsif options.key?(:hourly)
str_periodic << ", REPEAT = 3, DAYS = \"#{options[:hourly]}\""
end
if options.key?(:end)
begin
end_date = Date.parse(options[:end])
str_periodic << ", END_TYPE = 2, END_VALUE = #{end_date.to_time.to_i}"
rescue ArgumentError
if options[:end].to_i > 0
str_periodic << ", END_TYPE = 1, END_VALUE = #{options[:end].to_i}"
end
end
elsif str_periodic != ''
str_periodic << ', END_TYPE = 0'
end
tmp_str = 'SCHED_ACTION = ['
tmp_str << "ACTION = #{action}, " if action
tmp_str << "WARNING = #{warning}," if warning
tmp_str << "ARGS = \"#{options[:args]}\"," if options[:args]
tmp_str << "TIME = #{options[:schedule]}"
tmp_str << str_periodic << ']'
tmp_str
end
def self.scheduled_action_table(object)
CLIHelper::ShowTable.new(nil, object) do
column :ID, '', :adjust => true do |d|
d['ID']
end
column :ACTION, '', :adjust => true do |d|
d['ACTION']
end
column :ARGS, '', :adjust => true do |d|
d['ARGS'] && !d['ARGS'].empty? ? d['ARGS'] : '-'
end
column :SCHEDULED, '', :adjust => true do |d|
t = d['TIME'].to_i
# relative action for VMs
if d['TIME'] !~ /^[0-9].*/ && !object['STIME'].nil?
t += object['STIME'].to_i
end
OpenNebulaHelper.time_to_str(t, false) unless d.nil?
end
column :REPEAT, '', :adjust => true do |d|
begin
str_rep = ''
case d['REPEAT']
when '0'
str_rep << 'Weekly '
when '1'
str_rep << 'Monthly '
when '2'
str_rep << 'Yearly '
when '3'
str_rep << 'Each ' << d['DAYS'] << ' hours'
end
if d['REPEAT'] != '3'
str_rep << d['DAYS']
end
str_rep
rescue StandardError
''
end
end
column :END, '', :adjust => true do |d|
begin
str_end = ''
case d['END_TYPE']
when '0'
str_end << 'None'
when '1'
str_end << 'After ' << d['END_VALUE'] << ' times'
when '2'
str_end << 'On ' << \
OpenNebulaHelper.time_to_str(d['END_VALUE'], false, false, true)
end
str_end
rescue StandardError
''
end
end
column :STATUS, '', :left, :size => 50 do |d|
begin
if d['DONE'].to_i > 0 && d['REPEAT'].to_i < 0
"Done on #{OpenNebulaHelper.time_to_str(d['DONE'], false)}"
elsif d['MESSAGE'] && !d['MESSAGE'].empty?
"Error! #{d['MESSAGE']}"
else
t1 = Time.now
t2 = d['TIME'].to_i
# relative action for VMs
if (d['TIME'] !~ /^[0-9].*/) && !object['STIME'].nil?
t2 += object['STIME'].to_i
end
t2 = Time.at(t2)
days = ((t2 - t1) / (24 * 3600)).round(2)
hours = ((t2 - t1) / 3600).round(2)
minutes = ((t2 - t1) / 60).round(2)
if days > 1
"Next in #{days} days"
elsif days <= 1 && hours > 1
"Next in #{hours} hours"
elsif minutes > 0
"Next in #{minutes} minutes"
else
'Overdue!'
end
end
rescue StandardError
''
end
end
end
end
end

View File

@ -34,7 +34,7 @@ class OneAclHelper < OpenNebulaHelper::OneHelper
def self.resource_mask(str)
resource_type=str.split('/')[0]
mask = '------------------'
mask = '-------------------'
resource_type.split('+').each do |type|
case type
@ -74,6 +74,8 @@ class OneAclHelper < OpenNebulaHelper::OneHelper
mask[16] = 'P'
when 'VNTEMPLATE'
mask[17] = 't'
when 'BACKUPJOB'
mask[18] = 'B'
end
end
mask
@ -128,9 +130,9 @@ class OneAclHelper < OpenNebulaHelper::OneHelper
d['STRING'].split(' ')[0]
end
column :RES_VHNIUTGDCOZSvRMAPt,
column :RES_VHNIUTGDCOZSvRMAPtB,
'Resource to which the rule applies',
:size => 22 do |d|
:size => 23 do |d|
OneAclHelper.resource_mask d['STRING'].split(' ')[1]
end
@ -155,7 +157,7 @@ class OneAclHelper < OpenNebulaHelper::OneHelper
d['STRING']
end
default :ID, :USER, :RES_VHNIUTGDCOZSvRMAPt, :RID, :OPE_UMAC, :ZONE
default :ID, :USER, :RES_VHNIUTGDCOZSvRMAPtB, :RID, :OPE_UMAC, :ZONE
end
end
# rubocop:enable Lint/IneffectiveAccessModifier

View File

@ -0,0 +1,284 @@
# -------------------------------------------------------------------------- #
# Copyright 2002-2023, OpenNebula Project, OpenNebula Systems #
# #
# 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 'one_helper'
# Helper for onebackupjob command
class OneBackupJobHelper < OpenNebulaHelper::OneHelper
def self.rname
'BACKUPJOB'
end
def self.conf_file
'onebackupjob.yaml'
end
TEMPLATE_OPTIONS = [
{
:name => 'name',
:large => '--name name',
:format => String,
:description => 'Name of the new backup job'
},
{
:name => 'description',
:large => '--description description',
:format => String,
:description => 'Description for the new Image'
},
{
:name => 'backup_vms',
:large => '--vms "vm_id1,vm_id2..."',
:format => String,
:description => 'List of VM IDs to backup'
},
{
:name => 'keep_last',
:large => '--keep N',
:format => String,
:description => 'Keep N backups for the VMs in this backup job'
},
{
:name => 'mode',
:large => '--mode <increment|full>',
:format => String,
:description => 'Backup mode'
}
]
def format_pool(options)
config_file = self.class.table_conf
CLIHelper::ShowTable.new(config_file, self) do
column :ID, 'ONE identifier for the Backup Job', :size=>4 do |d|
d['ID']
end
column :USER, 'Username of the Backup Job owner', :left,
:size=>15 do |d|
helper.user_name(d, options)
end
column :GROUP, 'Group of the Backup Job', :left, :size=>15 do |d|
helper.group_name(d, options)
end
column :PRIO, 'Priority of the Backup Job', :left, :size=>4 do |d|
d['PRIORITY'].to_i
end
column :NAME, 'Date for the last backup operation', :left, :size=>15 do |d|
d['NAME']
end
column :LAST, 'Date for the last backup operation', :size => 15 do |d|
begin
btime = d['LAST_BACKUP_TIME'].to_i
rescue StandardError
btime = 0
end
OpenNebulaHelper.time_to_str(btime, false, true, true)
end
column :VMS, 'VM IDs part of this backup job', :size => 15 do |d|
begin
vm = d['TEMPLATE']['BACKUP_VMS']
vm[12..-1]='...' if vm.size > 15
vm
rescue StandardError
'-'
end
end
default :ID, :USER, :GROUP, :PRIO, :NAME, :LAST, :VMS
end
end
def schedule_actions(ids, options, warning = nil)
# Verbose by default
options[:verbose] = true
message = if options[:schedule].class == Integer
"backup scheduled at #{Time.at(options[:schedule])}"
else
"backup scheduled after #{options[:schedule]}s"
end
tmp_str = OpenNebulaHelper.schedule_action_tmpl(options, nil, warning)
perform_actions(ids, options, message) do |bj|
rc = bj.sched_action_add(tmp_str)
if OpenNebula.is_error?(rc)
STDERR.puts rc.message
exit(-1)
end
end
end
# Update schedule action
#
# @param id [Integer] BackupJob ID
# @param action_id [Integer] Sched action ID
# @param file [String] File path with update content
# @param options
def update_schedule_action(id, action_id, file, options)
perform_action(id, options, 'Sched action updated') do |bj|
rc = bj.info
if OpenNebula.is_error?(rc)
STDERR.puts "Error #{rc.message}"
exit(-1)
end
xpath = "TEMPLATE/SCHED_ACTION[ID=#{action_id}]"
unless bj.retrieve_elements(xpath)
STDERR.puts "Sched action #{action_id} not found"
exit(-1)
end
# Get user information
if file
str = File.read(file)
else
str = OpenNebulaHelper.update_template(id, bj, nil, xpath)
end
# Add the modified sched action
tmp_str = "\nSCHED_ACTION = ["
tmp_str << str.split("\n").join(',')
tmp_str << ']'
rc = bj.sched_action_update(action_id, tmp_str)
if OpenNebula.is_error?(rc)
STDERR.puts "Error updating: #{rc.message}"
exit(-1)
end
end
end
def self.create_backupjob_template(options)
template_options = TEMPLATE_OPTIONS.map do |o|
o[:name].to_sym
end
template_options << :name
t = ''
template_options.each do |n|
t << "#{n.to_s.upcase}=\"#{options[n]}\"\n" if options[n]
end
t
end
private
def factory(id = nil)
if id
OpenNebula::BackupJob.new_with_id(id, @client)
else
xml=OpenNebula::BackupJob.build_xml
OpenNebula::BackupJob.new(xml, @client)
end
end
def factory_pool(user_flag = -2)
OpenNebula::BackupJobPool.new(@client, user_flag)
end
def format_resource(bj, options = {})
bj_hash = bj.to_hash
str='%-15s: %-20s'
str_h1='%-80s'
# ----------------------------------------------------------------------
CLIHelper.print_header(
str_h1 % "BACKUP JOB #{bj['ID']} INFORMATION"
)
# ----------------------------------------------------------------------
puts format(str, 'ID', bj.id.to_s)
puts format(str, 'NAME', bj.name)
puts format(str, 'USER', bj['UNAME'])
puts format(str, 'GROUP', bj['GNAME'])
puts format(str, 'LOCK', OpenNebulaHelper.level_lock_to_str(bj['LOCK/LOCKED']))
CLIHelper.print_header(str_h1 % 'PERMISSIONS', false)
['OWNER', 'GROUP', 'OTHER'].each do |e|
mask = '---'
mask[0] = 'u' if bj["PERMISSIONS/#{e}_U"] == '1'
mask[1] = 'm' if bj["PERMISSIONS/#{e}_M"] == '1'
mask[2] = 'a' if bj["PERMISSIONS/#{e}_A"] == '1'
puts format(str, e, mask)
end
puts
# ----------------------------------------------------------------------
CLIHelper.print_header(
str_h1 % 'LAST BACKUP JOB EXECUTION INFORMATION'
)
# ----------------------------------------------------------------------
puts format(str, 'TIME', OpenNebulaHelper.time_to_str(bj['LAST_BACKUP_TIME']))
puts format(str, 'DURATION', OpenNebulaHelper.period_to_str(bj['LAST_BACKUP_DURATION']))
puts
# ----------------------------------------------------------------------
CLIHelper.print_header(
str_h1 % 'VIRTUAL MACHINE BACKUP STATUS'
)
# ----------------------------------------------------------------------
up = bj.retrieve_elements('UPDATED_VMS/ID')
out = bj.retrieve_elements('OUTDATED_VMS/ID')
act = bj.retrieve_elements('BACKING_UP_VMS/ID')
err = bj.retrieve_elements('ERROR_VMS/ID')
up = [] if up.nil?
out = [] if out.nil?
act = [] if act.nil?
err = [] if err.nil?
puts format(str, 'UPDATED', up.join(','))
puts format(str, 'OUTDATED', out.join(','))
puts format(str, 'ONGOING', act.join(','))
puts format(str, 'ERROR', err.join(','))
if bj.has_elements?('/BACKUPJOB/TEMPLATE/SCHED_ACTION')
puts
CLIHelper.print_header(str_h1 % 'SCHEDULED ACTIONS', false)
table = OpenNebulaHelper.scheduled_action_table(self)
table.show([bj_hash['BACKUPJOB']['TEMPLATE']['SCHED_ACTION']].flatten, {})
end
if !options[:all]
bj.delete_element('/BACKUPJOB/TEMPLATE/SCHED_ACTION')
end
puts
# ----------------------------------------------------------------------
CLIHelper.print_header(str_h1 % 'TEMPLATE CONTENTS', false)
# ----------------------------------------------------------------------
puts bj.template_str
end
end

View File

@ -112,72 +112,6 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
:description => 'Creates the new VM on hold state instead of pending'
}
SCHEDULE = {
:name => 'schedule',
:large => '--schedule TIME',
:description => 'Schedules this action to be executed after' \
'the given time. For example: onevm resume 0 --schedule "09/23 14:15"',
:format => String,
:proc => lambda {|o, options|
if o[0] == '+'
options[:schedule] = o
elsif o == 'now'
options[:schedule] = Time.now.to_i
else
begin
options[:schedule] = Time.parse(o).to_i
rescue StandardError
STDERR.puts "Error parsing time spec: #{o}"
exit(-1)
end
end
}
}
WEEKLY = {
:name => 'weekly',
:large => '--weekly days',
:description => 'Repeats the schedule action the days of the week ' \
'specified, it can be a number between 0 (Sunday) to 6 (Saturday) ' \
'separated with commas. ' \
'For example: onevm resume 0 --schedule "09/23 14:15" --weekly 0,2,4',
:format => String
}
MONTHLY = {
:name => 'monthly',
:large => '--monthly days',
:description => 'Repeats the schedule action the days of the month ' \
'specified, it can be a number between 1,31 separated with commas. ' \
'For example: onevm resume 0 --schedule "09/23 14:15" --monthly 1,14',
:format => String
}
YEARLY = {
:name => 'yearly',
:large => '--yearly days',
:description => 'Repeats the schedule action the days of the year ' \
'specified, it can be a number between 0,365 separated with commas. ' \
'For example: onevm resume 0 --schedule "09/23 14:15" --yearly 30,60',
:format => String
}
HOURLY = {
:name => 'hourly',
:large => '--hourly hour',
:description => 'Repeats the schedule action each hours specified,' \
'it can be a number between 0,168 separated with commas. ' \
'For example: onevm resume 0 --schedule "09/23 14:15" --hourly 1,5',
:format => Numeric
}
END_TIME = {
:name => 'end',
:large => '--end number|TIME',
:description => '----',
:format => String
}
ALL_TEMPLATE = {
:name => 'all',
:large => '--all',
@ -426,41 +360,9 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
"#{action} scheduled after #{options[:schedule]}s from start"
end
perform_actions(ids, options, message) do |vm|
str_periodic = ''
if options.key?(:weekly)
str_periodic << ", REPEAT = 0, DAYS = \"#{options[:weekly]}\""
elsif options.key?(:monthly)
str_periodic << ", REPEAT = 1, DAYS = \"#{options[:monthly]}\""
elsif options.key?(:yearly)
str_periodic << ", REPEAT = 2, DAYS = \"#{options[:yearly]}\""
elsif options.key?(:hourly)
str_periodic << ", REPEAT = 3, DAYS = \"#{options[:hourly]}\""
end
if options.key?(:end)
begin
end_date = Date.parse(options[:end])
str_periodic << ', END_TYPE = 2, ' \
"END_VALUE = #{end_date.to_time.to_i}"
rescue ArgumentError
if options[:end].to_i > 0
str_periodic << ', END_TYPE = 1, ' \
"END_VALUE = #{options[:end].to_i}"
end
end
elsif str_periodic != ''
str_periodic << ', END_TYPE = 0'
end
tmp_str = 'SCHED_ACTION = ['
tmp_str << "ACTION = #{action}, "
tmp_str << "WARNING = #{warning}," if warning
tmp_str << "ARGS = \"#{options[:args]}\"," if options[:args]
tmp_str << "TIME = #{options[:schedule]}"
tmp_str << str_periodic << ']'
tmp_str = OpenNebulaHelper.schedule_action_tmpl(options, action, warning)
perform_actions( ids, options, message) do |vm|
rc = vm.sched_action_add(tmp_str)
if OpenNebula.is_error?(rc)
@ -475,8 +377,9 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
# @param vm_id [Integer] Virtual Machine ID
# @param action_id [Integer] Sched action ID
# @param file [String] File path with update content
def update_schedule_action(vm_id, action_id, file)
perform_action(vm_id, {}, 'Sched action updated') do |vm|
# @param options
def update_schedule_action(vm_id, action_id, file, options)
perform_action(vm_id, options, 'Sched action updated') do |vm|
rc = vm.info
if OpenNebula.is_error?(rc)
@ -1290,92 +1193,8 @@ class OneVMHelper < OpenNebulaHelper::OneHelper
puts
CLIHelper.print_header(str_h1 % 'SCHEDULED ACTIONS', false)
CLIHelper::ShowTable.new(nil, self) do
column :ID, '', :adjust => true do |d|
d['ID'] unless d.nil?
end
column :ACTION, '', :adjust => true do |d|
d['ACTION'] unless d.nil?
end
column :ARGS, '', :adjust => true do |d|
d['ARGS'] ? d['ARGS'] : '-'
end
column :SCHEDULED, '', :adjust => true do |d|
t2 = d['TIME'].to_i
t2 += vm['STIME'].to_i unless d['TIME'] =~ /^[0-9].*/
OpenNebulaHelper.time_to_str(t2, false) \
unless d.nil?
end
column :REPEAT, '', :adjust => true do |d|
str_rep = ''
if !d.nil? && d.key?('REPEAT')
case d['REPEAT']
when '0'
str_rep << 'Weekly '
when '1'
str_rep << 'Monthly '
when '2'
str_rep << 'Yearly '
when '3'
str_rep << 'Each ' << d['DAYS'] << ' hours'
end
if d['REPEAT'] != '3'
str_rep << d['DAYS']
end
end
str_rep unless d.nil?
end
column :END, '', :adjust => true do |d|
str_end = ''
if !d.nil? && d.key?('END_TYPE')
case d['END_TYPE']
when '0'
str_end << 'None'
when '1'
str_end << 'After ' << d['END_VALUE'] << ' times'
when '2'
str_end << 'On ' << \
OpenNebulaHelper.time_to_str(d['END_VALUE'], false, false, true)
end
end
str_end unless d.nil?
end
column :STATUS, '', :left, :size => 50 do |d|
if d['DONE'] && !d['REPEAT']
"Done on #{OpenNebulaHelper.time_to_str(d['DONE'], false)}"
elsif d['MESSAGE']
"Error! #{d['MESSAGE']}"
else
t1 = Time.now
t2 = d['TIME'].to_i
t2 += vm['STIME'].to_i unless d['TIME'] =~ /^[0-9].*/
t2 = Time.at(t2)
days = ((t2 - t1) / (24 * 3600)).round(2)
hours = ((t2 - t1) / 3600).round(2)
minutes = ((t2 - t1) / 60).round(2)
if days > 1
"Next in #{days} days"
elsif days <= 1 && hours > 1
"Next in #{hours} hours"
elsif minutes > 0
"Next in #{minutes} minutes"
else
'Overdue!'
end
end
end
end.show([vm_hash['VM']['TEMPLATE']['SCHED_ACTION']].flatten,
{})
table = OpenNebulaHelper.scheduled_action_table(self)
table.show([vm_hash['VM']['TEMPLATE']['SCHED_ACTION']].flatten, {})
end
if !options[:all]

369
src/cli/onebackupjob Executable file
View File

@ -0,0 +1,369 @@
#!/usr/bin/env ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2023, OpenNebula Project, OpenNebula Systems #
# #
# 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'
GEMS_LOCATION = '/usr/share/one/gems'
else
RUBY_LIB_LOCATION = ONE_LOCATION + '/lib/ruby'
GEMS_LOCATION = ONE_LOCATION + '/share/gems'
end
# %%RUBYGEMS_SETUP_BEGIN%%
if File.directory?(GEMS_LOCATION)
real_gems_path = File.realpath(GEMS_LOCATION)
if !defined?(Gem) || Gem.path != [real_gems_path]
$LOAD_PATH.reject! {|l| l =~ /vendor_ruby/ }
# Suppress warnings from Rubygems
# https://github.com/OpenNebula/one/issues/5379
begin
verb = $VERBOSE
$VERBOSE = nil
require 'rubygems'
Gem.use_paths(real_gems_path)
ensure
$VERBOSE = verb
end
end
end
# %%RUBYGEMS_SETUP_END%%
$LOAD_PATH << RUBY_LIB_LOCATION
$LOAD_PATH << RUBY_LIB_LOCATION + '/cli'
require 'tempfile'
require 'command_parser'
require 'one_helper/onebackupjob_helper'
CommandParser::CmdParser.new(ARGV) do
usage '`onebackupjob` <command> [<args>] [<options>]'
version OpenNebulaHelper::ONE_VERSION
helper = OneBackupJobHelper.new
before_proc do
helper.set_client(options)
end
USE = {
:name => 'use',
:large => '--use',
:description => 'lock use actions'
}
MANAGE = {
:name => 'manage',
:large => '--manage',
:description => 'lock manage actions'
}
ADMIN = {
:name => 'admin',
:large => '--admin',
:description => 'lock admin actions'
}
ALL = {
:name => 'all',
:large => '--all',
:description => 'lock all actions'
}
########################################################################
# Global Options
########################################################################
set :option, CommandParser::OPTIONS + OpenNebulaHelper::CLIENT_OPTIONS
list_options = CLIHelper::OPTIONS
list_options += OpenNebulaHelper::FORMAT
list_options << OpenNebulaHelper::NUMERIC
list_options << OpenNebulaHelper::DESCRIBE
########################################################################
# Formatters for arguments
########################################################################
set :format, :groupid, OpenNebulaHelper.rname_to_id_desc('GROUP') do |arg|
OpenNebulaHelper.rname_to_id(arg, 'GROUP')
end
set :format, :userid, OpenNebulaHelper.rname_to_id_desc('USER') do |arg|
OpenNebulaHelper.rname_to_id(arg, 'USER')
end
set :format, :backupjobid, OneBackupJobHelper.to_id_desc do |arg|
helper.to_id(arg)
end
set :format, :backupjobid_list, OneBackupJobHelper.list_to_id_desc do |arg|
helper.list_to_id(arg)
end
set :format, :filterflag, OneBackupJobHelper.filterflag_to_i_desc do |arg|
helper.filterflag_to_i(arg)
end
########################################################################
# Commands
########################################################################
create_desc = <<-EOT.unindent
Creates a new Backup Job
Examples:
- using a template description file:
onebackupjob create centOS.tmpl
EOT
command :create,
create_desc,
[:file, nil],
:options => [OpenNebulaHelper::SCHEDULE_OPTIONS] +
OneBackupJobHelper::TEMPLATE_OPTIONS do
rc = nil
helper.create_resource(options) do |bj|
begin
if args[0]
template = File.read(args[0])
else
template = OneBackupJobHelper.create_backupjob_template(options)
end
rc = bj.allocate(template)
rescue StandardError => e
STDERR.puts e.message
exit(-1)
end
if OpenNebula.is_error?(rc)
puts rc.message
exit(-1)
end
helper.schedule_actions([bj.id], options) unless options[:schedule].nil?
end
end
delete_desc = <<-EOT.unindent
Deletes the given Backup Job
EOT
command :delete, delete_desc, [:range, :backupjobid_list] do
helper.perform_actions(args[0], options, 'deleting') do |bj|
bj.delete
end
end
update_desc = <<-EOT.unindent
Update the Backup Job contents. If a path is not provided the editor will
be launched to modify the current content.
EOT
command :update, update_desc, :backupjobid, [:file, nil] do
helper.perform_action(args[0], options, 'modified') do |obj|
if args[1]
str = File.read(args[1])
else
rc = obj.info
if OpenNebula.is_error?(rc)
puts rc.message
exit(-1)
end
obj.delete_element('TEMPLATE/SCHED_ACTION')
str = OpenNebulaHelper.editor_input(obj.template_like_str('TEMPLATE'))
end
obj.update(str)
end
end
chgrp_desc = <<-EOT.unindent
Changes the Backup Job group
EOT
command :chgrp, chgrp_desc, [:range, :backupjobid_list], :groupid do
helper.perform_actions(args[0], options, 'Group changed') do |bj|
bj.chown(-1, args[1].to_i)
end
end
chown_desc = <<-EOT.unindent
Changes the Backup Job owner and group
EOT
command :chown, chown_desc, [:range, :backupjobid_list], :userid,
[:groupid, nil] do
args[2].nil? ? gid = -1 : gid = args[2].to_i
helper.perform_actions(args[0], options,
'Owner/Group changed') do |bj|
bj.chown(args[1].to_i, gid)
end
end
chmod_desc = <<-EOT.unindent
Changes the BackupJob permissions
EOT
command :chmod, chmod_desc, [:range, :backupjobid_list], :octet do
helper.perform_actions(args[0], options,
'Permissions changed') do |bj|
bj.chmod_octet(OpenNebulaHelper.to_octet(args[1]))
end
end
rename_desc = <<-EOT.unindent
Renames the Backup Job
EOT
command :rename, rename_desc, :backupjobid, :name do
helper.perform_action(args[0], options, 'renamed') do |bj|
bj.rename(args[1])
end
end
list_desc = <<-EOT.unindent
Lists Backup Jobs in the pool
EOT
command :list, list_desc, [:filterflag, nil], :options => list_options do
helper.list_pool(options, false, args[0])
end
show_desc = <<-EOT.unindent
Shows information for the given Backup Job
EOT
command :show, show_desc, :backupjobid,
:options => [OpenNebulaHelper::FORMAT] do
helper.show_resource(args[0], options)
end
lock_desc = <<-EOT.unindent
Locks an Backup Job to prevent certain actions defined by different levels.
The show action will never be locked.
Levels:
[Use]: locks Admin, Manage and Use actions.
[Manage]: locks Manage and Use actions.
[Admin]: locks only Admin actions.
EOT
command :lock, lock_desc, [:range, :backupjobid_list],
:options => [USE, MANAGE, ADMIN, ALL] do
helper.perform_actions(args[0], options, 'Backup Job locked') do |bj|
if !options[:use].nil?
level = 1
elsif !options[:manage].nil?
level = 2
elsif !options[:admin].nil?
level = 3
elsif !options[:all].nil?
level = 4
else
level = 1
end
bj.lock(level)
end
end
unlock_desc = <<-EOT.unindent
Unlocks an Backup Job.
EOT
command :unlock, unlock_desc, [:range, :backupjobid_list] do
helper.perform_actions(args[0], options, 'Backup Job unlocked') do |bj|
bj.unlock
end
end
backup_desc = <<-EOT.unindent
Start the Backup Job execution.
EOT
command :backup, backup_desc, [:range, :backupjobid_list],
:options => OpenNebulaHelper::SCHEDULE_OPTIONS do
if !options[:schedule].nil?
helper.schedule_actions(args[0], options)
else
helper.perform_actions(args[0], options, 'Starting Backups') do |bj|
bj.backup
end
end
end
cancel_desc = <<-EOT.unindent
Cancel pending Backup Job, removing Virtual Machines from the waiting list
EOT
command :cancel, cancel_desc, [:range, :backupjobid_list] do
helper.perform_actions(args[0], options, 'Backups canceled') do |bj|
bj.cancel
end
end
retry_desc = <<-EOT.unindent
Retry failed Backup Job. Trigger backup on Virtual Machines from error list.
EOT
command :retry, retry_desc, [:range, :backupjobid_list] do
helper.perform_actions(args[0], options,
'Retrying backups for failed Virtual Machines') do |bj|
bj.retry
end
end
priority_desc = <<-EOT.unindent
Change the priority of the Backup Job. Only oneadmin may increase priority over 50.
EOT
command :priority, priority_desc, [:range, :backupjobid_list], :priority do
helper.perform_actions(args[0], options, 'Priority changed') do |bj|
bj.priority(args[1].to_i)
end
end
sched_delete_desc = <<-EOT.unindent
Remove Scheduled Action from Backup Job.
EOT
command :"sched-delete", sched_delete_desc, :bjid, :schedid do
schedid = args[1]
helper.perform_action(args[0], options, 'Scheduled Action deleted') do |bj|
bj.sched_action_delete(schedid)
end
end
sched_update_desc = <<-EOT.unindent
Start the Backup Job execution.
EOT
command :"sched-update", sched_update_desc, :bjid, :schedid,
[:file, nil] do
bj_id = args[0]
sched_id = args[1]
file = args[2]
helper.update_schedule_action(bj_id, sched_id, file, options)
end
end

View File

@ -422,12 +422,7 @@ CommandParser::CmdParser.new(ARGV) do
EOT
command :hold, hold_desc, [:range, :vmid_list],
:options => [OneVMHelper::SCHEDULE,
OneVMHelper::WEEKLY,
OneVMHelper::MONTHLY,
OneVMHelper::YEARLY,
OneVMHelper::HOURLY,
OneVMHelper::END_TIME] do
:options => OpenNebulaHelper::SCHEDULE_OPTIONS do
if !options[:schedule].nil?
helper.schedule_actions(args[0], options, @comm_name)
else
@ -444,12 +439,7 @@ CommandParser::CmdParser.new(ARGV) do
EOT
command :release, release_desc, [:range, :vmid_list],
:options => [OneVMHelper::SCHEDULE,
OneVMHelper::WEEKLY,
OneVMHelper::MONTHLY,
OneVMHelper::YEARLY,
OneVMHelper::HOURLY,
OneVMHelper::END_TIME] do
:options => OpenNebulaHelper::SCHEDULE_OPTIONS do
if !options[:schedule].nil?
helper.schedule_actions(args[0], options, @comm_name)
else
@ -512,13 +502,8 @@ CommandParser::CmdParser.new(ARGV) do
EOT
command :terminate, terminate_desc, [:range, :vmid_list],
:options => [OneVMHelper::SCHEDULE,
OneVMHelper::WEEKLY,
OneVMHelper::MONTHLY,
OneVMHelper::YEARLY,
OneVMHelper::HOURLY,
OneVMHelper::END_TIME,
OneVMHelper::HARD] do
:options => OpenNebulaHelper::SCHEDULE_OPTIONS +
[OneVMHelper::HARD] do
command_name = 'terminate'
command_name << '-hard' if options[:hard]
@ -540,13 +525,8 @@ CommandParser::CmdParser.new(ARGV) do
EOT
command :undeploy, undeploy_desc, [:range, :vmid_list],
:options => [OneVMHelper::SCHEDULE,
OneVMHelper::WEEKLY,
OneVMHelper::MONTHLY,
OneVMHelper::YEARLY,
OneVMHelper::HOURLY,
OneVMHelper::END_TIME,
OneVMHelper::HARD] do
:options => OpenNebulaHelper::SCHEDULE_OPTIONS +
[OneVMHelper::HARD] do
command_name = 'undeploy'
command_name << '-hard' if options[:hard]
@ -567,13 +547,8 @@ CommandParser::CmdParser.new(ARGV) do
EOT
command :poweroff, poweroff_desc, [:range, :vmid_list],
:options => [OneVMHelper::SCHEDULE,
OneVMHelper::WEEKLY,
OneVMHelper::MONTHLY,
OneVMHelper::YEARLY,
OneVMHelper::HOURLY,
OneVMHelper::END_TIME,
OneVMHelper::HARD] do
:options => OpenNebulaHelper::SCHEDULE_OPTIONS +
[OneVMHelper::HARD] do
command_name = 'poweroff'
command_name << '-hard' if options[:hard]
@ -596,13 +571,8 @@ CommandParser::CmdParser.new(ARGV) do
EOT
command :reboot, reboot_desc, [:range, :vmid_list],
:options => [OneVMHelper::SCHEDULE,
OneVMHelper::WEEKLY,
OneVMHelper::MONTHLY,
OneVMHelper::YEARLY,
OneVMHelper::HOURLY,
OneVMHelper::END_TIME,
OneVMHelper::HARD] do
:options => OpenNebulaHelper::SCHEDULE_OPTIONS +
[OneVMHelper::HARD] do
command_name = 'reboot'
command_name << '-hard' if options[:hard]
@ -680,12 +650,7 @@ CommandParser::CmdParser.new(ARGV) do
EOT
command :stop, stop_desc, [:range, :vmid_list],
:options => [OneVMHelper::SCHEDULE,
OneVMHelper::WEEKLY,
OneVMHelper::MONTHLY,
OneVMHelper::YEARLY,
OneVMHelper::HOURLY,
OneVMHelper::END_TIME] do
:options => OpenNebulaHelper::SCHEDULE_OPTIONS do
if !options[:schedule].nil?
helper.schedule_actions(args[0], options, @comm_name)
else
@ -705,12 +670,7 @@ CommandParser::CmdParser.new(ARGV) do
EOT
command :suspend, suspend_desc, [:range, :vmid_list],
:options => [OneVMHelper::SCHEDULE,
OneVMHelper::WEEKLY,
OneVMHelper::MONTHLY,
OneVMHelper::YEARLY,
OneVMHelper::HOURLY,
OneVMHelper::END_TIME] do
:options => OpenNebulaHelper::SCHEDULE_OPTIONS do
if !options[:schedule].nil?
helper.schedule_actions(args[0], options, @comm_name)
else
@ -727,12 +687,7 @@ CommandParser::CmdParser.new(ARGV) do
EOT
command :resume, resume_desc, [:range, :vmid_list],
:options => [OneVMHelper::SCHEDULE,
OneVMHelper::WEEKLY,
OneVMHelper::MONTHLY,
OneVMHelper::YEARLY,
OneVMHelper::HOURLY,
OneVMHelper::END_TIME] do
:options => OpenNebulaHelper::SCHEDULE_OPTIONS do
if !options[:schedule].nil?
helper.schedule_actions(args[0], options, @comm_name)
else
@ -1084,12 +1039,7 @@ CommandParser::CmdParser.new(ARGV) do
EOT
command :"snapshot-create", snapshot_create_desc, [:range, :vmid_list],
[:name, nil], :options => [OneVMHelper::SCHEDULE,
OneVMHelper::WEEKLY,
OneVMHelper::MONTHLY,
OneVMHelper::YEARLY,
OneVMHelper::HOURLY,
OneVMHelper::END_TIME] do
[:name, nil], :options => OpenNebulaHelper::SCHEDULE_OPTIONS do
if !options[:schedule].nil?
# add name as an argument
options[:args] = args[1]
@ -1108,12 +1058,7 @@ CommandParser::CmdParser.new(ARGV) do
EOT
command :"snapshot-revert", snapshot_revert_desc, :vmid, :snapshot_id,
:options => [OneVMHelper::SCHEDULE,
OneVMHelper::WEEKLY,
OneVMHelper::MONTHLY,
OneVMHelper::YEARLY,
OneVMHelper::HOURLY,
OneVMHelper::END_TIME] do
:options => OpenNebulaHelper::SCHEDULE_OPTIONS do
if !options[:schedule].nil?
# add snap ID as an argument
options[:args] = args[1]
@ -1132,12 +1077,7 @@ CommandParser::CmdParser.new(ARGV) do
EOT
command :"snapshot-delete", snapshot_delete_desc, :vmid, :snapshot_id,
:options => [OneVMHelper::SCHEDULE,
OneVMHelper::WEEKLY,
OneVMHelper::MONTHLY,
OneVMHelper::YEARLY,
OneVMHelper::HOURLY,
OneVMHelper::END_TIME] do
:options => OpenNebulaHelper::SCHEDULE_OPTIONS do
if !options[:schedule].nil?
# add snap ID as an argument
options[:args] = args[1]
@ -1159,12 +1099,7 @@ CommandParser::CmdParser.new(ARGV) do
command :"disk-snapshot-create", disk_snapshot_create_desc,
:vmid, :diskid, :name,
:options => [OneVMHelper::SCHEDULE,
OneVMHelper::WEEKLY,
OneVMHelper::MONTHLY,
OneVMHelper::YEARLY,
OneVMHelper::HOURLY,
OneVMHelper::END_TIME] do
:options => OpenNebulaHelper::SCHEDULE_OPTIONS do
if !options[:schedule].nil?
# add disk ID and name as arguments
options[:args] = "#{args[1]},#{args[2]}"
@ -1186,12 +1121,7 @@ CommandParser::CmdParser.new(ARGV) do
command :"disk-snapshot-revert", disk_snapshot_revert_desc,
:vmid, :diskid, :disk_snapshot_id,
:options => [OneVMHelper::SCHEDULE,
OneVMHelper::WEEKLY,
OneVMHelper::MONTHLY,
OneVMHelper::YEARLY,
OneVMHelper::HOURLY,
OneVMHelper::END_TIME] do
:options => OpenNebulaHelper::SCHEDULE_OPTIONS do
if !options[:schedule].nil?
# add disk ID and snap ID as arguments
options[:args] = "#{args[1]},#{args[2]}"
@ -1213,12 +1143,7 @@ CommandParser::CmdParser.new(ARGV) do
command :"disk-snapshot-delete", disk_snapshot_delete_desc,
:vmid, :diskid, :disk_snapshot_id,
:options => [OneVMHelper::SCHEDULE,
OneVMHelper::WEEKLY,
OneVMHelper::MONTHLY,
OneVMHelper::YEARLY,
OneVMHelper::HOURLY,
OneVMHelper::END_TIME] do
:options => OpenNebulaHelper::SCHEDULE_OPTIONS do
if !options[:schedule].nil?
# add disk ID and snap ID as arguments
options[:args] = "#{args[1]},#{args[2]}"
@ -1548,7 +1473,38 @@ CommandParser::CmdParser.new(ARGV) do
:vmid,
:sched_id,
[:file, nil] do
helper.update_schedule_action(args[0], args[1], args[2])
helper.update_schedule_action(args[0], args[1], args[2], options)
0
end
sched_delete_desc = <<-EOT.unindent
Deletes a Scheduled Action from the VM
EOT
command :'sched-delete', sched_delete_desc, :vmid, :sched_id do
helper.perform_action(args[0], {}, 'Scheduled Action deleted') do |vm|
rc = vm.sched_action_delete(args[1])
if OpenNebula.is_error?(rc)
STDERR.puts "Error deleting: #{rc.message}"
exit(-1)
end
end
0
end
sched_update_desc = <<-EOT.unindent
Updates a Scheduled Action from a VM
EOT
command :'sched-update',
sched_update_desc,
:vmid,
:sched_id,
[:file, nil] do
helper.update_schedule_action(args[0], args[1], args[2], options)
0
end
@ -1563,19 +1519,14 @@ CommandParser::CmdParser.new(ARGV) do
backup_vm_desc,
:vmid,
:options => [RESET_BACKUP,
OneDatastoreHelper::DATASTORE,
OneVMHelper::SCHEDULE,
OneVMHelper::WEEKLY,
OneVMHelper::MONTHLY,
OneVMHelper::YEARLY,
OneVMHelper::HOURLY,
OneVMHelper::END_TIME] do
OneDatastoreHelper::DATASTORE] +
OpenNebulaHelper::SCHEDULE_OPTIONS do
options[:datastore] = -1 if options[:datastore].nil?
reset = options[:reset] == true
if !options[:schedule].nil?
options[:args] = options[:datastore]
options[:args] = "#{options[:datastore]},#{reset ? 1 : 0}"
helper.schedule_actions([args[0]], options, @comm_name)
else
@ -1713,8 +1664,8 @@ CommandParser::CmdParser.new(ARGV) do
end
end
# Deprecated commands
# Deprecated commands, remove these commands in release 8.x
deprecated_command(:shutdown, 'terminate')
deprecated_command(:delete, 'recover')
deprecated_command(:'delete-chart', 'sched-delete')
deprecated_command(:'update-chart', 'sched-update')
end

View File

@ -463,4 +463,20 @@ string one_util::uuid()
<< setw(4) << random<short uint>();
return oss.str();
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
template <>
bool one_util::str_cast(const std::string& str, std::string& value)
{
if (str.empty())
{
return false;
}
value = str;
return true;
}

View File

@ -19,6 +19,7 @@
#include "Quotas.h"
#include "Nebula.h"
#include "VirtualMachinePool.h"
#include "ScheduledActionPool.h"
using namespace std;
@ -271,14 +272,37 @@ void DispatchManager::trigger_done(int vid)
(lcm_state == VirtualMachine::EPILOG ||
lcm_state == VirtualMachine::CLEANUP_DELETE))
{
string error;
int rc = 0;
std::set<int> sa_ids(vm->sched_actions().get_collection());
free_vm_resources(std::move(vm), true);
auto sapool = Nebula::instance().get_sapool();
for (const auto& id: sa_ids)
{
if (auto sa = sapool->get(id))
{
rc += sapool->drop(sa.get(), error);
}
}
if ( rc != 0 )
{
ostringstream oss;
oss << "Some schedules for VM " << vid << " could not be removed";
NebulaLog::log("DiM", Log::ERROR, oss);
}
}
else
{
ostringstream oss;
oss << "done action received but VM " << vid << " not in ACTIVE state";
NebulaLog::log("DiM",Log::ERROR,oss);
NebulaLog::log("DiM", Log::ERROR, oss);
}
});
}

View File

@ -375,7 +375,7 @@ void Group::add_admin_rules(int user_id)
NebulaLog::log("GROUP",Log::ERROR,error_msg);
}
// #<uid> VM+NET+IMAGE+TEMPLATE+DOCUMENT+SECGROUP+VROUTER+VMGROUP/@<gid> USE+MANAGE *
// #<uid> VM+NET+IMAGE+TEMPLATE+DOCUMENT+SECGROUP+VROUTER+VMGROUP+BACKUPJOB/@<gid> USE+MANAGE *
if ( aclm->add_rule(
AclRule::INDIVIDUAL_ID |
user_id,
@ -388,6 +388,7 @@ void Group::add_admin_rules(int user_id)
PoolObjectSQL::SECGROUP |
PoolObjectSQL::VROUTER |
PoolObjectSQL::VMGROUP |
PoolObjectSQL::BACKUPJOB |
AclRule::GROUP_ID |
oid,

View File

@ -49,6 +49,7 @@ void LifeCycleManager::init_managers()
sgpool = nd.get_secgrouppool();
clpool = nd.get_clpool();
vnpool = nd.get_vnpool();
bjpool = nd.get_bjpool();
}
/* -------------------------------------------------------------------------- */

View File

@ -23,6 +23,7 @@
#include "VirtualMachineManager.h"
#include "ImageManager.h"
#include "Quotas.h"
#include "BackupJobPool.h"
#include "ClusterPool.h"
#include "HostPool.h"
#include "ImagePool.h"
@ -2768,6 +2769,7 @@ void LifeCycleManager::trigger_backup_success(int vid)
auto& backups = vm->backups();
int ds_id = backups.last_datastore_id();
int bj_id = backups.backup_job_id();
int incremental_id = backups.incremental_backup_id();
int keep_last = backups.keep_last();
@ -2958,6 +2960,16 @@ void LifeCycleManager::trigger_backup_success(int vid)
Quotas::ds_del(vm_uid, vm_gid, &ds_deltas);
/* ------------------------------------------------------------------ */
/* Remove VM from Backup Job pending list */
/* ------------------------------------------------------------------ */
if (auto bj = bjpool->get(bj_id))
{
bj->backup_finished(vid, true);
bjpool->update(bj.get());
}
return;
error_increment_update:
@ -2984,7 +2996,7 @@ void LifeCycleManager::trigger_backup_success(int vid)
void LifeCycleManager::trigger_backup_failure(int vid)
{
trigger([this, vid] {
int vm_uid{0}, vm_gid{0};
int vm_uid{0}, vm_gid{0}, bj_id{-1};
Template ds_deltas;
if ( auto vm = vmpool->get(vid) )
@ -3008,8 +3020,10 @@ void LifeCycleManager::trigger_backup_failure(int vid)
vm_uid = vm->get_uid();
vm_gid = vm->get_gid();
int incremental_id = vm->backups().incremental_backup_id();
Backups::Mode mode = vm->backups().mode();
auto& backups = vm->backups();
int incremental_id = backups.incremental_backup_id();
Backups::Mode mode = backups.mode();
bj_id = backups.backup_job_id();
vm->backup_size(ds_deltas);
ds_deltas.add("DATASTORE", vm->backups().last_datastore_id());
@ -3019,13 +3033,23 @@ void LifeCycleManager::trigger_backup_failure(int vid)
ds_deltas.add("IMAGES", 1);
}
vm->backups().last_backup_clear();
backups.last_backup_clear();
vmpool->update(vm.get());
}
// Quota rollback
Quotas::ds_del(vm_uid, vm_gid, &ds_deltas);
/* Remove VM from Backup Job pending list */
/* ------------------------------------------------------------------ */
if (auto bj = bjpool->get(bj_id))
{
bj->backup_finished(vid, false);
// todo Add failure to BJ?
bjpool->update(bj.get());
}
});
}

View File

@ -24,6 +24,7 @@
#include "LogDB.h"
#include "SystemDB.h"
#include "BackupJobPool.h"
#include "ClusterPool.h"
#include "DatastorePool.h"
#include "DocumentPool.h"
@ -33,6 +34,7 @@
#include "ImagePool.h"
#include "MarketPlacePool.h"
#include "MarketPlaceAppPool.h"
#include "ScheduledActionPool.h"
#include "SecurityGroupPool.h"
#include "UserPool.h"
#include "VdcPool.h"
@ -57,6 +59,7 @@
#include "MarketPlaceManager.h"
#include "RaftManager.h"
#include "RequestManager.h"
#include "ScheduledActionManager.h"
#include "TransferManager.h"
#include "VirtualMachineManager.h"
@ -116,11 +119,14 @@ Nebula::~Nebula()
delete ipamm;
delete raftm;
delete frm;
delete sam;
delete logdb;
delete fed_logdb;
delete system_db;
delete vntpool;
delete hkpool;
delete bjpool;
delete sapool;
};
/* -------------------------------------------------------------------------- */
@ -520,6 +526,8 @@ void Nebula::start(bool bootstrap_only)
rc += VNTemplatePool::bootstrap(logdb);
rc += HookPool::bootstrap(logdb);
rc += HookLog::bootstrap(logdb);
rc += BackupJobPool::bootstrap(logdb);
rc += ScheduledActionPool::bootstrap(logdb);
// Create the system tables only if bootstrap went well
if (rc == 0)
@ -797,6 +805,10 @@ void Nebula::start(bool bootstrap_only)
hkpool = new HookPool(logdb);
bjpool = new BackupJobPool(logdb);
sapool = new ScheduledActionPool(logdb);
default_user_quota.select();
default_group_quota.select();
@ -1010,9 +1022,9 @@ void Nebula::start(bool bootstrap_only)
}
}
// ---- Image Manager ----
if (!cache)
{
// ---- Image Manager ----
vector<const VectorAttribute *> image_mads;
nebula_configuration->get("DATASTORE_MAD", image_mads);
@ -1085,6 +1097,18 @@ void Nebula::start(bool bootstrap_only)
}
}
// ---- Scheduled Action Manager ----
if (!cache)
{
int max_backups;
int max_backups_host;
nebula_configuration->get("MAX_BACKUPS", max_backups);
nebula_configuration->get("MAX_BACKUPS_HOST", max_backups_host);
// todo Read settings from Scheduler config file
sam = new ScheduledActionManager(timer_period, max_backups, max_backups_host);
}
// -----------------------------------------------------------
// Load mads
// -----------------------------------------------------------
@ -1185,6 +1209,8 @@ void Nebula::start(bool bootstrap_only)
if (!cache)
{
sam->finalize();
vmm->finalize();
lcm->finalize();

View File

@ -71,6 +71,7 @@ env.Prepend(LIBS=[
'nebula_ipamm',
'nebula_vmgroup',
'nebula_protocol',
'nebula_sam',
'crypto',
'xml2'
])

View File

@ -0,0 +1,213 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2023, OpenNebula Project, OpenNebula Systems */
/* */
/* 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. */
/*--------------------------------------------------------------------------- */
package goca
import (
"encoding/xml"
"errors"
"github.com/OpenNebula/one/src/oca/go/src/goca/schemas/backupjob"
"github.com/OpenNebula/one/src/oca/go/src/goca/schemas/shared"
)
// BackupJobsController is a controller for Backup Jobs
type BackupJobsController entitiesController
// BackupJobController is a controller for Backup Job entities
type BackupJobController entityController
// BackupJobs returns an BackupJobs controller
func (c *Controller) BackupJobs() *BackupJobsController {
return &BackupJobsController{c}
}
// BackupJob returns an Backup Job controller
func (c *Controller) BackupJob(id int) *BackupJobController {
return &BackupJobController{c, id}
}
// ByName returns an Backup Job ID from name
func (c *BackupJobsController) ByName(name string, args ...int) (int, error) {
var id int
bjPool, err := c.Info(args...)
if err != nil {
return -1, err
}
match := false
for i := 0; i < len(bjPool.BackupJobs); i++ {
if bjPool.BackupJobs[i].Name != name {
continue
}
if match {
return -1, errors.New("multiple resources with that name")
}
id = bjPool.BackupJobs[i].ID
match = true
}
if !match {
return -1, errors.New("resource not found")
}
return id, nil
}
// Info returns a new Backup Job pool. It accepts the scope of the query.
func (bjc *BackupJobsController) Info(args ...int) (*backupjob.Pool, error) {
fArgs, err := handleArgs(args)
if err != nil {
return nil, err
}
response, err := bjc.c.Client.Call("one.backupjobpool.info", fArgs...)
if err != nil {
return nil, err
}
bjPool := &backupjob.Pool{}
err = xml.Unmarshal([]byte(response.Body()), bjPool)
if err != nil {
return nil, err
}
return bjPool, nil
}
// Info connects to OpenNebula and fetches the information of the Backup Job
func (bjc *BackupJobController) Info() (*backupjob.BackupJob, error) {
response, err := bjc.c.Client.Call("one.backupjob.info", bjc.ID)
if err != nil {
return nil, err
}
bj := &backupjob.BackupJob{}
err = xml.Unmarshal([]byte(response.Body()), bj)
if err != nil {
return nil, err
}
return bj, nil
}
// Create allocates a new Backup Job based on the template string provided. It
// returns the Backup Job ID.
func (bjc *BackupJobsController) Create(template string) (int, error) {
response, err := bjc.c.Client.Call("one.backupjob.allocate", template)
if err != nil {
return -1, err
}
return response.BodyInt(), nil
}
// Update adds Backup Job content.
// * tpl: The new Backup Job content. Syntax can be the usual attribute=value or XML.
func (bjc *BackupJobController) Update(tpl string) error {
_, err := bjc.c.Client.Call("one.backupjob.update", bjc.ID, tpl)
return err
}
// Chown changes the owner/group of the Backup Job. If uid or gid is -1 it will not
// change
func (bjc *BackupJobController) Chown(uid, gid int) error {
_, err := bjc.c.Client.Call("one.backupjob.chown", bjc.ID, uid, gid)
return err
}
// Chmod changes the permissions of the Backup Job. If any perm is -1 it will not
// change
func (bjc *BackupJobController) Chmod(perm shared.Permissions) error {
args := append([]interface{}{bjc.ID}, perm.ToArgs()...)
_, err := bjc.c.Client.Call("one.backupjob.chmod", args...)
return err
}
// Rename changes the name of the image
func (bjc *BackupJobController) Rename(newName string) error {
_, err := bjc.c.Client.Call("one.backupjob.rename", bjc.ID, newName)
return err
}
// Lock locks the Backup Job following lock level. See levels in locks.go.
func (bjc *BackupJobController) Lock(level shared.LockLevel) error {
_, err := bjc.c.Client.Call("one.backupjob.lock", bjc.ID, level)
return err
}
// Unlock unlocks the BackupJob.
func (bjc *BackupJobController) Unlock() error {
_, err := bjc.c.Client.Call("one.backupjob.unlock", bjc.ID)
return err
}
// Delete will remove the Backup Job from OpenNebula, which will remove it from the
// backend.
func (bjc *BackupJobController) Delete() error {
_, err := bjc.c.Client.Call("one.backupjob.delete", bjc.ID)
return err
}
// Backup runs the Backup Job
func (bjc *BackupJobController) Backup() error {
_, err := bjc.c.Client.Call("one.backupjob.backup", bjc.ID)
return err
}
// Cancel ongoing Backup Job execution
func (bjc *BackupJobController) Cancel() error {
_, err := bjc.c.Client.Call("one.backupjob.cancel", bjc.ID)
return err
}
// Retry backup for failed Virtual Machine
func (bjc *BackupJobController) Retry() error {
_, err := bjc.c.Client.Call("one.backupjob.retry", bjc.ID)
return err
}
// Set priority for Backup Job, only admin can set priority over 50
func (bjc *BackupJobController) Priority(prio int) error {
_, err := bjc.c.Client.Call("one.backupjob.priority", bjc.ID, prio)
return err
}
// SchedAdd creates a new Scheduled Action for the Backup Job
func (bjc *BackupJobController) SchedAdd(description string) (int, error) {
response, err := bjc.c.Client.Call("one.backupjob.schedadd", bjc.ID, description)
if err != nil {
return -1, err
}
return response.BodyInt(), err
}
// SchedUpdate updates a Scheduled Action for the Backup Job
func (bjc *BackupJobController) SchedUpdate(saID int, description string) (int, error) {
response, err := bjc.c.Client.Call("one.backupjob.schedupdate", bjc.ID, saID, description)
if err != nil {
return -1, err
}
return response.BodyInt(), err
}
// SchedDelete deletes a Scheduled Action
func (bjc *BackupJobController) SchedDelete(saID int) error {
_, err := bjc.c.Client.Call("one.backupjob.scheddelete", bjc.ID, saID)
return err
}

View File

@ -0,0 +1,224 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2023, OpenNebula Project, OpenNebula Systems */
/* */
/* 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. */
/*--------------------------------------------------------------------------- */
package goca
import (
"github.com/OpenNebula/one/src/oca/go/src/goca/schemas/backupjob/keys"
"github.com/OpenNebula/one/src/oca/go/src/goca/schemas/shared"
. "gopkg.in/check.v1"
)
type BJSuite struct {
bjID int
}
var _ = Suite(&BJSuite{})
func (s *BJSuite) SetUpTest(c *C) {
// Create Backup Job
bjTpl := `
NAME = "test-backupjob"
BACKUP_VMS = "1,2,3"`
id, err := testCtrl.BackupJobs().Create(bjTpl)
c.Assert(err, IsNil)
s.bjID = id
}
func (s *BJSuite) TearDownTest(c *C) {
// Delete Backup Job
bjC := testCtrl.BackupJob(s.bjID)
bjC.Delete()
}
func (s *BJSuite) TestGetByNameAndID(c *C) {
// Get Backup Job by ID
bj, err := testCtrl.BackupJob(s.bjID).Info()
c.Assert(err, IsNil)
c.Assert(bj.ID, Equals, s.bjID)
// Test value from Backup Job template
vms, err := bj.Template.Get(keys.BackupVMs)
c.Assert(err, IsNil)
c.Assert(vms, Equals, "1,2,3")
// Get Backup Job by Name
id, err := testCtrl.BackupJobs().ByName(bj.Name)
c.Assert(err, IsNil)
c.Assert(bj.ID, Equals, id)
}
func (s *BJSuite) TestUpdate(c *C) {
bjC := testCtrl.BackupJob(s.bjID)
err := bjC.Update(`BACKUP_VMS = "1,2,3,4"`)
c.Assert(err, IsNil)
bj, err := testCtrl.BackupJob(s.bjID).Info()
c.Assert(err, IsNil)
vms, err := bj.Template.Get(keys.BackupVMs)
c.Assert(err, IsNil)
c.Assert(vms, Equals, "1,2,3,4")
}
func (s *BJSuite) TestRename(c *C) {
bjC := testCtrl.BackupJob(s.bjID)
bjC.Rename("new_name")
bj, err := testCtrl.BackupJob(s.bjID).Info()
c.Assert(err, IsNil)
c.Assert(bj.Name, Equals, "new_name");
}
func (s *BJSuite) TestChown(c *C) {
// Test only if the call exists, no real change
bjC := testCtrl.BackupJob(s.bjID)
err := bjC.Chown(1, 1)
c.Assert(err, IsNil)
}
func (s *BJSuite) TestChmod(c *C) {
new_permissions := shared.Permissions{1, 1, 1, 1, 1, 1, 1, 1, 1}
bjC := testCtrl.BackupJob(s.bjID)
err := bjC.Chmod(new_permissions)
c.Assert(err, IsNil)
bj, err := bjC.Info()
c.Assert(err, IsNil)
c.Assert(*bj.Permissions, Equals, new_permissions);
}
func (s *BJSuite) TestLock(c *C) {
// Lock
bjC := testCtrl.BackupJob(s.bjID)
err := bjC.Lock(shared.LockUse)
c.Assert(err, IsNil)
bj, err := bjC.Info()
c.Assert(err, IsNil)
c.Assert(bj.LockInfos.Locked, Equals, 1);
// Unlock
err = bjC.Unlock()
c.Assert(err, IsNil)
bj, err = bjC.Info()
c.Assert(err, IsNil)
c.Assert(bj.LockInfos, IsNil)
}
func (s *BJSuite) TestBackup(c *C) {
// Test only if the call exists, no real change
bjC := testCtrl.BackupJob(s.bjID)
err := bjC.Backup()
c.Assert(err, IsNil)
}
func (s *BJSuite) TestCancel(c *C) {
// Test only if the call exists, no real change
bjC := testCtrl.BackupJob(s.bjID)
err := bjC.Cancel()
c.Assert(err, IsNil)
}
func (s *BJSuite) TestRetry(c *C) {
// Test only if the call exists, no real change
bjC := testCtrl.BackupJob(s.bjID)
err := bjC.Retry()
c.Assert(err, IsNil)
}
func (s *BJSuite) TestPriority(c *C) {
bjC := testCtrl.BackupJob(s.bjID)
err := bjC.Priority(20)
c.Assert(err, IsNil)
bj, err := bjC.Info()
c.Assert(err, IsNil)
c.Assert(bj.Priority, Equals, 20)
}
func (s *BJSuite) TestScheduledAction(c *C) {
// Create Scheduled Action
sa_tmpl := `SCHED_ACTION = [
REPEAT = "3",
DAYS = "1",
TIME = "1695478500" ]`
bjC := testCtrl.BackupJob(s.bjID)
saID, err := bjC.SchedAdd(sa_tmpl)
c.Assert(err, IsNil)
// Read Scheduled Action
bj, err := bjC.Info()
c.Assert(err, IsNil)
sched_actions := bj.Template.GetSchedActions()
c.Assert(len(sched_actions), Equals, 1)
days, err := sched_actions[0].Get(keys.Days)
c.Assert(err, IsNil)
c.Assert(days, Equals, "1")
// Update Scheduled Action
sa_update := `SCHED_ACTION = [ DAYS = "5" ]`
_, err = bjC.SchedUpdate(saID, sa_update)
c.Assert(err, IsNil)
// Read updated value
bj, err = bjC.Info()
c.Assert(err, IsNil)
sched_actions = bj.Template.GetSchedActions()
c.Assert(len(sched_actions), Equals, 1)
days, err = sched_actions[0].Get(keys.Days)
c.Assert(err, IsNil)
c.Assert(days, Equals, "5")
// Delete Scheduled Action
err = bjC.SchedDelete(saID)
c.Assert(err, IsNil)
// Test it doesn't exists
bj, err = bjC.Info()
c.Assert(err, IsNil)
sched_actions = bj.Template.GetSchedActions()
c.Assert(len(sched_actions), Equals, 0)
}

View File

@ -0,0 +1,50 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2023, OpenNebula Project, OpenNebula Systems */
/* */
/* 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. */
/*--------------------------------------------------------------------------- */
package backupjob
import (
"encoding/xml"
"github.com/OpenNebula/one/src/oca/go/src/goca/schemas/shared"
)
// Pool represents an OpenNebula Backup Job pool
type Pool struct {
XMLName xml.Name `xml:"BACKUPJOB_POOL"`
BackupJobs []BackupJob `xml:"BACKUPJOB"`
}
// BackupJob represents an OpenNebula Backup Job
type BackupJob struct {
XMLName xml.Name `xml:"BACKUPJOB"`
ID int `xml:"ID,omitempty"`
UID int `xml:"UID,omitempty"`
GID int `xml:"GID,omitempty"`
UName string `xml:"UNAME,omitempty"`
GName string `xml:"GNAME,omitempty"`
Name string `xml:"NAME"`
LockInfos *shared.Lock `xml:"LOCK,omitempty"`
Permissions *shared.Permissions `xml:"PERMISSIONS,omitempty"`
Priority int `xml:"PRIORITY,omitempty"`
LastBackupTime int `xml:"LAST_BACKUP_TIME,omitempty"`
LastBackupDuration int `xml:"LAST_BACKUP_DURATION,omitempty"`
UpdatedVMs shared.EntitiesID `xml:"UPDATED_VMS,omitempty"`
OutdatedVMs shared.EntitiesID `xml:"OUTDATED_VMS,omitempty"`
BackingUpVMs shared.EntitiesID `xml:"BACKING_UP_VMS,omitempty"`
ErrorVMs shared.EntitiesID `xml:"ERROR_VMS,omitempty"`
Template Template `xml:"TEMPLATE"`
}

View File

@ -0,0 +1,47 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2023, OpenNebula Project, OpenNebula Systems */
/* */
/* 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. */
/*--------------------------------------------------------------------------- */
package keys
// Template is a type used to enumerate Backup Job template keys
type Template string
const (
Name Template = "NAME"
KeepLast Template = "KEEP_LAST"
BackupVolatile Template = "BACKUP_VOLATILE"
FsFreeze Template = "FS_FREEZE"
Mode Template = "MODE"
BackupVMs Template = "BACKUP_VMS"
DatastoreId Template = "DATASTORE_ID"
Execution Template = "EXECUTION"
)
// SchedAction define keys for scheduled action
type SchedAction string
const (
SchedActionVec string = "SCHED_ACTION"
Time SchedAction = "TIME"
Repeat SchedAction = "REPEAT"
Days SchedAction = "DAYS"
Action SchedAction = "ACTION"
EndType SchedAction = "END_TYPE"
EndValue SchedAction = "END_VALUE"
ActionID SchedAction = "ID"
ParentID SchedAction = "PARENT_ID"
)

View File

@ -0,0 +1,77 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2023, OpenNebula Project, OpenNebula Systems */
/* */
/* 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. */
/*--------------------------------------------------------------------------- */
package backupjob
import (
dyn "github.com/OpenNebula/one/src/oca/go/src/goca/dynamic"
"github.com/OpenNebula/one/src/oca/go/src/goca/schemas/backupjob/keys"
)
// Template is the dynamic part of the Backup Job entity
type Template struct {
dyn.Template
}
// NewTemplate returns an image template
func NewTemplate() *Template {
return &Template{
dyn.Template{},
}
}
// Get return the string value of a template Backup Job key
func (t *Template) Get(key keys.Template) (string, error) {
return t.GetStr(string(key))
}
// GetI returns the integer value for an Backup Job template key
func (n *Template) GetI(key keys.Template) (int, error) {
return n.GetInt(string(key))
}
// Add adds an Backup Job template key, value pair
func (t *Template) Add(key keys.Template, value interface{}) {
t.AddPair(string(key), value)
}
type SchedAction struct {
dyn.Vector
}
// Add adds a SchedAction key, value pair
func (t *SchedAction) Add(key keys.SchedAction, value interface{}) {
t.AddPair(string(key), value)
}
// Get retrieve a SchedAction key
func (t *SchedAction) Get(key keys.SchedAction) (string, error) {
return t.GetStr(string(key))
}
// GetSchedActions allow to get Scheduled Actions from Template
func (t *Template) GetSchedActions() []SchedAction {
vecs := t.GetVectors(string(keys.SchedActionVec))
shed_actions := make([]SchedAction, len(vecs))
for i, v := range vecs {
shed_actions[i] = SchedAction{*v}
}
return shed_actions
}

View File

@ -0,0 +1,72 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2023, OpenNebula Project, OpenNebula Systems */
/* */
/* 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. */
/*--------------------------------------------------------------------------- */
package shared
import (
"encoding/xml"
dyn "github.com/OpenNebula/one/src/oca/go/src/goca/dynamic"
)
// SchedAction is a scheduled action on VM
type SchedAction struct {
dyn.Vector
}
// SchedAction define keys for scheduled action
type SchedActionKeys string
const (
SchedActionVec string = "SCHED_ACTION"
ActionID SchedActionKeys = "ID"
ParentID SchedActionKeys = "PARENT_ID"
Action SchedActionKeys = "ACTION"
Time SchedActionKeys = "TIME"
Repeat SchedActionKeys = "REPEAT"
Days SchedActionKeys = "DAYS"
EndType SchedActionKeys = "END_TYPE"
EndValue SchedActionKeys = "END_VALUE"
Done SchedActionKeys = "DONE"
)
// AddSchedAction returns a Scheduled Action structure
func NewSchedAction() *SchedAction {
return &SchedAction{
dyn.Vector{XMLName: xml.Name{Local: SchedActionVec}},
}
}
// Add adds a key, value pair to Scheduled Action
func (sa *SchedAction) Add(key SchedActionKeys, value interface{}) {
sa.AddPair(string(key), value)
}
// ID returns the Scheduled Action ID as an integer
func (sa *SchedAction) ID() (int, error) {
return sa.GetInt(string(ActionID))
}
// Get return the string value for Scheduled Action key
func (t *SchedAction) Get(key SchedActionKeys) (string, error) {
return t.GetStr(string(key))
}
// GetI returns the integer value for a disk key
func (d *SchedAction) GetI(key SchedActionKeys) (int, error) {
return d.GetInt(string(key))
}

View File

@ -167,4 +167,5 @@ const (
EndType SchedAction = "END_TYPE"
EndValue SchedAction = "END_VALUE"
ActionID SchedAction = "ID"
ParentID SchedAction = "PARENT_ID"
)

View File

@ -0,0 +1,545 @@
/*******************************************************************************
* Copyright 2002-2023, OpenNebula Project, OpenNebula Systems
*
* 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.
******************************************************************************/
package org.opennebula.client.backupjob;
import org.opennebula.client.Client;
import org.opennebula.client.OneResponse;
import org.opennebula.client.PoolElement;
import org.w3c.dom.Node;
/**
* This class represents an OpenNebula Backup Job.
* It also offers static XML-RPC call wrappers.
*/
public class BackupJob extends PoolElement
{
private static final String METHOD_PREFIX = "backupjob.";
private static final String ALLOCATE = METHOD_PREFIX + "allocate";
private static final String DELETE = METHOD_PREFIX + "delete";
private static final String UPDATE = METHOD_PREFIX + "update";
private static final String RENAME = METHOD_PREFIX + "rename";
private static final String INFO = METHOD_PREFIX + "info";
private static final String CHOWN = METHOD_PREFIX + "chown";
private static final String CHMOD = METHOD_PREFIX + "chmod";
private static final String LOCK = METHOD_PREFIX + "lock";
private static final String UNLOCK = METHOD_PREFIX + "unlock";
private static final String BACKUP = METHOD_PREFIX + "backup";
private static final String CANCEL = METHOD_PREFIX + "cancel";
private static final String RETRY = METHOD_PREFIX + "retry";
private static final String PRIORITY = METHOD_PREFIX + "priority";
private static final String SCHEDADD = METHOD_PREFIX + "schedadd";
private static final String SCHEDDELETE = METHOD_PREFIX + "scheddelete";
private static final String SCHEDUPDATE = METHOD_PREFIX + "schedupdate";
/**
* Creates a new Backup Job representation.
* @param id The Backup Job id.
* @param client XML-RPC Client.
*/
public BackupJob(int id, Client client)
{
super(id, client);
}
/**
* @see PoolElement
*/
protected BackupJob(Node xmlElement, Client client)
{
super(xmlElement, client);
}
// =================================
// Static XML-RPC methods
// =================================
/**
* Allocates a new BackupJob in OpenNebula.
*
* @param client XML-RPC Client.
* @param description A string containing the template of the Backup Job.
*
* @return If successful the message contains the associated
* ID generated for this Backup Job.
*/
public static OneResponse allocate(
Client client,
String description)
{
return client.call(ALLOCATE, description);
}
/**
* Deletes an Backup Job from OpenNebula.
*
* @param client XML-RPC Client.
* @param id The Backup Job ID we want to delete.
* @return An encapsulated response.
*/
public static OneResponse delete(Client client, int id)
{
return client.call(DELETE, id);
}
/**
* Retrieves the information of the given Backup JOb.
*
* @param client XML-RPC Client.
* @param id The Backup Job ID
* @return If successful the message contains the string
* with the information returned by OpenNebula.
*/
public static OneResponse info(Client client, int id)
{
return client.call(INFO, id);
}
/**
* Replaces the template contents.
*
* @param client XML-RPC Client.
* @param id The Backkup Job ID we want to modify.
* @param new_template New template contents
* @return If successful the message contains the Backup Job ID.
*/
public static OneResponse update(Client client, int id, String new_template)
{
return client.call(UPDATE, id, new_template);
}
/**
* Renames Backup Job
*
* @param client XML-RPC Client.
* @param id The Backup Job ID.
* @param name New name for the Backup Job.
* @return If an error occurs the error message contains the reason.
*/
public static OneResponse rename(Client client, int id, String name)
{
return client.call(RENAME, id, name);
}
/**
* Changes the owner/group
*
* @param client XML-RPC Client.
* @param id The Backup Job ID we want to modify.
* @param uid The new owner user ID. Set it to -1 to leave the current one.
* @param gid The new group ID. Set it to -1 to leave the current one.
* @return If an error occurs the error message contains the reason.
*/
public static OneResponse chown(Client client, int id, int uid, int gid)
{
return client.call(CHOWN, id, uid, gid);
}
/**
* Changes the Backup Job permissions
*
* @param client XML-RPC Client.
* @param id The Backup Job ID we want to modify.
* @param owner_u 1 to allow, 0 deny, -1 do not change
* @param owner_m 1 to allow, 0 deny, -1 do not change
* @param owner_a 1 to allow, 0 deny, -1 do not change
* @param group_u 1 to allow, 0 deny, -1 do not change
* @param group_m 1 to allow, 0 deny, -1 do not change
* @param group_a 1 to allow, 0 deny, -1 do not change
* @param other_u 1 to allow, 0 deny, -1 do not change
* @param other_m 1 to allow, 0 deny, -1 do not change
* @param other_a 1 to allow, 0 deny, -1 do not change
* @return If an error occurs the error message contains the reason.
*/
public static OneResponse chmod(Client client, int id,
int owner_u, int owner_m, int owner_a,
int group_u, int group_m, int group_a,
int other_u, int other_m, int other_a)
{
return chmod(client, CHMOD, id,
owner_u, owner_m, owner_a,
group_u, group_m, group_a,
other_u, other_m, other_a);
}
/**
* Changes the permissions
*
* @param client XML-RPC Client.
* @param id The Backup Job ID of the target object.
* @param octet Permissions octed , e.g. 640
* @return If an error occurs the error message contains the reason.
*/
public static OneResponse chmod(Client client, int id, String octet)
{
return chmod(client, CHMOD, id, octet);
}
/**
* Changes the permissions
*
* @param client XML-RPC Client.
* @param id The Backup Job ID of the target object.
* @param octet Permissions octed , e.g. 640
* @return If an error occurs the error message contains the reason.
*/
public static OneResponse chmod(Client client, int id, int octet)
{
return chmod(client, CHMOD, id, octet);
}
/**
* Lock Backup Job
*
* @param client XML-RPC Client.
* @param id The Backup Job ID.
* @param level Lock level.
* @return If an error occurs the error message contains the reason.
*/
public static OneResponse lock(Client client, int id, int level)
{
return client.call(LOCK, id, level);
}
/**
* Unlock Backup Job
*
* @param client XML-RPC Client.
* @param id The Backup Job ID.
* @return If an error occurs the error message contains the reason.
*/
public static OneResponse unlock(Client client, int id)
{
return client.call(UNLOCK, id);
}
/**
* Execute the Backup Job
*
* @param client XML-RPC Client.
* @param id The Backup Job ID.
* @return If an error occurs the error message contains the reason.
*/
public static OneResponse backup(Client client, int id)
{
return client.call(BACKUP, id);
}
/**
* Cancel ongoing Backup Job
*
* @param client XML-RPC Client.
* @param id The Backup Job ID.
* @return If an error occurs the error message contains the reason.
*/
public static OneResponse cancel(Client client, int id)
{
return client.call(CANCEL, id);
}
/**
* Retry failed Backup Job, executes again backup for failed Virtual Machines
*
* @param client XML-RPC Client.
* @param id The Backup Job ID.
* @return If an error occurs the error message contains the reason.
*/
public static OneResponse retry(Client client, int id)
{
return client.call(RETRY, id);
}
/**
* Set priority for Backup Job, range for priority is 0-100.
* Base value is 50, only admin user can set priority over 50
*
* @param client XML-RPC Client.
* @param id The Backup Job ID.
* @param priority New value for priority
* @return If an error occurs the error message contains the reason.
*/
public static OneResponse priority(Client client, int id, int prio)
{
return client.call(PRIORITY, id, prio);
}
/**
* Add Scheduled Action to Backup Job
*
* @param client XML-RPC Client.
* @param id The Backup Job ID.
* @param template Scheduled Action template.
* @return If an error occurs the error message contains the reason.
*/
public static OneResponse schedadd(Client client, int id, String template)
{
return client.call(SCHEDADD, id, template);
}
/**
* Update Backup Job Scheduled Action
*
* @param client XML-RPC Client.
* @param id The Backup Job ID.
* @param sa_id The Scheduled Action ID.
* @param template Updated values for Scheduled Action.
* @return If an error occurs the error message contains the reason.
*/
public static OneResponse schedupdate(Client client, int id, int sa_id, String template)
{
return client.call(SCHEDUPDATE, id, sa_id, template);
}
/**
* Delete Backup Job Scheduled Action
*
* @param client XML-RPC Client.
* @param id The Backup Job ID.
* @param sa_id The Scheduled Action ID.
* @return If an error occurs the error message contains the reason.
*/
public static OneResponse scheddelete(Client client, int id, int sa_id)
{
return client.call(SCHEDDELETE, id, sa_id);
}
// =================================
// Instanced object XML-RPC methods
// =================================
/**
* Retrieves the information of the Backup Job.
*
* @return If successful the message contains the string
* with the information returned by OpenNebula.
*/
public OneResponse info()
{
OneResponse response = info(client, id);
super.processInfo(response);
return response;
}
/**
* Deletes the Backup Job from OpenNebula.
*
* @param force Ignore errors
* @return A encapsulated response.
*/
public OneResponse delete()
{
return delete(client, id);
}
/**
* Replaces the template contents.
*
* @param new_template New template contents
* @return If successful the message contains the Backup Job ID.
*/
public OneResponse update(String new_template)
{
return update(client, id, new_template);
}
/**
* Renames this Backup Job
*
* @param name New name for the Backup Job.
* @return If an error occurs the error message contains the reason.
*/
public OneResponse rename(String name)
{
return rename(client, id, name);
}
/**
* Changes the owner/group
*
* @param uid The new owner user ID. Set it to -1 to leave the current one.
* @param gid The new group ID. Set it to -1 to leave the current one.
* @return If an error occurs the error message contains the reason.
*/
public OneResponse chown(int uid, int gid)
{
return chown(client, id, uid, gid);
}
/**
* Changes the owner
*
* @param uid The new owner user ID.
* @return If an error occurs the error message contains the reason.
*/
public OneResponse chown(int uid)
{
return chown(uid, -1);
}
/**
* Changes the group
*
* @param gid The new group ID.
* @return If an error occurs the error message contains the reason.
*/
public OneResponse chgrp(int gid)
{
return chown(-1, gid);
}
/**
* Changes the Backup Job permissions
*
* @param owner_u 1 to allow, 0 deny, -1 do not change
* @param owner_m 1 to allow, 0 deny, -1 do not change
* @param owner_a 1 to allow, 0 deny, -1 do not change
* @param group_u 1 to allow, 0 deny, -1 do not change
* @param group_m 1 to allow, 0 deny, -1 do not change
* @param group_a 1 to allow, 0 deny, -1 do not change
* @param other_u 1 to allow, 0 deny, -1 do not change
* @param other_m 1 to allow, 0 deny, -1 do not change
* @param other_a 1 to allow, 0 deny, -1 do not change
* @return If an error occurs the error message contains the reason.
*/
public OneResponse chmod(int owner_u, int owner_m, int owner_a,
int group_u, int group_m, int group_a,
int other_u, int other_m, int other_a)
{
return chmod(client, id,
owner_u, owner_m, owner_a,
group_u, group_m, group_a,
other_u, other_m, other_a);
}
/**
* Changes the permissions
*
* @param octet Permissions octed , e.g. 640
* @return If an error occurs the error message contains the reason.
*/
public OneResponse chmod(String octet)
{
return chmod(client, id, octet);
}
/**
* Changes the permissions
*
* @param octet Permissions octed , e.g. 640
* @return If an error occurs the error message contains the reason.
*/
public OneResponse chmod(int octet)
{
return chmod(client, id, octet);
}
/**
* Lock this Backup Job
*
* @param level Lock level.
* @return If an error occurs the error message contains the reason.
*/
public OneResponse lock(int level)
{
return lock(client, id, level);
}
/**
* Unlock this Backup Job
*
* @return If an error occurs the error message contains the reason.
*/
public OneResponse unlock()
{
return unlock(client, id);
}
/**
* Execute the Backup Job
*
* @return If an error occurs the error message contains the reason.
*/
public OneResponse backup()
{
return backup(client, id);
}
/**
* Cancel ongoing Backup Job
*
* @return If an error occurs the error message contains the reason.
*/
public OneResponse cancel()
{
return cancel(client, id);
}
/**
* Retry failed Backup Job, executes again backup for failed Virtual Machines
*
* @return If an error occurs the error message contains the reason.
*/
public OneResponse retry()
{
return retry(client, id);
}
/**
* Set priority for Backup Job, range for priority is 0-100.
* Base value is 50, only admin user can set priority over 50
*
* @param priority New value for priority
* @return If an error occurs the error message contains the reason.
*/
public OneResponse priority(int prio)
{
return priority(client, id, prio);
}
/**
* Add Scheduled Action to Backup Job
*
* @param template Scheduled Action template.
* @return If an error occurs the error message contains the reason.
*/
public OneResponse schedadd(String template)
{
return schedadd(client, id, template);
}
/**
* Update Backup Job Scheduled Action
*
* @param sa_id The Scheduled Action ID.
* @param template Updated values for Scheduled Action.
* @return If an error occurs the error message contains the reason.
*/
public OneResponse schedupdate(int sa_id, String template)
{
return schedupdate(client, id, sa_id, template);
}
/**
* Delete Backup Job Scheduled Action
*
* @param sa_id The Scheduled Action ID.
* @return If an error occurs the error message contains the reason.
*/
public OneResponse scheddelete(int sa_id)
{
return scheddelete(client, id, sa_id);
}
}

View File

@ -0,0 +1,267 @@
/*******************************************************************************
* Copyright 2002-2023, OpenNebula Project, OpenNebula Systems
*
* 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.
******************************************************************************/
package org.opennebula.client.backupjob;
import java.util.AbstractList;
import java.util.Iterator;
import org.opennebula.client.Client;
import org.opennebula.client.OneResponse;
import org.opennebula.client.Pool;
import org.opennebula.client.PoolElement;
import org.w3c.dom.Node;
/**
* This class represents an OpenNebula Backup Job pool.
* It also offers static XML-RPC call wrappers.
*/
public class BackupJobPool extends Pool implements Iterable<BackupJob>
{
private static final String ELEMENT_NAME = "BACKUPJOB";
private static final String INFO_METHOD = "backupjobpool.info";
private int filter;
/**
* Creates a new Backup Job pool with the default filter flag value
* set to {@link Pool#MINE_GROUP} (Backup Jobs belonging to the connected user,
* and the ones in his group)
*
* @param client XML-RPC Client.
*
* @see BackupJobPool#BackupJobPool(Client, int)
*/
public BackupJobPool(Client client)
{
super(ELEMENT_NAME, client, INFO_METHOD);
this.filter = MINE_GROUP;
}
/**
* Creates a new Backup Job pool.
*
* @param client XML-RPC Client.
* @param filter Filter flag to use by default in the method
* {@link BackupJobPool#info()}. Possible values:
* <ul>
* <li>{@link Pool#ALL}: All Backup Jobs</li>
* <li>{@link Pool#MINE}: Connected user's Backup Jobs</li>
* <li>{@link Pool#MINE_GROUP}: Connected user's Backup Jobs, and the ones in
* his group</li>
* <li>{@link Pool#GROUP}: User's primary group Backup Jobs</li>
* <li>&gt;= 0 UID User's Backup Jobs</li>
* </ul>
*/
public BackupJobPool(Client client, int filter)
{
super(ELEMENT_NAME, client, INFO_METHOD);
this.filter = filter;
}
/* (non-Javadoc)
* @see org.opennebula.client.Pool#factory(org.w3c.dom.Node)
*/
@Override
public PoolElement factory(Node node)
{
return new BackupJob(node, client);
}
/**
* Retrieves all or part of the Backup Jobs in the pool.
*
* @param client XML-RPC Client.
* @param filter Filter flag to use. Possible values:
* <ul>
* <li>{@link Pool#ALL}: All Backup JObs</li>
* <li>{@link Pool#MINE}: Connected user's Backup Jobs</li>
* <li>{@link Pool#MINE_GROUP}: Connected user's Backup Jobs, and the ones in
* his group</li>
* <li>{@link Pool#GROUP}: User's primary group Backup Jobs</li>
* <li>&gt;= 0 UID User's Backup Jobs</li>
* </ul>
* @return If successful the message contains the string
* with the information returned by OpenNebula.
*/
public static OneResponse info(Client client, int filter)
{
return Pool.info(client, INFO_METHOD, filter, -1, -1);
}
/**
* Retrieves all the Backup Jobs in the pool.
*
* @param client XML-RPC Client.
* @return If successful the message contains the string
* with the information returned by OpenNebula.
*/
public static OneResponse infoAll(Client client)
{
return Pool.infoAll(client, INFO_METHOD);
}
/**
* Retrieves all the connected user's Backup Jobs.
*
* @param client XML-RPC Client.
* @return If successful the message contains the string
* with the information returned by OpenNebula.
*/
public static OneResponse infoMine(Client client)
{
return Pool.infoMine(client, INFO_METHOD);
}
/**
* Retrieves all the connected user's Backup Jobs and the ones in
* his group.
*
* @param client XML-RPC Client.
* @return If successful the message contains the string
* with the information returned by OpenNebula.
*/
public static OneResponse infoGroup(Client client)
{
return Pool.infoGroup(client, INFO_METHOD);
}
/**
* Retrieves all or part of the Backup Jobs in the pool. The Backup Jobs to retrieve
* can be also filtered by Id, specifying the first and last Id to include.
*
* @param client XML-RPC Client.
* @param filter Filter flag to use. Possible values:
* <ul>
* <li>{@link Pool#ALL}: All Backup Jobs</li>
* <li>{@link Pool#MINE}: Connected user's Backup Jobs</li>
* <li>{@link Pool#MINE_GROUP}: Connected user's Backup Jobs, and the ones in
* his group</li>
* <li>{@link Pool#GROUP}: User's primary group Backup Jobs</li>
* <li>&gt;= 0 UID User's Backup Jobs</li>
* </ul>
* @param startId Lowest ID to retrieve
* @param endId Biggest ID to retrieve
* @return If successful the message contains the string
* with the information returned by OpenNebula.
*/
public static OneResponse info(Client client, int filter,
int startId, int endId)
{
return Pool.info(client, INFO_METHOD, filter, startId, endId);
}
/**
* Loads the xml representation of all or part of the
* Backup Jobs in the pool. The filter used is the one set in
* the constructor.
*
* @see BackupJobPool#info(Client, int)
*
* @return If successful the message contains the string
* with the information returned by OpenNebula.
*/
public OneResponse info()
{
return super.info(filter, -1, -1);
}
/**
* Loads the xml representation of all the Backup Jobs in the pool.
*
* @return If successful the message contains the string
* with the information returned by OpenNebula.
*/
public OneResponse infoAll()
{
return super.infoAll();
}
/**
* Loads the xml representation of all the connected user's Backup Jobs.
*
* @return If successful the message contains the string
* with the information returned by OpenNebula.
*/
public OneResponse infoMine()
{
return super.infoMine();
}
/**
* Loads the xml representation of all the connected user's Backup Jobs and
* the ones in his group.
*
* @return If successful the message contains the string
* with the information returned by OpenNebula.
*/
public OneResponse infoGroup()
{
return super.infoGroup();
}
/**
* Retrieves all or part of the Backup Jobs in the pool. The Backup Jobs to retrieve
* can be also filtered by Id, specifying the first and last Id to include.
*
* @param filter Filter flag to use. Possible values:
* <ul>
* <li>{@link Pool#ALL}: All Backup Jobs</li>
* <li>{@link Pool#MINE}: Connected user's Backup Jobs</li>
* <li>{@link Pool#MINE_GROUP}: Connected user's Backup Jobs, and the ones in
* his group</li>
* <li>{@link Pool#GROUP}: User's primary group Backup Jobs</li>
* <li>&gt;= 0 UID User's Backup Jobs</li>
* </ul>
* @param startId Lowest ID to retrieve
* @param endId Biggest ID to retrieve
* @return If successful the message contains the string
* with the information returned by OpenNebula.
*/
public OneResponse info(int filter, int startId, int endId)
{
return super.info(filter, startId, endId);
}
public Iterator<BackupJob> iterator()
{
AbstractList<BackupJob> ab = new AbstractList<BackupJob>()
{
public int size()
{
return getLength();
}
public BackupJob get(int index)
{
return (BackupJob) item(index);
}
};
return ab.iterator();
}
/**
* Returns the Backup Job with the given Id from the pool. If it is not found,
* then returns null. The method {@link #info()} must be called before.
*
* @param id of the Backup Job to retrieve
* @return The Backup Job with the given Id, or null if it was not found.
*/
public BackupJob getById(int id)
{
return (BackupJob) super.getById(id);
}
}

View File

@ -68,7 +68,8 @@ RESOURCES = {
"MARKETPLACE": 0x8000000000000,
"MARKETPLACEAPP": 0x10000000000000,
"VMGROUP": 0x20000000000000,
"VNTEMPLATE": 0x40000000000000
"VNTEMPLATE": 0x40000000000000,
"BACKUPJOB": 0x100000000000000,
}
RIGHTS = {

View File

@ -73,6 +73,8 @@ require 'opennebula/hook'
require 'opennebula/hook_pool'
require 'opennebula/hook_log'
require 'opennebula/flow'
require 'opennebula/backupjob'
require 'opennebula/backupjob_pool'
module OpenNebula

View File

@ -73,7 +73,8 @@ module OpenNebula
"MARKETPLACE" => 0x8000000000000,
"MARKETPLACEAPP"=> 0x10000000000000,
"VMGROUP" => 0x20000000000000,
"VNTEMPLATE" => 0x40000000000000
"VNTEMPLATE" => 0x40000000000000,
"BACKUPJOB" =>0x100000000000000
}
RIGHTS =

View File

@ -0,0 +1,250 @@
# -------------------------------------------------------------------------- #
# Copyright 2002-2023, OpenNebula Project, OpenNebula Systems #
# #
# 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 'opennebula/lockable_ext'
require 'opennebula/pool_element'
module OpenNebula
# Class for representing a Backup Job object
class BackupJob < PoolElement
#######################################################################
# Constants and Class Methods
#######################################################################
BACKUPJOB_METHODS = {
:allocate => 'backupjob.allocate',
:info => 'backupjob.info',
:update => 'backupjob.update',
:delete => 'backupjob.delete',
:chown => 'backupjob.chown',
:chmod => 'backupjob.chmod',
:clone => 'backupjob.clone',
:rename => 'backupjob.rename',
:lock => 'backupjob.lock',
:unlock => 'backupjob.unlock',
:backup => 'backupjob.backup',
:cancel => 'backupjob.cancel',
:retry => 'backupjob.retry',
:priority => 'backupjob.priority',
:schedadd => 'backupjob.schedadd',
:scheddelete => 'backupjob.scheddelete',
:schedupdate => 'backupjob.schedupdate'
}
# Creates a BackupJob description with just its identifier
# this method should be used to create plain BackupJob objects.
# +id+ the id of the user
#
# Example:
# bj = BackupJob.new(BackupJob.build_xml(3),rpc_client)
#
def self.build_xml(pe_id = nil)
if pe_id
obj_xml = "<BACKUPJOB><ID>#{pe_id}</ID></BACKUPJOB>"
else
obj_xml = '<BACKUPJOB></BACKUPJOB>'
end
XMLElement.build_xml(obj_xml, 'BACKUPJOB')
end
# Class constructor
def initialize(xml, client)
LockableExt.make_lockable(self, BACKUPJOB_METHODS)
super(xml, client)
@client = client
end
#######################################################################
# XML-RPC Methods for the Backup Job Object
#######################################################################
# Retrieves the information of the given Backup Job.
def info
return Error.new('ID not defined') unless @pe_id
rc = @client.call(BACKUPJOB_METHODS[:info], @pe_id)
if !OpenNebula.is_error?(rc)
initialize_xml(rc, 'BACKUPJOB')
rc = nil
@pe_id = self['ID'].to_i if self['ID']
@name = self['NAME'] if self['NAME']
end
rc
end
alias info! info
# Allocates a new Backup Job in OpenNebula
#
# @param description [String] The contents of the BackupJob.
#
# @return [nil, OpenNebula::Error] nil in case of success, Error
# otherwise
def allocate(description)
super(BACKUPJOB_METHODS[:allocate], description)
end
# Deletes the BackupJob
#
# @return [nil, OpenNebula::Error] nil in case of success, Error
# otherwise
def delete
call(BACKUPJOB_METHODS[:delete], @pe_id)
end
# Replaces the Backup Job contents
#
# @param new_template [String] New template contents
# @param append [true, false] True to append new attributes instead of
# replace the whole template
#
# @return [nil, OpenNebula::Error] nil in case of success, Error
# otherwise
def update(new_template)
super(BACKUPJOB_METHODS[:update], new_template)
end
# Changes the owner/group
# uid:: _Integer_ the new owner id. Set to -1 to leave the current one
# gid:: _Integer_ the new group id. Set to -1 to leave the current one
# [return] nil in case of success or an Error object
def chown(uid, gid)
super(BACKUPJOB_METHODS[:chown], uid, gid)
end
# Changes the Backup Job permissions.
#
# @param octet [String] Permissions octed , e.g. 640
#
# @return [nil, OpenNebula::Error] nil in case of success, Error
# otherwise
def chmod_octet(octet)
super(BACKUPJOB_METHODS[:chmod], octet)
end
# Changes the Backup Job permissions.
# Each [Integer] argument must be 1 to allow, 0 deny, -1 do not change
#
# @return [nil, OpenNebula::Error] nil in case of success, Error
# otherwise
# rubocop:disable Metrics/ParameterLists
def chmod(owner_u, owner_m, owner_a, group_u, group_m, group_a, other_u,
other_m, other_a)
call(BACKUPJOB_METHODS[:chmod], @pe_id, owner_u, owner_m, owner_a, group_u,
group_m, group_a, other_u, other_m, other_a)
end
# rubocop:enable Metrics/ParameterLists
# Renames this Backup Job
#
# @param name [String] New name for the Backup Job.
#
# @return [nil, OpenNebula::Error] nil in case of success, Error
# otherwise
def rename(name)
call(BACKUPJOB_METHODS[:rename], @pe_id, name)
end
# Starts the Backup Job
#
# @return [nil, OpenNebula::Error] nil in case of success, Error
# otherwise
def backup
call(BACKUPJOB_METHODS[:backup], @pe_id)
end
# Cancel pending Backup Job, removing VMs from waiting list
#
# @return [nil, OpenNebula::Error] nil in case of success, Error
# otherwise
def cancel
call(BACKUPJOB_METHODS[:cancel], @pe_id)
end
# Retry backup for VMs in error list
#
# @return [nil, OpenNebula::Error] nil in case of success, Error
# otherwise
def retry
call(BACKUPJOB_METHODS[:retry], @pe_id)
end
# Change priority of Backup Job
#
# @return [nil, OpenNebula::Error] nil in case of success, Error
# otherwise
def priority(pr)
call(BACKUPJOB_METHODS[:priority], @pe_id, pr)
end
# Add Scheduled action
#
# @param sched_template [String] Template with SCHED_ACTIONs
# @return [nil, OpenNebula::Error] nil in case of success, Error
# otherwise
def sched_action_add(sched_template)
call(BACKUPJOB_METHODS[:schedadd], @pe_id, sched_template)
end
# Delete Scheduled Action
#
# @param sched_id [Int] id of the SCHED_ACTION
# @return [nil, OpenNebula::Error] nil in case of success, Error
# otherwise
def sched_action_delete(sched_id)
call(BACKUPJOB_METHODS[:scheddelete], @pe_id, sched_id.to_i)
end
# Update Scheduled Action
#
# @param sched_id [Int] id of the SCHED_ACTION
# @param sched_template [String] Template containing a SCHED_ACTION
# @return [nil, OpenNebula::Error] nil in case of success, Error
# otherwise
def sched_action_update(sched_id, sched_template)
call(BACKUPJOB_METHODS[:schedupdate], @pe_id,
sched_id.to_i, sched_template)
end
#######################################################################
# Helpers to get Template information
#######################################################################
# Returns the group identifier
# [return] _Integer_ the element's group ID
def gid
self['GID'].to_i
end
def owner_id
self['UID'].to_i
end
def public?
self['PERMISSIONS/GROUP_U'] == '1' || self['PERMISSIONS/OTHER_U'] == '1'
end
end
end

View File

@ -0,0 +1,82 @@
# -------------------------------------------------------------------------- #
# Copyright 2002-2023, OpenNebula Project, OpenNebula Systems #
# #
# 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 'opennebula/pool'
module OpenNebula
# Class representing a Backup Job pool
class BackupJobPool < Pool
#######################################################################
# Constants and Class attribute accessors
#######################################################################
BACKUPJOB_POOL_METHODS = {
:info => 'backupjobpool.info'
}
#######################################################################
# Class constructor & Pool Methods
#######################################################################
# +client+ a Client object that represents an XML-RPC connection
# +user_id+ used to refer to a Pool with Templates from that user
def initialize(client, user_id = -1)
super('BACKUPJOB_POOL', 'BACKUPJOB', client)
@user_id = user_id
end
# Factory method to create Backup Job objects
def factory(element_xml)
OpenNebula::BackupJob.new(element_xml, @client)
end
#######################################################################
# XML-RPC Methods for the Template Object
#######################################################################
# Retrieves all or part of the Templates in the pool.
def info(*args)
case args.size
when 0
info_filter(BACKUPJOB_POOL_METHODS[:info], @user_id, -1, -1)
when 3
info_filter(BACKUPJOB_POOL_METHODS[:info], args[0], args[1], args[2])
end
end
def info_all
super(BACKUPJOB_POOL_METHODS[:info])
end
def info_mine
super(BACKUPJOB_POOL_METHODS[:info])
end
def info_group
super(BACKUPJOB_POOL_METHODS[:info])
end
alias info! info
alias info_all! info_all
alias info_mine! info_mine
alias info_group! info_group
end
end

View File

@ -37,7 +37,7 @@ module OpenNebula
SELF = -1
# Default resource ACL's for group users (create)
GROUP_DEFAULT_ACLS = "VM+IMAGE+TEMPLATE+DOCUMENT+SECGROUP+VROUTER+VMGROUP"
GROUP_DEFAULT_ACLS = "VM+IMAGE+TEMPLATE+DOCUMENT+SECGROUP+VROUTER+VMGROUP+BACKUPJOB"
# The default view for group and group admins, must be defined in
# sunstone_views.yaml

View File

@ -125,6 +125,7 @@ module OpenNebula::LockableExt
def self.lockable?(obj)
# Lockable classes
lockable = [
OpenNebula::BackupJob,
OpenNebula::Document,
OpenNebula::Hook,
OpenNebula::Image,

View File

@ -54,7 +54,15 @@ class OneDBBacKEnd
document_pool: "oid INTEGER PRIMARY KEY, name VARCHAR(128), " <<
"body MEDIUMTEXT, type INTEGER, uid INTEGER, gid INTEGER, " <<
"owner_u INTEGER, group_u INTEGER, other_u INTEGER"
"owner_u INTEGER, group_u INTEGER, other_u INTEGER",
backupjob_pool: "oid INTEGER PRIMARY KEY, name VARCHAR(128), " <<
"body MEDIUMTEXT, uid INTEGER, gid INTEGER, " <<
"owner_u INTEGER, group_u INTEGER, other_u INTEGER, " <<
"priority INTEGER, outdated_vms INTEGER",
schedaction_pool: "oid INTEGER PRIMARY KEY, parent_id INTEGER, "<<
"type VARCHAR(128), body MEDIUMTEXT, time INTEGER, done INTEGER"
}
VERSION_SCHEMA = {

View File

@ -51,6 +51,7 @@ require 'fsck/vrouter'
require 'fsck/template'
require 'fsck/quotas'
require 'fsck/scheduled_actions'
module OneDBFsck
@ -543,6 +544,19 @@ EOT
fix_template
log_time
########################################################################
# Scheduled Actions
########################################################################
check_scheduled_actions
fix_scheduled_actions
log_time
# Log results
log_total_errors
return true

View File

@ -0,0 +1,40 @@
# Scheduled Action module
module OneDBFsck
# Check Scheduled Actions
def check_scheduled_actions
@to_delete = []
@item = Struct.new(:id, :type)
# Check Scheduled Actions owner object exists
check_resource_exists('BACKUPJOB', 'backupjob_pool')
check_resource_exists('VM', 'vm_pool')
end
def check_resource_exists(resource_name, pool_name)
# Query to select Scheduled Actions without owner
query = 'SELECT oid FROM schedaction_pool ' \
"WHERE type = '#{resource_name}' AND " \
'NOT EXISTS (SELECT oid ' \
"FROM #{pool_name} WHERE #{pool_name}.oid = schedaction_pool.parent_id "
query += "AND #{pool_name}.state != 6" if resource_name == 'VM'
query += ')'
@db.fetch(query) do |row|
log_error("Scheduled action #{row[:oid]} of object type #{resource_name}" \
' does not have an owner', true)
@to_delete << @item.new(row[:oid], resource_name)
end
end
# Fix broken Scheduled Actions
def fix_scheduled_actions
@db.transaction do
# Removing hanging Scheduled Actions
@to_delete.each do |o|
@db[:schedaction_pool].where(:oid => o.id, :type => o.type).delete
end
end
end
end

View File

@ -129,6 +129,32 @@ int ObjectCollection::del(int id)
return 0;
};
int ObjectCollection::del_not_present(const ObjectCollection& base)
{
int removed = 0;
if ( collection_set.size() == 0 )
{
return 0;
}
for (auto it = collection_set.begin(); it != collection_set.end(); )
{
if ( base.contains(*it) )
{
++it;
}
else
{
it = collection_set.erase(it);
removed++;
}
}
return removed;
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -37,7 +37,8 @@ const long int PoolObjectSQL::LockableObject = PoolObjectSQL::ObjectType::VM
| PoolObjectSQL::ObjectType::VMGROUP
| PoolObjectSQL::ObjectType::VNTEMPLATE
| PoolObjectSQL::ObjectType::DOCUMENT
| PoolObjectSQL::ObjectType::HOOK;
| PoolObjectSQL::ObjectType::HOOK
| PoolObjectSQL::ObjectType::BACKUPJOB;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

View File

@ -767,6 +767,14 @@ void Request::failure_response(ErrorCode ec, const string& str_val,
/* -------------------------------------------------------------------------- */
string Request::failure_message(ErrorCode ec, RequestAttributes& att)
{
return failure_message(ec, att, method_name, auth_object);
}
/* -------------------------------------------------------------------------- */
string Request::failure_message(ErrorCode ec, RequestAttributes& att,
const std::string& method_name, PoolObjectSQL::ObjectType auth_object)
{
std::ostringstream oss;
std::string obname;

View File

@ -54,6 +54,7 @@
#include "RequestManagerHook.h"
#include "RequestManagerMarketPlace.h"
#include "RequestManagerSchedAction.h"
#include "RequestManagerBackupJob.h"
#include "RequestManagerSystem.h"
#include "RequestManagerProxy.h"
@ -379,6 +380,7 @@ void RequestManager::register_xml_methods()
xmlrpc_c::methodPtr vmg_update(new VMGroupUpdateTemplate());
xmlrpc_c::methodPtr vntemplate_update(new VirtualNetworkTemplateUpdateTemplate());
xmlrpc_c::methodPtr hook_update(new HookUpdateTemplate());
xmlrpc_c::methodPtr backupjob_update(new BackupJobUpdateTemplate());
// Allocate Methods
xmlrpc_c::methodPtr vm_allocate(new VirtualMachineAllocate());
@ -394,6 +396,7 @@ void RequestManager::register_xml_methods()
xmlrpc_c::methodPtr vmg_allocate(new VMGroupAllocate());
xmlrpc_c::methodPtr vntemplate_allocate(new VirtualNetworkTemplateAllocate());
xmlrpc_c::methodPtr hook_allocate(new HookAllocate());
xmlrpc_c::methodPtr backupjob_allocate(new BackupJobAllocate());
// Clone Methods
xmlrpc_c::methodPtr template_clone(new VMTemplateClone());
@ -414,6 +417,7 @@ void RequestManager::register_xml_methods()
xmlrpc_c::methodPtr vmg_delete(new VMGroupDelete());
xmlrpc_c::methodPtr vntemplate_delete(new VirtualNetworkTemplateDelete());
xmlrpc_c::methodPtr hook_delete(new HookDelete());
xmlrpc_c::methodPtr backupjob_delete(new BackupJobDelete());
// Info Methods
xmlrpc_c::methodPtr vm_info(new VirtualMachineInfo());
@ -429,6 +433,7 @@ void RequestManager::register_xml_methods()
xmlrpc_c::methodPtr vrouter_info(new VirtualRouterInfo());
xmlrpc_c::methodPtr vmg_info(new VMGroupInfo());
xmlrpc_c::methodPtr hook_info(new HookInfo());
xmlrpc_c::methodPtr backupjob_info(new BackupJobInfo());
// Lock Methods
xmlrpc_c::methodPtr doc_lock(new DocumentLock());
@ -449,6 +454,8 @@ void RequestManager::register_xml_methods()
xmlrpc_c::methodPtr vntemplate_unlock(new VNTemplateUnlock());
xmlrpc_c::methodPtr hook_lock(new HookLock());
xmlrpc_c::methodPtr hook_unlock(new HookUnlock());
xmlrpc_c::methodPtr backupjob_lock(new BackupJobLock());
xmlrpc_c::methodPtr backupjob_unlock(new BackupJobUnlock());
// PoolInfo Methods
xmlrpc_c::methodPtr hostpool_info(new HostPoolInfo());
@ -466,6 +473,7 @@ void RequestManager::register_xml_methods()
xmlrpc_c::methodPtr vmgpool_info(new VMGroupPoolInfo());
xmlrpc_c::methodPtr vrouter_pool_info(new VirtualRouterPoolInfo());
xmlrpc_c::methodPtr hookpool_info(new HookPoolInfo());
xmlrpc_c::methodPtr backupjobpool_info(new BackupJobPoolInfo());
// Host Methods
xmlrpc_c::methodPtr host_status(new HostStatus());
@ -496,6 +504,7 @@ void RequestManager::register_xml_methods()
xmlrpc_c::methodPtr vrouter_chown(new VirtualRouterChown());
xmlrpc_c::methodPtr vmg_chown(new VMGroupChown());
xmlrpc_c::methodPtr vntemplate_chown(new VirtualNetworkTemplateChown());
xmlrpc_c::methodPtr backupjob_chown(new BackupJobChown());
// Chmod Methods
xmlrpc_c::methodPtr vm_chmod(new VirtualMachineChmod());
@ -508,6 +517,7 @@ void RequestManager::register_xml_methods()
xmlrpc_c::methodPtr vrouter_chmod(new VirtualRouterChmod());
xmlrpc_c::methodPtr vmg_chmod(new VMGroupChmod());
xmlrpc_c::methodPtr vntemplate_chmod(new VirtualNetworkTemplateChmod());
xmlrpc_c::methodPtr backupjob_chmod(new BackupJobChmod());
// Cluster Methods
xmlrpc_c::methodPtr cluster_addhost(new ClusterAddHost());
@ -537,6 +547,7 @@ void RequestManager::register_xml_methods()
xmlrpc_c::methodPtr vmg_rename(new VMGroupRename());
xmlrpc_c::methodPtr vntemplate_rename(new VirtualNetworkTemplateRename());
xmlrpc_c::methodPtr hook_rename(new HookRename());
xmlrpc_c::methodPtr backupjob_rename(new BackupJobRename());
// Virtual Router Methods
xmlrpc_c::methodPtr vrouter_instantiate(new VirtualRouterInstantiate());
@ -549,9 +560,18 @@ void RequestManager::register_xml_methods()
// Hook methods
xmlrpc_c::methodPtr hook_retry(new HookRetry());
//HookLog methods
// HookLog methods
xmlrpc_c::methodPtr hooklog_info(new HookLogInfo());
// Backup Job methods
xmlrpc_c::methodPtr backupjob_backup(new BackupJobBackup());
xmlrpc_c::methodPtr backupjob_cancel(new BackupJobCancel());
xmlrpc_c::methodPtr backupjob_retry(new BackupJobRetry());
xmlrpc_c::methodPtr backupjob_priority(new BackupJobPriority());
xmlrpc_c::methodPtr backupjob_schedadd(new BackupJobSchedAdd());
xmlrpc_c::methodPtr backupjob_scheddelete(new BackupJobSchedDelete());
xmlrpc_c::methodPtr backupjob_schedupdate(new BackupJobSchedUpdate());
/* VM related methods */
RequestManagerRegistry.addMethod("one.vm.deploy", vm_deploy);
RequestManagerRegistry.addMethod("one.vm.action", vm_action);
@ -1220,6 +1240,25 @@ void RequestManager::register_xml_methods()
/* Hook Log related methods */
RequestManagerRegistry.addMethod("one.hooklog.info", hooklog_info);
/* Backup Job related methods */
RequestManagerRegistry.addMethod("one.backupjob.allocate", backupjob_allocate);
RequestManagerRegistry.addMethod("one.backupjob.delete", backupjob_delete);
RequestManagerRegistry.addMethod("one.backupjob.update", backupjob_update);
RequestManagerRegistry.addMethod("one.backupjob.rename", backupjob_rename);
RequestManagerRegistry.addMethod("one.backupjob.info", backupjob_info);
RequestManagerRegistry.addMethod("one.backupjob.chown", backupjob_chown);
RequestManagerRegistry.addMethod("one.backupjob.chmod", backupjob_chmod);
RequestManagerRegistry.addMethod("one.backupjob.lock", backupjob_lock);
RequestManagerRegistry.addMethod("one.backupjob.unlock", backupjob_unlock);
RequestManagerRegistry.addMethod("one.backupjob.backup", backupjob_backup);
RequestManagerRegistry.addMethod("one.backupjob.cancel", backupjob_cancel);
RequestManagerRegistry.addMethod("one.backupjob.retry", backupjob_retry);
RequestManagerRegistry.addMethod("one.backupjob.priority", backupjob_priority);
RequestManagerRegistry.addMethod("one.backupjob.schedadd", backupjob_schedadd);
RequestManagerRegistry.addMethod("one.backupjob.scheddelete", backupjob_scheddelete);
RequestManagerRegistry.addMethod("one.backupjob.schedupdate", backupjob_schedupdate);
RequestManagerRegistry.addMethod("one.backupjobpool.info", backupjobpool_info);
/* System related methods */
RequestManagerRegistry.addMethod("one.system.version", system_version);
RequestManagerRegistry.addMethod("one.system.config", system_config);

View File

@ -25,6 +25,7 @@
#include "FedReplicaManager.h"
#include "ImageManager.h"
#include "MarketPlaceManager.h"
#include "ScheduledActionPool.h"
using namespace std;
@ -264,6 +265,22 @@ void RequestManagerAllocate::request_execute(xmlrpc_c::paramList const& params,
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
static int drop_sched_actions(ScheduledActionPool *pool, std::vector<int> sa_ids)
{
std::string error;
int i = 0;
for (const auto& id : sa_ids)
{
if (auto sa = pool->get(id))
{
pool->drop(sa.get(), error);
i++;
}
}
return i;
}
Request::ErrorCode VirtualMachineAllocate::pool_allocate(
xmlrpc_c::paramList const& paramList,
@ -271,52 +288,119 @@ Request::ErrorCode VirtualMachineAllocate::pool_allocate(
int& id,
RequestAttributes& att)
{
bool on_hold = false;
auto sapool = Nebula::instance().get_sapool();
auto vmpool = static_cast<VirtualMachinePool *>(pool);
std::vector<int> sa_ids;
bool on_hold = false;
bool sa_error = false;
time_t stime = time(0);
if ( paramList.size() > 2 )
{
on_hold = xmlrpc_c::value_boolean(paramList.getBoolean(2));
}
/* ---------------------------------------------------------------------- */
/* Save SCHED_ACTION attributes for allocation */
/* ---------------------------------------------------------------------- */
std::vector<unique_ptr<VectorAttribute>> sas;
tmpl->remove("SCHED_ACTION", sas);
/* ---------------------------------------------------------------------- */
/* Allocate VirtualMachine object */
/* ---------------------------------------------------------------------- */
Template tmpl_back(*tmpl);
unique_ptr<VirtualMachineTemplate> ttmpl(
static_cast<VirtualMachineTemplate*>(tmpl.release()));
VirtualMachinePool * vmpool = static_cast<VirtualMachinePool *>(pool);
auto tmpl_ptr = static_cast<VirtualMachineTemplate*>(tmpl.release());
unique_ptr<VirtualMachineTemplate> ttmpl(tmpl_ptr);
int rc = vmpool->allocate(att.uid, att.gid, att.uname, att.gname, att.umask,
move(ttmpl), &id, att.resp_msg, on_hold);
if ( rc < 0 )
{
vector<unique_ptr<Template>> ds_quotas;
std::string memory, cpu;
goto error_drop_vm;
}
tmpl_back.get("MEMORY", memory);
tmpl_back.get("CPU", cpu);
/* ---------------------------------------------------------------------- */
/* Create ScheduleAction and associate to the BackupJob */
/* ---------------------------------------------------------------------- */
for (const auto& sa : sas)
{
int sa_id = sapool->allocate(PoolObjectSQL::VM, id, stime, sa.get(), att.resp_msg);
tmpl_back.add("RUNNING_MEMORY", memory);
tmpl_back.add("RUNNING_CPU", cpu);
tmpl_back.add("RUNNING_VMS", 1);
tmpl_back.add("VMS", 1);
quota_rollback(&tmpl_back, Quotas::VIRTUALMACHINE, att);
VirtualMachineDisks::extended_info(att.uid, &tmpl_back);
VirtualMachineDisks::image_ds_quotas(&tmpl_back, ds_quotas);
for (auto& quota : ds_quotas)
if (sa_id < 0)
{
quota_rollback(quota.get(), Quotas::DATASTORE, att);
sa_error = true;
break;
}
sa_ids.push_back(sa_id);
}
/* ---------------------------------------------------------------------- */
/* Error creating a SCHED_ACTION rollback created objects */
/* ---------------------------------------------------------------------- */
if (sa_error)
{
drop_sched_actions(sapool, sa_ids);
goto error_drop_vm;
}
/* ---------------------------------------------------------------------- */
/* Associate SCHED_ACTIONS to the BackupJob */
/* ---------------------------------------------------------------------- */
if ( auto vm = vmpool->get(id) )
{
for (const auto id: sa_ids)
{
vm->sched_actions().add(id);
}
vmpool->update(vm.get());
}
else
{
att.resp_msg = "VM deleted while setting up SCHED_ACTION";
drop_sched_actions(sapool, sa_ids);
return Request::INTERNAL;
}
return Request::SUCCESS;
}
error_drop_vm:
vector<unique_ptr<Template>> ds_quotas;
std::string memory, cpu;
tmpl_back.get("MEMORY", memory);
tmpl_back.get("CPU", cpu);
tmpl_back.add("RUNNING_MEMORY", memory);
tmpl_back.add("RUNNING_CPU", cpu);
tmpl_back.add("RUNNING_VMS", 1);
tmpl_back.add("VMS", 1);
quota_rollback(&tmpl_back, Quotas::VIRTUALMACHINE, att);
VirtualMachineDisks::extended_info(att.uid, &tmpl_back);
VirtualMachineDisks::image_ds_quotas(&tmpl_back, ds_quotas);
for (auto& quota : ds_quotas)
{
quota_rollback(quota.get(), Quotas::DATASTORE, att);
}
return Request::INTERNAL;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
@ -1365,3 +1449,104 @@ Request::ErrorCode HookAllocate::pool_allocate(
return Request::SUCCESS;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
Request::ErrorCode BackupJobAllocate::pool_allocate(
xmlrpc_c::paramList const& paramList,
unique_ptr<Template> tmpl,
int& id,
RequestAttributes& att)
{
/* ---------------------------------------------------------------------- */
/* Get SCHED_ACTION attributes */
/* ---------------------------------------------------------------------- */
std::vector<unique_ptr<VectorAttribute>> sas;
tmpl->remove("SCHED_ACTION", sas);
/* ---------------------------------------------------------------------- */
/* Create BackupJob object */
/* ---------------------------------------------------------------------- */
BackupJobPool * bjpool = static_cast<BackupJobPool *>(pool);
int rc = bjpool->allocate(att.uid, att.gid, att.uname, att.gname, att.umask,
move(tmpl), &id, att.resp_msg);
if (rc < 0)
{
return Request::INTERNAL;
}
if (sas.empty())
{
return Request::SUCCESS;
}
/* ---------------------------------------------------------------------- */
/* Create ScheduleAction and associate to the BackupJob */
/* ---------------------------------------------------------------------- */
auto sapool = Nebula::instance().get_sapool();
std::vector<int> sa_ids;
bool sa_error = false;
for (const auto& sa : sas)
{
int sa_id = sapool->allocate(PoolObjectSQL::BACKUPJOB, id, 0, sa.get(),
att.resp_msg);
if (sa_id < 0)
{
sa_error = true;
break;
}
else
{
sa_ids.push_back(sa_id);
}
}
/* ---------------------------------------------------------------------- */
/* Error creating a SCHED_ACTION rollback created objects */
/* ---------------------------------------------------------------------- */
if (sa_error)
{
drop_sched_actions(sapool, sa_ids);
if ( auto bj = bjpool->get(id) )
{
string error;
bjpool->drop(bj.get(), error);
}
return Request::INTERNAL;
}
/* ---------------------------------------------------------------------- */
/* Associate SCHED_ACTIONS to the BackupJob */
/* ---------------------------------------------------------------------- */
if ( auto bj = bjpool->get(id) )
{
for (const auto id: sa_ids)
{
bj->sched_actions().add(id);
}
bjpool->update(bj.get());
}
else
{
// BackupJob no longer exits, delete SchedActions
drop_sched_actions(sapool, sa_ids);
att.resp_msg = "BACKUPJOB deleted while setting up SCHED_ACTION";
return Request::INTERNAL;
}
return Request::SUCCESS;
}

View File

@ -0,0 +1,412 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2023, OpenNebula Project, OpenNebula Systems */
/* */
/* 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 "RequestManagerBackupJob.h"
#include "Nebula.h"
#include "BackupJobPool.h"
#include "ScheduledActionPool.h"
#include "DispatchManager.h"
using namespace std;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
RequestManagerBackupJob::RequestManagerBackupJob(const std::string& method_name,
const std::string& params,
const std::string& help)
: Request(method_name, params, help)
{
Nebula& nd = Nebula::instance();
pool = nd.get_bjpool();
auth_object = PoolObjectSQL::BACKUPJOB;
auth_op = AuthRequest::MANAGE;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void BackupJobBackup::request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att)
{
int bj_id = _paramList.getInt(1);
if (!basic_authorization(bj_id, att))
{
return;
}
auto bjpool = static_cast<BackupJobPool*>(pool);
auto bj = bjpool->get(bj_id);
if (bj == nullptr)
{
att.resp_id = bj_id;
failure_response(NO_EXISTS, att);
return;
}
int rc = bj->execute(att.resp_msg);
bjpool->update(bj.get());
if (rc != 0)
{
NebulaLog::error("ReM", att.resp_msg);
failure_response(ACTION, att);
return;
}
success_response(bj_id, att);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void BackupJobCancel::request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att)
{
int bj_id = _paramList.getInt(1);
if (!basic_authorization(bj_id, att))
{
return;
}
auto bjpool = static_cast<BackupJobPool*>(pool);
auto bj = bjpool->get(bj_id);
if (bj == nullptr)
{
att.resp_id = bj_id;
failure_response(NO_EXISTS, att);
return;
}
std::set<int> active_vms(bj->backing_up());
bj->cancel();
bjpool->update(bj.get());
bj.reset();
// Failure is because non-exist VM or wrong state, ignore failures
auto dm = Nebula::instance().get_dm();
for (const auto& vm_id : active_vms)
{
dm->backup_cancel(vm_id, att, att.resp_msg);
}
success_response(bj_id, att);
return;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void BackupJobRetry::request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att)
{
int bj_id = _paramList.getInt(1);
if (!basic_authorization(bj_id, att))
{
return;
}
auto bjpool = static_cast<BackupJobPool*>(pool);
auto bj = bjpool->get(bj_id);
if (bj == nullptr)
{
att.resp_id = bj_id;
failure_response(NO_EXISTS, att);
return;
}
bj->retry();
bjpool->update(bj.get());
success_response(bj_id, att);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void BackupJobPriority::request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att)
{
int bj_id = _paramList.getInt(1);
int priority = _paramList.getInt(2);
if ( priority > BackupJob::MAX_PRIO || priority < BackupJob::MIN_PRIO )
{
att.resp_msg = "Wrong priority value";
failure_response(ACTION, att);
return;
}
if ( priority > BackupJob::MAX_USER_PRIO )
{
att.auth_op = AuthRequest::ADMIN;
}
if (!basic_authorization(bj_id, att))
{
return;
}
auto bjpool = static_cast<BackupJobPool*>(pool);
auto bj = bjpool->get(bj_id);
if (bj == nullptr)
{
att.resp_id = bj_id;
failure_response(NO_EXISTS, att);
return;
}
bj->priority(priority);
bjpool->update(bj.get());
success_response(bj_id, att);
return;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void BackupJobSchedAdd::request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att)
{
int bj_id = _paramList.getInt(1);
string template_str = _paramList.getString(2);
if (!basic_authorization(bj_id, att))
{
return;
}
auto& nd = Nebula::instance();
auto bjpool = nd.get_bjpool();
auto sapool = nd.get_sapool();
// Create template from template string
auto tmpl = std::make_unique<Template>();
if (tmpl->parse_str_or_xml(template_str, att.resp_msg) != 0)
{
failure_response(INTERNAL, att);
return;
}
const VectorAttribute * va = tmpl->get("SCHED_ACTION");
if ( va == nullptr )
{
att.resp_msg = "No SCHED_ACTION attribute in template";
failure_response(ACTION, att);
return;
}
auto sa_id = sapool->allocate(PoolObjectSQL::BACKUPJOB, bj_id, time(0), va, att.resp_msg);
if ( sa_id < 0 )
{
failure_response(ACTION, att);
return;
}
// Update Scheduled Action ID in the BJ
if (auto bj = bjpool->get(bj_id))
{
bj->sched_actions().add(sa_id);
bjpool->update(bj.get());
}
else
{
att.resp_id = bj_id;
// BackupJob no longer exists, cleanup the Scheduled Action
if (auto sa = sapool->get(sa_id))
{
string err;
sapool->drop(sa.get(), err);
}
failure_response(NO_EXISTS, att);
return;
}
att.resp_obj = PoolObjectSQL::SCHEDULEDACTION;
att.resp_id = sa_id;
success_response(sa_id, att);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void BackupJobSchedDelete::request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att)
{
int bj_id = _paramList.getInt(1);
int sa_id = _paramList.getInt(2);
if (!basic_authorization(bj_id, att))
{
return;
}
auto& nd = Nebula::instance();
auto bjpool = nd.get_bjpool();
auto sapool = nd.get_sapool();
if (auto bj = bjpool->get(bj_id))
{
if ( bj->sched_actions().del(sa_id) == -1 )
{
att.resp_obj = PoolObjectSQL::SCHEDULEDACTION;
att.resp_id = sa_id;
failure_response(NO_EXISTS, att);
return;
}
bjpool->update(bj.get());
}
else
{
failure_response(NO_EXISTS, att);
return;
}
if (auto sa = sapool->get(sa_id))
{
if (sapool->drop(sa.get(), att.resp_msg) != 0)
{
failure_response(ACTION, att);
return;
}
}
att.resp_obj = PoolObjectSQL::SCHEDULEDACTION;
att.resp_id = sa_id;
success_response(sa_id, att);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void BackupJobSchedUpdate::request_execute(xmlrpc_c::paramList const& _paramList,
RequestAttributes& att)
{
int bj_id = _paramList.getInt(1);
int sa_id = _paramList.getInt(2);
std::string template_str = _paramList.getString(3);
if (!basic_authorization(bj_id, att))
{
return;
}
/* ---------------------------------------------------------------------- */
/* Parse input template and get SCHED_ACTION attribute */
/* ---------------------------------------------------------------------- */
auto tmpl = std::make_unique<Template>();
if (tmpl->parse_str_or_xml(template_str, att.resp_msg) != 0)
{
failure_response(INTERNAL, att);
return;
}
const VectorAttribute * v_sa = tmpl->get("SCHED_ACTION");
if ( v_sa == nullptr )
{
att.resp_msg = "No SCHED_ACTION attribute in template";
failure_response(INTERNAL, att);
return;
}
/* ---------------------------------------------------------------------- */
/* Check Scheduled Action association */
/* ---------------------------------------------------------------------- */
auto& nd = Nebula::instance();
auto bjpool = nd.get_bjpool();
auto sapool = nd.get_sapool();
if (auto bj = bjpool->get(bj_id))
{
if (!bj->sched_actions().contains(sa_id))
{
std::ostringstream oss;
oss << "SCHED_ACTION with id = " << sa_id << " doesn't exist";
att.resp_msg = oss.str();
failure_response(INTERNAL, att);
return;
}
}
else
{
failure_response(NO_EXISTS, att);
return;
}
/* ---------------------------------------------------------------------- */
/* Update the ScheduledAction */
/* ---------------------------------------------------------------------- */
if (auto sa = sapool->get(sa_id))
{
if (sa->parse(v_sa, 0, att.resp_msg) == -1)
{
failure_response(INTERNAL, att);
return;
}
sapool->update(sa.get());
}
att.resp_obj = PoolObjectSQL::SCHEDULEDACTION;
att.resp_id = sa_id;
success_response(sa_id, att);
}

View File

@ -26,6 +26,7 @@
#include "IPAMManager.h"
#include "MarketPlaceManager.h"
#include "BackupJobPool.h"
#include "ClusterPool.h"
#include "DatastorePool.h"
#include "DocumentPool.h"
@ -42,6 +43,7 @@
#include "VMTemplatePool.h"
#include "VNTemplatePool.h"
#include "ZonePool.h"
#include "ScheduledActionPool.h"
using namespace std;
@ -1036,3 +1038,51 @@ HookDelete::HookDelete():
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
BackupJobDelete::BackupJobDelete():
RequestManagerDelete("one.backupjob.delete",
"Deletes a Backup Job")
{
Nebula& nd = Nebula::instance();
pool = nd.get_bjpool();
auth_object = PoolObjectSQL::BACKUPJOB;
};
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
int BackupJobDelete::drop(std::unique_ptr<PoolObjectSQL> object, bool r, RequestAttributes& att)
{
BackupJob * bj = static_cast<BackupJob *>(object.get());
std::set<int> sa_ids(bj->sched_actions().get_collection());
int rc = RequestManagerDelete::drop(std::move(object), false, att);
if (rc != 0)
{
return rc;
}
auto sapool = Nebula::instance().get_sapool();
string error;
rc = 0;
for (const auto& id: sa_ids)
{
if (auto sa = sapool->get(id))
{
rc += sapool->drop(sa.get(), error);
}
}
if ( rc != 0 )
{
att.resp_msg = "BackupJob deleted, but some associated schedules could not be removed";
return -1;
}
return rc;
}

View File

@ -19,6 +19,7 @@
#include "VirtualMachineDisk.h"
#include "Nebula.h"
#include "VirtualRouterPool.h"
#include "ScheduledActionPool.h"
using namespace std;
@ -291,3 +292,4 @@ void VirtualNetworkInfo::to_xml(RequestAttributes& att, PoolObjectSQL * object,
static_cast<VirtualNetwork*>(object)->to_xml_extended(str, vms, vnets, vrs);
};

View File

@ -16,6 +16,7 @@
#include "RequestManagerLock.h"
#include "Nebula.h"
#include "BackupJobPool.h"
#include "DocumentPool.h"
#include "HookPool.h"
#include "ImagePool.h"
@ -398,3 +399,27 @@ HookUnlock::HookUnlock()
auth_object = PoolObjectSQL::HOOK;
pool = nd.get_hkpool();
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
BackupJobLock::BackupJobLock()
: RequestManagerLock("one.backupjob.lock",
"Lock a Backup Job")
{
Nebula& nd = Nebula::instance();
auth_object = PoolObjectSQL::BACKUPJOB;
pool = nd.get_bjpool();
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
BackupJobUnlock::BackupJobUnlock()
: RequestManagerUnlock("one.backupjob.unlock",
"Unlock a BackupJob")
{
Nebula& nd = Nebula::instance();
auth_object = PoolObjectSQL::BACKUPJOB;
pool = nd.get_bjpool();
}

View File

@ -18,6 +18,7 @@
#include "HookLog.h"
#include "Nebula.h"
#include "AuthManager.h"
#include "BackupJobPool.h"
#include "ClusterPool.h"
#include "DatastorePool.h"
#include "DocumentPool.h"
@ -1130,3 +1131,16 @@ void HookLogInfo::request_execute(xmlrpc_c::paramList const& _paramList,
return;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
BackupJobPoolInfo::BackupJobPoolInfo()
: RequestManagerPoolInfoFilter("one.backupjobpool.info",
"Returns the Backup Job pool",
"A:siii")
{
Nebula& nd = Nebula::instance();
pool = nd.get_bjpool();
auth_object = PoolObjectSQL::BACKUPJOB;
}

View File

@ -15,6 +15,7 @@
/* -------------------------------------------------------------------------- */
#include "RequestManagerSchedAction.h"
#include "ScheduledActionPool.h"
using namespace std;
@ -30,24 +31,79 @@ void RequestManagerSchedAdd::request_execute(xmlrpc_c::paramList const& paramLis
return;
}
auto vm = pool->get<VirtualMachine>(oid);
time_t stime;
if ( !vm )
if ( auto vm = pool->get_ro<VirtualMachine>(oid) )
{
stime = vm->get_stime();
}
else
{
att.resp_id = oid;
failure_response(NO_EXISTS, att);
return;
}
if ( vm->sched_action_add(template_str, att.resp_msg) != 0 )
/* ---------------------------------------------------------------------- */
/* Parse input template and create ScheduledAction object */
/* ---------------------------------------------------------------------- */
auto sapool = Nebula::instance().get_sapool();
auto tmpl = std::make_unique<Template>();
if (tmpl->parse_str_or_xml(template_str, att.resp_msg) != 0)
{
failure_response(INTERNAL, att);
return;
}
pool->update(vm.get());
const VectorAttribute * va = tmpl->get("SCHED_ACTION");
success_response(oid, att);
if ( va == nullptr )
{
att.resp_msg = "No SCHED_ACTION attribute in template";
failure_response(ACTION, att);
return;
}
auto sa_id = sapool->allocate(PoolObjectSQL::VM, oid, stime, va, att.resp_msg);
if ( sa_id < 0 )
{
failure_response(ACTION, att);
return;
}
/* ---------------------------------------------------------------------- */
/* Update the VirtualMachine to add the new ScheduledAction */
/* ---------------------------------------------------------------------- */
if (auto vm = pool->get<VirtualMachine>(oid))
{
vm->sched_actions().add(sa_id);
pool->update(vm.get());
}
else
{
att.resp_id = oid;
// VM no longer exists, cleanup the Scheduled Action
if (auto sa = sapool->get(sa_id))
{
string err;
sapool->drop(sa.get(), err);
}
failure_response(NO_EXISTS, att);
return;
}
att.resp_obj = PoolObjectSQL::SCHEDULEDACTION;
att.resp_id = sa_id;
success_response(sa_id, att);
return;
}
@ -66,24 +122,43 @@ void RequestManagerSchedDelete::request_execute(xmlrpc_c::paramList const& param
return;
}
auto vm = pool->get<VirtualMachine>(oid);
if ( auto vm = pool->get<VirtualMachine>(oid) )
{
if ( vm->sched_actions().del(sched_id) == -1 )
{
att.resp_obj = PoolObjectSQL::SCHEDULEDACTION;
att.resp_id = sched_id;
if ( !vm )
failure_response(NO_EXISTS, att);
return;
}
pool->update(vm.get());
}
else
{
att.resp_id = oid;
failure_response(NO_EXISTS, att);
return;
}
if ( vm->sched_action_delete(sched_id, att.resp_msg) != 0 )
auto& nd = Nebula::instance();
auto sapool = nd.get_sapool();
if (auto sa = sapool->get(sched_id))
{
failure_response(INTERNAL, att);
return;
if (sapool->drop(sa.get(), att.resp_msg) != 0)
{
failure_response(ACTION, att);
return;
}
}
pool->update(vm.get());
att.resp_obj = PoolObjectSQL::SCHEDULEDACTION;
att.resp_id = sched_id;
success_response(oid, att);
success_response(sched_id, att);
return;
}
@ -94,8 +169,9 @@ void RequestManagerSchedDelete::request_execute(xmlrpc_c::paramList const& param
void RequestManagerSchedUpdate::request_execute(xmlrpc_c::paramList const& paramList,
RequestAttributes& att)
{
int oid = paramList.getInt(1);
int oid = paramList.getInt(1);
int sched_id = paramList.getInt(2);
string template_str = paramList.getString(3);
if ( basic_authorization(oid, att) == false )
@ -103,24 +179,76 @@ void RequestManagerSchedUpdate::request_execute(xmlrpc_c::paramList const& param
return;
}
auto vm = pool->get<VirtualMachine>(oid);
/* ---------------------------------------------------------------------- */
/* Parse input template and get SCHED_ACTION attribute */
/* ---------------------------------------------------------------------- */
auto tmpl = std::make_unique<Template>();
if ( !vm )
{
att.resp_id = oid;
failure_response(NO_EXISTS, att);
return;
}
if ( vm->sched_action_update(sched_id, template_str, att.resp_msg) != 0 )
if (tmpl->parse_str_or_xml(template_str, att.resp_msg) != 0)
{
failure_response(INTERNAL, att);
return;
}
pool->update(vm.get());
const VectorAttribute * v_sa = tmpl->get("SCHED_ACTION");
success_response(oid, att);
if ( v_sa == nullptr )
{
att.resp_msg = "No SCHED_ACTION attribute in template";
failure_response(INTERNAL, att);
return;
}
/* ---------------------------------------------------------------------- */
/* Check Scheduled Action association */
/* ---------------------------------------------------------------------- */
time_t stime;
if ( auto vm = pool->get<VirtualMachine>(oid) )
{
stime = vm->get_stime();
if (!vm->sched_actions().contains(sched_id))
{
std::ostringstream oss;
oss << "SCHED_ACTION with id = " << sched_id << " doesn't exist";
att.resp_msg = oss.str();
failure_response(INTERNAL, att);
return;
}
}
else
{
att.resp_id = oid;
failure_response(NO_EXISTS, att);
return;
}
/* ---------------------------------------------------------------------- */
/* Update the ScheduledAction */
/* ---------------------------------------------------------------------- */
auto sapool = Nebula::instance().get_sapool();
if (auto sa = sapool->get(sched_id))
{
if (sa->parse(v_sa, stime, att.resp_msg) == -1)
{
failure_response(INTERNAL, att);
return;
}
sapool->update(sa.get());
}
att.resp_obj = PoolObjectSQL::SCHEDULEDACTION;
att.resp_id = sched_id;
success_response(sched_id, att);
return;
}

File diff suppressed because it is too large Load Diff

View File

@ -54,6 +54,7 @@ source_files=[
'RequestManagerSecurityGroup.cc',
'RequestManagerVNTemplate.cc',
'RequestManagerHook.cc',
'RequestManagerBackupJob.cc',
'RequestManagerSchedAction.cc'
]

31
src/sam/SConstruct Normal file
View File

@ -0,0 +1,31 @@
# SConstruct for src/log
# -------------------------------------------------------------------------- #
# Copyright 2002-2023, OpenNebula Project, OpenNebula Systems #
# #
# 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_sam'
# Sources to generate the library
source_files=[
'ScheduledAction.cc',
'ScheduledActionPool.cc',
'ScheduledActionManager.cc'
]
# Build library
env.StaticLibrary(lib_name, source_files)

631
src/sam/ScheduledAction.cc Normal file
View File

@ -0,0 +1,631 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2023, OpenNebula Project, OpenNebula Systems */
/* */
/* 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 "ScheduledAction.h"
#include "Nebula.h"
#include "OneDB.h"
using namespace std;
std::set<std::string> ScheduledAction::VM_ACTIONS = {
"terminate",
"terminate-hard",
"undeploy",
"undeploy-hard",
"hold",
"release",
"stop",
"suspend",
"resume",
"reboot",
"reboot-hard",
"poweroff",
"poweroff-hard",
"snapshot-create",
"snapshot-revert",
"snapshot-delete",
"disk-snapshot-create",
"disk-snapshot-revert",
"disk-snapshot-delete",
"backup"
};
std::set<PoolObjectSQL::ObjectType> ScheduledAction::SCHED_OBJECTS = {
PoolObjectSQL::VM,
PoolObjectSQL::BACKUPJOB
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
ScheduledAction::ScheduledAction(PoolObjectSQL::ObjectType type,
int parent_id)
: PoolObjectSQL(-1, SCHEDULEDACTION, "", -1, -1, "", "", one_db::scheduled_action_table)
, _type(type)
, _parent_id(parent_id)
, _action("")
, _args("")
, _time(-1)
, _repeat(NONE)
, _days("")
, _end_type(END_NONE)
, _end_value(-1)
, _done(-1)
, _message("")
{
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
string& ScheduledAction::to_xml(string& xml) const
{
ostringstream oss;
oss << "<SCHED_ACTION>"
<< "<ID>" << oid << "</ID>"
<< "<PARENT_ID>" << _parent_id << "</PARENT_ID>"
<< "<TYPE>" << type_to_str(_type) << "</TYPE>"
<< "<ACTION>" << _action << "</ACTION>"
<< "<ARGS>" << _args << "</ARGS>"
<< "<TIME>" << _time << "</TIME>"
<< "<REPEAT>" << _repeat << "</REPEAT>"
<< "<DAYS>" << _days << "</DAYS>"
<< "<END_TYPE>" << _end_type << "</END_TYPE>"
<< "<END_VALUE>" << _end_value << "</END_VALUE>"
<< "<DONE>" << _done << "</DONE>"
<< "<MESSAGE>" << _message << "</MESSAGE>"
<< "</SCHED_ACTION>";
xml = oss.str();
return xml;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int ScheduledAction::parse(const VectorAttribute * va, time_t origin, string& error_str)
{
string tmp_str;
switch (_type)
{
case PoolObjectSQL::BACKUPJOB:
_action = "backup";
break;
case PoolObjectSQL::VM:
if (va->vector_value("ACTION", tmp_str) == 0 && !tmp_str.empty())
{
if ( VM_ACTIONS.find(tmp_str) == VM_ACTIONS.end() )
{
error_str = tmp_str + " is not supported.";
return -1;
}
_action = tmp_str;
}
break;
default:
error_str = "Not supported object type";
return -1;
};
if (_action.empty())
{
error_str = "No ACTION in template for Scheduled Action.";
return -1;
}
tmp_str.clear();
if (va->vector_value("TIME", tmp_str) == 0 && !tmp_str.empty())
{
_time = parse_time(tmp_str, origin);
}
if (_time == -1)
{
error_str = "Unable to parse the time value or value is empty: " + tmp_str;
return -1;
}
int tmp_int;
if (va->vector_value("REPEAT", tmp_int) == 0)
{
if (tmp_int >= NONE && tmp_int <= HOURLY)
{
_repeat = static_cast<Repeat>(tmp_int);
}
else
{
error_str = "Wrong REPEAT value: " + tmp_int;
return -1;
}
}
if (_repeat == NONE)
{
_days = "";
}
else if (va->vector_value("DAYS", _days) == 0)
{
if (!days_in_range(error_str))
{
return -1;
}
}
else if (_days.empty())
{
error_str = "Repeat set, but DAYS are empty";
return -1;
}
if (va->vector_value("END_TYPE", tmp_int) == 0)
{
if (tmp_int >= END_NONE && tmp_int <= DATE)
{
_end_type = static_cast<EndOn>(tmp_int);
}
else
{
error_str = "Wrong END_TYPE value: " + tmp_int;
return -1;
}
}
if (_end_type <= NEVER)
{
_end_value = -1;
}
else if (va->vector_value("END_VALUE", _end_value) == 0)
{
if (ends_in_range(error_str))
{
return -1;
}
}
else if (_end_value < 0)
{
error_str = "END_TYPE set, but END_VALUE is empty";
}
if (va->vector_value("ARGS", tmp_str) == 0)
{
_args = tmp_str;
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool ScheduledAction::days_in_range(std::string& error)
{
static const char * e[] = {
"Days in a week have to be in [0,6] range", //WEEKLY - 0
"Days in a month have to be in [1,31] range", // MONTHLY - 1
"Days in a year have to be in [0,365] range", // YEARLY - 2
"Hours have to be in [0,168] range" // HOURLY - 3
};
static int fday[] = {0,1,0,1};
static int lday[] = {7,32,366,168};
bool extra_check;
std::set<int> d;
one_util::split_unique<int>(_days, ',', d);
if ( d.empty() && _repeat > NONE)
{
error = "Scheduled Action repeat set, but DAYS are empty";
return false;
}
int _fday = *(d.begin());
int _lday = *(d.rbegin());
switch(_repeat)
{
case WEEKLY:
case MONTHLY:
case YEARLY:
extra_check = false;
break;
case HOURLY:
extra_check = d.size() != 1;
break;
case NONE:
return d.empty();
}
if ( _fday < fday[_repeat] || _lday >= lday[_repeat] || extra_check )
{
error = e[_repeat];
return false;
}
return true;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int ScheduledAction::ends_in_range(std::string& error)
{
if ( _end_type == TIMES && _end_value < 0 )
{
error = "Error parsing END_VALUE, times has to be greater or equal to 0";
return -1;
}
else if ( _end_type == DATE )
{
struct tm val_tm;
localtime_r((time_t *)&_end_value, &val_tm);
time_t out = mktime(&val_tm);
if (out == -1)
{
error = "Error parsing END_VALUE, wrong format for date.";
return -1;
}
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
bool ScheduledAction::is_due()
{
// -------------------------------------------------------------------------
// Check action has already finished (END_TYPE and END_VALUE defined)
// -------------------------------------------------------------------------
bool has_ended = false;
switch (_end_type)
{
case END_NONE:
case NEVER:
has_ended = false;
break;
case TIMES:
has_ended = _end_value <= 0;
break;
case DATE:
has_ended = time(0) > _end_value;
break;
}
if (has_ended)
{
return false;
}
// -------------------------------------------------------------------------
// Check if the action has been completed
// -------------------------------------------------------------------------
if (_done > 0 && _done >= _time)
{
return false; //Action has been already completed
}
return _time < time(0); //Action is due
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
time_t ScheduledAction::next_action()
{
time_t current = time(0);
_done = current;
if (_repeat == NONE)
{
return -1;
}
std::set<int> days_set;
one_util::split_unique<int>(_days, ',', days_set);
if ( days_set.empty() )
{
return -1;
}
/* --------------------------------------------------------------------- */
/* Check if action is already finished */
/* --------------------------------------------------------------------- */
if (_end_type == TIMES)
{
if (_end_value <= 0)
{
return -1;
}
--_end_value;
}
else if (_end_type == DATE)
{
if (time(0) > _end_value)
{
return -1;
}
}
/* --------------------------------------------------------------------- */
/* Compute next event for the action - HOURLY */
/* --------------------------------------------------------------------- */
if ( _repeat == HOURLY )
{
do {
_time += *(days_set.begin()) * 3600;
} while (_time < current);
return _time;
}
/* --------------------------------------------------------------------- */
/* Compute next event for the action - WEEKLY, MONTHLY & YEARLY */
/* --------------------------------------------------------------------- */
struct tm current_tm;
int cday;
localtime_r(&current, &current_tm);
switch(_repeat)
{
case WEEKLY:
cday = current_tm.tm_wday;
break;
case MONTHLY:
cday = current_tm.tm_mday;
break;
case YEARLY:
cday = current_tm.tm_yday;
break;
case HOURLY:
case NONE:
return -1;
}
int delta = 0;
if (cday < *(days_set.begin())) //before first day in range
{
delta = *(days_set.begin()) - cday;
}
else if (cday >= *(days_set.rbegin())) //after or last day in range
{
int pdays = days_in_period(current_tm.tm_mon, current_tm.tm_year);
delta = pdays - cday + *(days_set.begin()); //assume start day is 0
}
else //day in range
{
auto nday_it = days_set.upper_bound(cday);
delta = *nday_it - cday;
}
_time += delta * 24 * 3600;
return _time;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int ScheduledAction::rebuild_attributes()
{
int tmp_int;
string tmp_str;
int rc = 0;
rc += xpath(oid, "/SCHED_ACTION/ID", -1);
rc += xpath(_parent_id, "/SCHED_ACTION/PARENT_ID", -1);
rc += xpath(_action, "/SCHED_ACTION/ACTION", "");
rc += xpath(_args, "/SCHED_ACTION/ARGS", "");
rc += xpath(_time, "/SCHED_ACTION/TIME",(time_t) -1);
rc += xpath(_done, "/SCHED_ACTION/DONE",(time_t) -1);
rc += xpath(_days, "/SCHED_ACTION/DAYS", "");
rc += xpath(_message, "/SCHED_ACTION/MESSAGE", "");
rc += xpath(_end_value, "/SCHED_ACTION/END_VALUE", (time_t)-1);
rc += xpath(tmp_str, "/SCHED_ACTION/TYPE", "");
_type = str_to_type(tmp_str);
rc += xpath(tmp_int, "/SCHED_ACTION/REPEAT", static_cast<int>(NONE));
_repeat = static_cast<Repeat>(tmp_int);
rc += xpath(tmp_int, "/SCHED_ACTION/END_TYPE", static_cast<int>(END_NONE));
_end_type = static_cast<EndOn>(tmp_int);
if (rc != 0)
{
NebulaLog::error("SCH", "Unable to create ScheduledAction from xml");
return -1;
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
time_t ScheduledAction::parse_time(std::string str_time, time_t origin)
{
time_t action_time;
std::istringstream iss;
if ( str_time[0] == '+' )
{
str_time.erase(0, 1);
}
else
{
origin = 0;
}
iss.str(str_time);
iss >> action_time;
if (iss.fail() || !iss.eof())
{
return -1;
}
action_time += origin;
return action_time;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int ScheduledAction::days_in_period(int month, int year)
{
static map<int, int> MONTHS_DAYS = {{0, 31}, {1, 28}, {2, 31}, {3, 30},
{4, 31}, {5, 30}, {6, 31}, {7, 31}, {8, 30}, {9, 31}, {10, 30},
{11, 31}};
int leap_year = 0;
int leap_month = 0;
year += 1900;
if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
{
leap_year = 1;
if ( month == 1 )
{
leap_month = 1;
}
}
switch(_repeat)
{
case WEEKLY:
return 7;
//Return value for months assume month day starts in 0
case MONTHLY:
return MONTHS_DAYS[month] + leap_month;
case YEARLY:
return 365 + leap_year;
case HOURLY:
case NONE:
return 0;
}
return 0;
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int ScheduledAction::insert(SqlDB * db, std::string& error_str)
{
if ( SCHED_OBJECTS.find(_type) == SCHED_OBJECTS.end() )
{
error_str = PoolObjectSQL::type_to_str(_type) + " is not supported.";
NebulaLog::error("SCH", error_str);
return -1;
}
return insert_replace(db, false, error_str);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int ScheduledAction::insert_replace(SqlDB *db, bool replace, std::string& error_str)
{
ostringstream oss;
string tmp;
char * sql_xml;
int rc;
sql_xml = db->escape_str(to_xml(tmp));
if ( sql_xml == 0 )
{
error_str = "Error creating Scheduled Action XML.";
return -1;
}
if ( validate_xml(sql_xml) != 0 )
{
error_str = "Error validating Scheduled Action XML.";
return -1;
}
if(replace)
{
oss << "UPDATE " << one_db::scheduled_action_table << " SET "
<< "body = '" << sql_xml << "', "
<< "time = " << _time << ", "
<< "done = " << _done
<< " WHERE oid = " << oid;
}
else
{
oss << "INSERT INTO " << one_db::scheduled_action_table
<< " (" << one_db::scheduled_action_db_names << ") VALUES ("
<< oid << ","
<< _parent_id << ","
<< "'" << type_to_str(_type) << "',"
<< "'" << sql_xml << "',"
<< _time << ","
<< _done << ")";
}
rc = db->exec_wr(oss);
db->free_str(sql_xml);
if (rc != 0)
{
error_str = "Error inserting ScheduledAction to DB, the SQL querry was: " + oss.str();
}
return rc;
}

View File

@ -0,0 +1,675 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2023, OpenNebula Project, OpenNebula Systems */
/* */
/* 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 "ScheduledActionManager.h"
#include "Nebula.h"
#include "BackupJob.h"
#include "BackupJobPool.h"
#include "ScheduledActionPool.h"
#include "VirtualMachinePool.h"
#include "DispatchManager.h"
#include "RequestManagerVirtualMachine.h"
using namespace std;
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
ScheduledActionManager::ScheduledActionManager(time_t timer,
int max_backups,
int max_backups_host)
: timer_thread(timer, [this](){timer_action();})
, _max_backups(max_backups)
, _max_backups_host(max_backups_host)
{
NebulaLog::info("SCH", "Staring Scheduled Action Manager...");
auto& nd = Nebula::instance();
bj_pool = nd.get_bjpool();
vm_pool = nd.get_vmpool();
sa_pool = nd.get_sapool();
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void ScheduledActionManager::finalize()
{
timer_thread.stop();
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void ScheduledActionManager::timer_action()
{
scheduled_vm_actions();
update_backup_counters();
run_vm_backups();
scheduled_backup_jobs();
backup_jobs();
vm_backups.clear();
host_backups.clear();
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void ScheduledActionManager::scheduled_vm_actions()
{
// Get due Scheduled Actions from DB (only one action per VM)
auto actions_to_launch = sa_pool->get_is_due_actions(PoolObjectSQL::VM);
set<int> processed_vms;
for (const auto& action : actions_to_launch)
{
auto vm_id = action.second;
if (processed_vms.count(vm_id) > 0)
{
continue;
}
processed_vms.insert(vm_id);
auto sa = sa_pool->get_ro(action.first);
if (!sa)
{
continue;
}
if (sa->action() == "backup")
{
vm_backups.push_back(action);
return;
}
auto aname = sa->action();
sa.release();
run_scheduled_action_vm(vm_id, action.first, aname);
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void ScheduledActionManager::update_backup_counters()
{
// Read VMs in backup state, make a map with host backups count
vector<int> backups;
vm_pool->get_backup(backups);
active_backups = backups.size();
for (auto vm_id : backups)
{
auto vm = vm_pool->get_ro(vm_id);
if (!vm)
{
continue;
}
auto hid = vm->get_hid();
auto it = host_backups.find(hid);
if ( it == host_backups.end() )
{
host_backups.insert(std::pair<int, int>(hid, 1));
}
else
{
++it->second;
}
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void ScheduledActionManager::run_vm_backups()
{
for (auto backup : vm_backups)
{
int sa_id = backup.first;
int vm_id = backup.second;
/* ------------------------------------------------------------------ */
/* Backup jobs consistency checks: */
/* - Active backups vs max_backups */
/* - Active backups in host per max_backups_host */
/* - VM still exists */
/* ------------------------------------------------------------------ */
if (_max_backups != 0 && active_backups >= _max_backups)
{
ostringstream oss;
oss << "Reached max number of active backups (" << _max_backups << ")";
NebulaLog::debug("SCH", oss.str());
break;
}
auto vm = vm_pool->get_ro(vm_id);
if (!vm)
{
ostringstream oss;
oss << "Unable scheduled backup for non-exist VM: " << vm_id;
NebulaLog::debug("SCH", oss.str());
continue;
}
// Check max backups host
int hid = vm->get_hid();
if (_max_backups_host != 0 && host_backups[hid] >= _max_backups_host)
{
std::ostringstream oss;
oss << "Reached max number of host backups (" << _max_backups_host
<< ") for host " << vm->get_hid();
NebulaLog::debug("SCH", oss.str());
break;
}
vm.reset();
run_scheduled_action_vm(vm_id, sa_id, "backup");
/* ------------------------------------------------------------------ */
/* Update backup counters */
/* ------------------------------------------------------------------ */
++active_backups;
++host_backups[hid];
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void ScheduledActionManager::scheduled_backup_jobs()
{
// Get IDs of Backup Jobs with due Scheduled Actions from DB
auto actions_to_launch = sa_pool->get_is_due_actions(PoolObjectSQL::BACKUPJOB);
set<int> processed_bjs;
for (const auto& action : actions_to_launch)
{
std::ostringstream oss;
std::string error;
auto bj_id = action.second;
if (processed_bjs.count(bj_id) > 0)
{
continue;
}
processed_bjs.insert(bj_id);
auto bj = bj_pool->get(bj_id);
auto sa = sa_pool->get(action.first);
if (!bj || !sa)
{
continue;
}
oss << "Executing action '" << sa->action() << "' for Backup Job "
<< bj->get_oid() << " : ";
if (bj->execute(error) == 0)
{
sa->log_error("");
sa->next_action();
oss << "Success.";
NebulaLog::info("SCH", oss.str());
}
else
{
std::ostringstream oss_aux;
oss_aux << one_util::log_time(time(0)) << " : " << error;
sa->log_error(oss_aux.str());
oss << "Failure. " << error;
NebulaLog::error("SCH", oss.str());
}
sa_pool->update(sa.get());
bj_pool->update(bj.get());
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void ScheduledActionManager::backup_jobs()
{
// Get Backup Jobs by priority and start VM backups
auto bj_ids = bj_pool->active();
for (auto bj_id : bj_ids)
{
auto bj = bj_pool->get(bj_id);
if (!bj)
{
continue;
}
// Copy (not reference) of outdated and backing_up vms (modified in loop)
auto vms = bj->backup_vms();
auto outdated = bj->outdated();
auto backing_up = bj->backing_up();
auto mode = bj->exec_mode();
auto ds_id = bj->ds_id();
auto reset = bj->reset();
for (auto vm_id : vms)
{
if (!outdated.count(vm_id))
{
continue;
}
/* -------------------------------------------------------------- */
/* Backup jobs consistency checks: */
/* - Active backups vs SEQUENTIAL */
/* - Active backups vs max_backups */
/* - Active backups in host per max_backups_host */
/* - VM is not in DONE */
/* - VM still exists */
/* -------------------------------------------------------------- */
if (mode == BackupJob::SEQUENTIAL && backing_up.size() >= 1)
{
ostringstream oss;
oss << "BackupJob " << bj_id << ": waiting for a active backup to complete";
NebulaLog::debug("SCH", oss.str());
break;
}
if (_max_backups != 0 && active_backups >= _max_backups)
{
ostringstream oss;
oss << "Reached max number of active backups (" << _max_backups << ")";
NebulaLog::debug("SCH", oss.str());
break;
}
auto vm = vm_pool->get(vm_id);
if (!vm)
{
ostringstream oss;
bj->remove_vm(vm_id);
oss << "Backup Job " << bj_id << ": Remove non-exist VM " << vm_id;
NebulaLog::debug("SCH", oss.str());
continue;
}
if (vm->get_state() == VirtualMachine::DONE)
{
ostringstream oss;
bj->remove_vm(vm_id);
oss << "Backup Job " << bj_id << ": Removing done VM " << vm_id;
NebulaLog::debug("SCH", oss.str());
continue;
}
int hid = vm->get_hid();
if (_max_backups_host != 0 && host_backups[hid] >= _max_backups_host)
{
std::ostringstream oss;
oss << "Reached max number of backups (" << _max_backups_host
<< ") for host " << hid;
NebulaLog::debug("SCH", oss.str());
break;
}
/* -------------------------------------------------------------- */
/* Create a backup condiguration for VM & set Backup Job */
/* -------------------------------------------------------------- */
auto& backups = vm->backups();
bool bck_vol = false;
if (bj->get_template_attribute("BACKUP_VOLATILE", bck_vol))
{
bck_vol = backups.do_volatile();
}
bool inc = vm->get_disks().backup_increment(bck_vol) && !vm->has_snapshots();
string err;
Template tmpl;
bj->get_backup_config(tmpl);
if ( backups.parse(&tmpl, inc, true, err) != 0 )
{
bj->set_template_error_message(err);
bj->add_error(vm_id);
NebulaLog::error("SCH", err);
continue;
}
backups.backup_job_id(bj_id);
vm_pool->update(vm.get());
vm.reset();
/* -------------------------------------------------------------- */
/* Launch backup, notify backup job */
/* -------------------------------------------------------------- */
VirtualMachineBackup vm_backup;
RequestAttributes ra(AuthRequest::ADMIN,
UserPool::ONEADMIN_ID,
GroupPool::ONEADMIN_ID,
PoolObjectSQL::VM);
auto ec = vm_backup.request_execute(ra, vm_id, ds_id, reset);
if ( ec != Request::SUCCESS)
{
err = Request::failure_message(ec, ra, "backup");
bj->set_template_error_message(err);
bj->add_error(vm_id);
NebulaLog::error("SCH", err);
continue;
}
bj->backup_started(vm_id);
/* -------------------------------------------------------------- */
/* Update backup counters */
/* -------------------------------------------------------------- */
++active_backups;
++host_backups[hid];
}
bj_pool->update(bj.get());
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void ScheduledActionManager::run_scheduled_action_vm(int vm_id, int sa_id, const std::string& aname)
{
std::ostringstream oss;
oss << "Executing action '" << aname << "' for VM " << vm_id << " : ";
string error;
auto rc = vm_action_call(vm_id, sa_id, error);
auto sa = sa_pool->get(sa_id);
if ( !sa )
{
return;
}
if (rc == 0)
{
sa->log_error("");
sa->next_action();
oss << "Success.";
}
else
{
std::ostringstream oss_aux;
std::string time_str = one_util::log_time(time(0));
oss_aux << time_str << " : " << error;
sa->log_error(oss_aux.str());
oss << "Failure. " << error;
}
sa_pool->update(sa.get());
NebulaLog::info("SCH", oss.str());
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
static bool parse_args(std::queue<std::string>& tokens)
{
return true;
}
/**
* Parses tokens to specific value with given type
*
* @param tokens values to parse
* @param value given type to parse it
*
* @return 0 on success, -1 otherwise
*/
template<typename T, typename... Args>
static bool parse_args(std::queue<std::string>& tokens, T& value, Args&... args)
{
if (tokens.empty())
{
return false;
}
bool rc = one_util::str_cast(tokens.front(), value);
tokens.pop();
if (!rc)
{
return false;
}
return parse_args(tokens, args...);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int ScheduledActionManager::vm_action_call(int vmid, int sa_id, string& error)
{
auto sa = sa_pool->get_ro(sa_id);
const string& aname = sa->action();
const string& args_st = sa->args();
Request::ErrorCode ec;
stringstream ss(args_st);
queue<string> args;
string tmp_arg;
while (getline(ss, tmp_arg, ','))
{
args.push(tmp_arg);
}
RequestAttributes ra(AuthRequest::ADMIN,
UserPool::ONEADMIN_ID,
GroupPool::ONEADMIN_ID,
PoolObjectSQL::VM);
if (aname == "snapshot-create")
{
string name;
if (!parse_args(args, name))
{
error = "Missing or malformed ARGS for: snapshot-create."
" Format: snapshot-name";
return -1;
}
VirtualMachineSnapshotCreate request;
ec = request.request_execute(ra, vmid, name);
}
else if (aname == "snapshot-revert")
{
int snapid = 0;
if (!parse_args(args, snapid))
{
error = "Missing or malformed ARGS for: snapshot-revert."
" Format: snapshot-id";
return -1;
}
VirtualMachineSnapshotRevert request;
ec = request.request_execute(ra, vmid, snapid);
}
else if (aname == "snapshot-delete")
{
int snapid = 0;
if (!parse_args(args, snapid))
{
error = "Missing or malformed ARGS for: snapshot-delete."
" Format: snapshot-id";
return -1;
}
VirtualMachineSnapshotDelete request;
ec = request.request_execute(ra, vmid, snapid);
}
else if (aname == "disk-snapshot-create")
{
int diskid = 0;
string name;
if (!parse_args(args, diskid, name))
{
error = "Missing or malformed ARGS for: disk-snapshot-create."
" Format: disk-id, snapshot-name";
return -1;
}
VirtualMachineDiskSnapshotCreate request;
ec = request.request_execute(ra, vmid, diskid, name);
}
else if (aname == "disk-snapshot-revert")
{
int diskid = 0, snapid = 0;
if (!parse_args(args, diskid, snapid))
{
error = "Missing or malformed ARGS for: disk-snapshot-revert."
" Format: disk-id, snapshot-id";
return -1;
}
VirtualMachineDiskSnapshotRevert request;
ec = request.request_execute(ra, vmid, diskid, snapid);
}
else if (aname == "disk-snapshot-delete")
{
int diskid = 0, snapid = 0;
if (!parse_args(args, diskid, snapid))
{
error = "Missing or malformed ARGS for: disk-snapshot-delete."
" Format: disk-id, snapshot-id";
return -1;
}
VirtualMachineDiskSnapshotDelete request;
ec = request.request_execute(ra, vmid, diskid, snapid);
}
else if (aname == "backup")
{
int dsid = -1;
bool reset = false;
if (!parse_args(args, dsid, reset))
{
error = "Missing or malformed ARGS for: backup."
" Format: datastore-id, reset";
return -1;
}
VirtualMachineBackup request;
ec = request.request_execute(ra, vmid, dsid, reset);
}
else
{
VirtualMachineAction req;
ec = req.request_execute(ra, aname, vmid);
}
if (ec != Request::SUCCESS)
{
error = Request::failure_message(ec, ra, aname);
NebulaLog::error("SCH", error);
return -1;
}
return 0;
}

View File

@ -0,0 +1,143 @@
/* -------------------------------------------------------------------------- */
/* Copyright 2002-2023, OpenNebula Project, OpenNebula Systems */
/* */
/* 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 "ScheduledActionPool.h"
#include "NebulaLog.h"
using namespace std;
int ScheduledActionPool::allocate(PoolObjectSQL::ObjectType type,
int parent_id,
time_t origin,
const VectorAttribute * va,
string& error_str)
{
auto sched = new ScheduledAction(type, parent_id);
if (sched->parse(va, origin, error_str) != 0)
{
delete sched;
NebulaLog::error("SCH", error_str);
return -1;
}
return PoolSQL::allocate(sched, error_str);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int ScheduledActionPool::bootstrap(SqlDB *_db)
{
ostringstream oss(one_db::scheduled_action_db_bootstrap);
return _db->exec_local_wr(oss);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int ScheduledActionPool::dump(const std::set<int> &actions, std::string& oss)
{
if (actions.empty())
{
return 0;
}
ostringstream oid_filter;
bool first = true;
for (const auto& id: actions)
{
if ( first )
{
oid_filter << "oid = " << id;
first = false;
}
else
{
oid_filter << " OR oid = " << id;
}
}
return PoolSQL::dump(oss, string(), "body", one_db::scheduled_action_table,
oid_filter.str(), 0, -1, false);
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
template<typename T1, typename T2>
class vector_pair_cb : public Callbackable
{
public:
void set_callback(std::vector<std::pair<T1, T2>> * _map)
{
result = _map;
Callbackable::set_callback(
static_cast<Callbackable::Callback>(&vector_pair_cb::callback), 0);
};
int callback(void * nil, int num, char **values, char **names)
{
if ( num < 2 || values == 0 || values[0] == 0 || values[1] == 0)
{
return -1;
}
T1 key;
T2 value;
one_util::str_cast(values[0], key);
one_util::str_cast(values[1], value);
result->push_back(std::make_pair(key, value));
return 0;
};
private:
std::vector<std::pair<T1, T2>> * result = nullptr;
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
std::vector<std::pair<int, int>> ScheduledActionPool::get_is_due_actions(PoolObjectSQL::ObjectType ot)
{
ostringstream sql;
time_t actual_time = time(0);
vector_pair_cb<int,int> cb;
std::vector<std::pair<int, int>> actions;
cb.set_callback(&actions);
sql << "SELECT oid, parent_id FROM " << one_db::scheduled_action_table
<< " WHERE type = '" << PoolObjectSQL::type_to_str(ot) << "'"
<< " AND time < " << actual_time
<< " AND time > done "
<< " ORDER BY time";
db->exec_rd(sql, &cb);
cb.unset_callback();
return actions;
}

View File

@ -21,7 +21,7 @@
#include <map>
#include <vector>
#include "ScheduledAction.h"
#include "SchedAction.h"
class VirtualMachineActionsPoolXML;

View File

@ -95,7 +95,6 @@ protected:
delete vmpool;
delete vm_roles_pool;
delete vnetpool;
delete vmapool;
delete dspool;
delete img_dspool;
@ -125,8 +124,6 @@ protected:
VMGroupPoolXML * vmgpool = nullptr;
VirtualMachineActionsPoolXML* vmapool = nullptr;
MonitorPoolXML * hmonpool = nullptr;
// ---------------------------------------------------------------
@ -175,8 +172,6 @@ protected:
*/
virtual int set_up_pools();
virtual int do_scheduled_actions();
virtual void do_vm_groups();
private:

View File

@ -144,58 +144,6 @@ private:
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
class VirtualMachineActionsPoolXML : public VirtualMachinePoolXML
{
public:
VirtualMachineActionsPoolXML(Client* client,
unsigned int machines_limit):
VirtualMachinePoolXML(client, machines_limit, false, 0){};
virtual ~VirtualMachineActionsPoolXML(){};
/**
* Retrieves the VMs with pending actions
*
* @return 0 on success
* -1 on error
* -2 if no VMs with pending actions
*/
int set_up() override;
int active_backups() const
{
return _active_backups;
}
int host_backups(int host_id) const
{
return backups_host[host_id];
}
void add_backup(int host_id)
{
backups_host[host_id]++;
_active_backups++;
}
protected:
/**
* Total backup operations in progress
*/
mutable int _active_backups = 0;
/**
* Backup operations per host
*/
mutable std::map<int, int> backups_host;
int get_suitable_nodes(std::vector<xmlNodePtr>& content) const override;
};
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
class VirtualMachineRolePoolXML : public VirtualMachinePoolXML
{
public:

View File

@ -25,7 +25,6 @@
#include "Resource.h"
#include "VirtualMachineTemplate.h"
#include "ScheduledAction.h"
class ImageDatastorePoolXML;
@ -382,9 +381,6 @@ public:
return affined_vms;
}
//--------------------------------------------------------------------------
// Scheduled Action Interface
//--------------------------------------------------------------------------
/**
* Get the user template of the VM
* @return the template as a XML string
@ -408,23 +404,6 @@ public:
return vm_template.get();
}
/**
* Get scheduled actions of the VM
*
* @param attributes to hold the VM actions
*/
SchedActions get_actions() const
{
return SchedActions(vm_template.get());
}
/**
* Update scheduled action of the VM
*
* @param action sched action to update
*/
bool update_sched_action(const SchedAction* action);
/**
* Sets an attribute in the VM Template, it must be allocated in the heap
*

View File

@ -33,8 +33,8 @@ source_files=[
'DatastorePoolXML.cc',
'DatastoreXML.cc',
'VirtualNetworkPoolXML.cc',
'VirtualNetworkXML.cc',
'ScheduledActionXML.cc']
'VirtualNetworkXML.cc'
]
# Build library
sched_env.StaticLibrary(lib_name, source_files)

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