sync: add group filtering
like for manual pulls, but persisted in the sync job config and visible in the relevant GUI parts. GUI is read-only for now (and defaults to no filtering on creation), as this is a rather advanced feature that requires a complex GUI to be user-friendly (regex-freeform, type-combobox, remote group scanning + selector with additional freeform input). Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> Reviewed-by: Dominik Csapak <d.csapak@proxmox.com> Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
parent
71e534631f
commit
5f83d3f636
@ -403,6 +403,10 @@ pub const GROUP_FILTER_LIST_SCHEMA: Schema = ArraySchema::new("List of group fil
|
|||||||
optional: true,
|
optional: true,
|
||||||
schema: SYNC_SCHEDULE_SCHEMA,
|
schema: SYNC_SCHEDULE_SCHEMA,
|
||||||
},
|
},
|
||||||
|
groups: {
|
||||||
|
schema: GROUP_FILTER_LIST_SCHEMA,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize,Deserialize,Clone,Updater)]
|
#[derive(Serialize,Deserialize,Clone,Updater)]
|
||||||
@ -422,6 +426,8 @@ pub struct SyncJobConfig {
|
|||||||
pub comment: Option<String>,
|
pub comment: Option<String>,
|
||||||
#[serde(skip_serializing_if="Option::is_none")]
|
#[serde(skip_serializing_if="Option::is_none")]
|
||||||
pub schedule: Option<String>,
|
pub schedule: Option<String>,
|
||||||
|
#[serde(skip_serializing_if="Option::is_none")]
|
||||||
|
pub groups: Option<Vec<GroupFilter>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
|
@ -192,6 +192,8 @@ pub enum DeletableProperty {
|
|||||||
schedule,
|
schedule,
|
||||||
/// Delete the remove-vanished flag.
|
/// Delete the remove-vanished flag.
|
||||||
remove_vanished,
|
remove_vanished,
|
||||||
|
/// Delete the groups property.
|
||||||
|
groups,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
@ -254,6 +256,7 @@ pub fn update_sync_job(
|
|||||||
DeletableProperty::comment => { data.comment = None; },
|
DeletableProperty::comment => { data.comment = None; },
|
||||||
DeletableProperty::schedule => { data.schedule = None; },
|
DeletableProperty::schedule => { data.schedule = None; },
|
||||||
DeletableProperty::remove_vanished => { data.remove_vanished = None; },
|
DeletableProperty::remove_vanished => { data.remove_vanished = None; },
|
||||||
|
DeletableProperty::groups => { data.groups = None; },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -271,6 +274,7 @@ pub fn update_sync_job(
|
|||||||
if let Some(remote) = update.remote { data.remote = remote; }
|
if let Some(remote) = update.remote { data.remote = remote; }
|
||||||
if let Some(remote_store) = update.remote_store { data.remote_store = remote_store; }
|
if let Some(remote_store) = update.remote_store { data.remote_store = remote_store; }
|
||||||
if let Some(owner) = update.owner { data.owner = Some(owner); }
|
if let Some(owner) = update.owner { data.owner = Some(owner); }
|
||||||
|
if let Some(groups) = update.groups { data.groups = Some(groups); }
|
||||||
|
|
||||||
let schedule_changed = data.schedule != update.schedule;
|
let schedule_changed = data.schedule != update.schedule;
|
||||||
if update.schedule.is_some() { data.schedule = update.schedule; }
|
if update.schedule.is_some() { data.schedule = update.schedule; }
|
||||||
@ -390,6 +394,7 @@ acl:1:/remote/remote1/remotestore1:write@pbs:RemoteSyncOperator
|
|||||||
owner: Some(write_auth_id.clone()),
|
owner: Some(write_auth_id.clone()),
|
||||||
comment: None,
|
comment: None,
|
||||||
remove_vanished: None,
|
remove_vanished: None,
|
||||||
|
groups: None,
|
||||||
schedule: None,
|
schedule: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ impl TryFrom<&SyncJobConfig> for PullParameters {
|
|||||||
&sync_job.remote_store,
|
&sync_job.remote_store,
|
||||||
sync_job.owner.as_ref().unwrap_or_else(|| Authid::root_auth_id()).clone(),
|
sync_job.owner.as_ref().unwrap_or_else(|| Authid::root_auth_id()).clone(),
|
||||||
sync_job.remove_vanished,
|
sync_job.remove_vanished,
|
||||||
None,
|
sync_job.groups.clone(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
Ext.define('pbs-sync-jobs-status', {
|
Ext.define('pbs-sync-jobs-status', {
|
||||||
extend: 'Ext.data.Model',
|
extend: 'Ext.data.Model',
|
||||||
fields: [
|
fields: [
|
||||||
'id', 'owner', 'remote', 'remote-store', 'store', 'schedule',
|
'id', 'owner', 'remote', 'remote-store', 'store', 'schedule', 'groups',
|
||||||
'next-run', 'last-run-upid', 'last-run-state', 'last-run-endtime',
|
'next-run', 'last-run-upid', 'last-run-state', 'last-run-endtime',
|
||||||
{
|
{
|
||||||
name: 'duration',
|
name: 'duration',
|
||||||
@ -214,6 +214,12 @@ Ext.define('PBS.config.SyncJobView', {
|
|||||||
flex: 2,
|
flex: 2,
|
||||||
sortable: true,
|
sortable: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
header: gettext('Backup Groups'),
|
||||||
|
dataIndex: 'groups',
|
||||||
|
renderer: v => v ? Ext.String.htmlEncode(v) : gettext('All'),
|
||||||
|
width: 80,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
header: gettext('Schedule'),
|
header: gettext('Schedule'),
|
||||||
dataIndex: 'schedule',
|
dataIndex: 'schedule',
|
||||||
|
@ -199,6 +199,15 @@ Ext.define('PBS.window.SyncJobEdit', {
|
|||||||
],
|
],
|
||||||
|
|
||||||
columnB: [
|
columnB: [
|
||||||
|
{
|
||||||
|
fieldLabel: gettext('Backup Groups'),
|
||||||
|
xtype: 'displayfield',
|
||||||
|
name: 'groups',
|
||||||
|
renderer: v => v ? Ext.String.htmlEncode(v) : gettext('All'),
|
||||||
|
cbind: {
|
||||||
|
hidden: '{isCreate}',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
fieldLabel: gettext('Comment'),
|
fieldLabel: gettext('Comment'),
|
||||||
xtype: 'proxmoxtextfield',
|
xtype: 'proxmoxtextfield',
|
||||||
|
Loading…
Reference in New Issue
Block a user