use proxmox::const_regex;
use proxmox::{IPRE, IPRE_BRACKET, IPV4RE, IPV6RE, IPV4OCTET, IPV6H16, IPV6LS32};
-use crate::backup::{CryptMode, BACKUP_ID_REGEX};
+use crate::backup::{CryptMode, Fingerprint, BACKUP_ID_REGEX};
use crate::server::UPID;
#[macro_use]
pub use userid::Authid;
pub use userid::{PROXMOX_TOKEN_ID_SCHEMA, PROXMOX_TOKEN_NAME_SCHEMA, PROXMOX_GROUP_ID_SCHEMA};
+mod tape;
+pub use tape::*;
+
// File names: may not contain slashes, may not start with "."
pub const FILENAME_FORMAT: ApiStringFormat = ApiStringFormat::VerifyFn(|name| {
if name.starts_with('.') {
/// any identifier command line tools work with.
pub PROXMOX_SAFE_ID_REGEX = concat!(r"^", PROXMOX_SAFE_ID_REGEX_STR!(), r"$");
+ /// Regex for verification jobs 'DATASTORE:ACTUAL_JOB_ID'
+ pub VERIFICATION_JOB_WORKER_ID_REGEX = concat!(r"^(", PROXMOX_SAFE_ID_REGEX_STR!(), r"):");
+ /// Regex for sync jobs 'REMOTE:REMOTE_DATASTORE:LOCAL_DATASTORE:ACTUAL_JOB_ID'
+ pub SYNC_JOB_WORKER_ID_REGEX = concat!(r"^(", PROXMOX_SAFE_ID_REGEX_STR!(), r"):(", PROXMOX_SAFE_ID_REGEX_STR!(), r"):(", PROXMOX_SAFE_ID_REGEX_STR!(), r"):");
+
pub SINGLE_LINE_COMMENT_REGEX = r"^[[:^cntrl:]]*$";
pub HOSTNAME_REGEX = r"^(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?)$";
pub BACKUP_REPO_URL_REGEX = concat!(r"^^(?:(?:(", USER_ID_REGEX_STR!(), "|", APITOKEN_ID_REGEX_STR!(), ")@)?(", DNS_NAME!(), "|", IPRE_BRACKET!() ,"):)?(?:([0-9]{1,5}):)?(", PROXMOX_SAFE_ID_REGEX_STR!(), r")$");
- pub CERT_FINGERPRINT_SHA256_REGEX = r"^(?:[0-9a-fA-F][0-9a-fA-F])(?::[0-9a-fA-F][0-9a-fA-F]){31}$";
+ pub FINGERPRINT_SHA256_REGEX = r"^(?:[0-9a-fA-F][0-9a-fA-F])(?::[0-9a-fA-F][0-9a-fA-F]){31}$";
pub ACL_PATH_REGEX = concat!(r"^(?:/|", r"(?:/", PROXMOX_SAFE_ID_REGEX_STR!(), ")+", r")$");
pub const PVE_CONFIG_DIGEST_FORMAT: ApiStringFormat =
ApiStringFormat::Pattern(&SHA256_HEX_REGEX);
-pub const CERT_FINGERPRINT_SHA256_FORMAT: ApiStringFormat =
- ApiStringFormat::Pattern(&CERT_FINGERPRINT_SHA256_REGEX);
+pub const FINGERPRINT_SHA256_FORMAT: ApiStringFormat =
+ ApiStringFormat::Pattern(&FINGERPRINT_SHA256_REGEX);
pub const PROXMOX_SAFE_ID_FORMAT: ApiStringFormat =
ApiStringFormat::Pattern(&PROXMOX_SAFE_ID_REGEX);
pub const CERT_FINGERPRINT_SHA256_SCHEMA: Schema = StringSchema::new(
"X509 certificate fingerprint (sha256)."
)
- .format(&CERT_FINGERPRINT_SHA256_FORMAT)
+ .format(&FINGERPRINT_SHA256_FORMAT)
.schema();
-pub const PROXMOX_CONFIG_DIGEST_SCHEMA: Schema = StringSchema::new(r#"\
-Prevent changes if current configuration file has different SHA256 digest.
-This can be used to prevent concurrent modifications.
-"#
+pub const TAPE_ENCRYPTION_KEY_FINGERPRINT_SCHEMA: Schema = StringSchema::new(
+ "Tape encryption key fingerprint (sha256)."
)
- .format(&PVE_CONFIG_DIGEST_FORMAT)
+ .format(&FINGERPRINT_SHA256_FORMAT)
.schema();
+pub const PROXMOX_CONFIG_DIGEST_SCHEMA: Schema = StringSchema::new(
+ "Prevent changes if current configuration file has different \
+ SHA256 digest. This can be used to prevent concurrent \
+ modifications."
+)
+ .format(&PVE_CONFIG_DIGEST_FORMAT) .schema();
+
pub const CHUNK_DIGEST_FORMAT: ApiStringFormat =
ApiStringFormat::Pattern(&SHA256_HEX_REGEX);
type: SnapshotVerifyState,
optional: true,
},
+ fingerprint: {
+ type: String,
+ optional: true,
+ },
files: {
items: {
schema: BACKUP_ARCHIVE_NAME_SCHEMA
/// The result of the last run verify task
#[serde(skip_serializing_if="Option::is_none")]
pub verification: Option<SnapshotVerifyState>,
+ /// Fingerprint of encryption key
+ #[serde(skip_serializing_if="Option::is_none")]
+ pub fingerprint: Option<Fingerprint>,
/// List of contained archive files.
pub files: Vec<BackupContent>,
/// Overall snapshot size (sum of all archive sizes).
},
},
)]
-#[derive(Serialize, Deserialize)]
+#[derive(Serialize, Deserialize, Default)]
/// Counts of groups/snapshots per BackupType.
pub struct Counts {
/// The counts for CT backups
#[api(
properties: {
- "gc-status": { type: GarbageCollectionStatus, },
- counts: { type: Counts, }
+ "gc-status": {
+ type: GarbageCollectionStatus,
+ optional: true,
+ },
+ counts: {
+ type: Counts,
+ optional: true,
+ },
},
)]
#[derive(Serialize, Deserialize)]
/// Available space (bytes).
pub avail: u64,
/// Status of last GC
- pub gc_status: GarbageCollectionStatus,
+ #[serde(skip_serializing_if="Option::is_none")]
+ pub gc_status: Option<GarbageCollectionStatus>,
/// Group/Snapshot counts
- pub counts: Counts,
+ #[serde(skip_serializing_if="Option::is_none")]
+ pub counts: Option<Counts>,
}
#[api(
];
for fingerprint in invalid_fingerprints.iter() {
- if let Ok(_) = parse_simple_value(fingerprint, &schema) {
+ if parse_simple_value(fingerprint, &schema).is_ok() {
bail!("test fingerprint '{}' failed - got Ok() while exception an error.", fingerprint);
}
}
];
for name in invalid_user_ids.iter() {
- if let Ok(_) = parse_simple_value(name, &Userid::API_SCHEMA) {
+ if parse_simple_value(name, &Userid::API_SCHEMA).is_ok() {
bail!("test userid '{}' failed - got Ok() while exception an error.", name);
}
}
}
#[api()]
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
/// Describes a package for which an update is available.
pub struct APTUpdateInfo {
pub section: String,
/// URL under which the package's changelog can be retrieved
pub change_log_url: String,
+ /// Custom extra field for additional package information
+ #[serde(skip_serializing_if="Option::is_none")]
+ pub extra_info: Option<String>,
}
#[api()]