Skip to content

Commit

Permalink
fixes some remote send bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
JordanKeo45 committed Mar 12, 2024
1 parent cb75ca2 commit a260c81
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 42 deletions.
81 changes: 53 additions & 28 deletions zfs/src/components/snapshots/SendSnapshot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
import Modal from '../common/Modal.vue';
import { BetterCockpitFile } from '@45drives/cockpit-helpers';
import { ref, Ref, inject, computed } from 'vue';
import { sendSnapshot, doesDatasetExist, formatRecentSnaps } from '../../composables/snapshots';
import { sendSnapshot, doesDatasetExist, formatRecentSnaps, doesDatasetHaveSnaps } from '../../composables/snapshots';
import { convertTimestampToLocal, getRawTimestampFromString, convertRawTimestampToString, convertSizeToBytesDecimal } from '../../composables/helpers';
interface SendSnapshotProps {
Expand Down Expand Up @@ -235,6 +235,16 @@ async function doesRemoteDatasetExist() {
return await doesDatasetExist(sendingData.value);
} catch (error) {
console.error('Error checking dataset', error);
return false;
}
}
async function doesRemoteDatasetHaveSnaps() {
try {
return await doesDatasetHaveSnaps(sendingData.value);
} catch (error) {
console.error('Error checking dataset', error);
return false;
}
}
Expand Down Expand Up @@ -320,19 +330,27 @@ async function setSendData() {
} else {
datasetCheckResult.value = await doesRemoteDatasetExist();
if (datasetCheckResult.value) {
lastCommonSnap.value = await checkForLastCommonSnap();
console.log('remote lastCommonSnap:', lastCommonSnap.value);
if (lastCommonSnap.value) {
sendIncremental.value = true;
sendingData.value.sendOpts.incremental = sendIncremental!.value;
sendingData.value.sendIncName! = lastCommonSnap.value.name;
invalidConfig.value = false;
const doesRecvHaveSnaps = await doesRemoteDatasetHaveSnaps();
if (doesRecvHaveSnaps) {
lastCommonSnap.value = await checkForLastCommonSnap();
console.log('remote lastCommonSnap:', lastCommonSnap.value);
if (lastCommonSnap.value) {
sendIncremental.value = true;
sendingData.value.sendOpts.incremental = sendIncremental!.value;
sendingData.value.sendIncName! = lastCommonSnap.value.name;
invalidConfig.value = false;
} else {
sendIncremental.value = false;
sendingData.value.sendIncName! = "";
invalidConfig.value = true;
invalidConfigMsg.value = "Remote destination already exists and has been modified since most recent snapshot.";
mostRecentDestSnapMsg.value = `Most recent remote snapshot: ${mostRecentRemoteDestSnap.value!.name}`;
}
} else {
sendIncremental.value = false;
sendingData.value.sendIncName! = "";
invalidConfig.value = true;
invalidConfigMsg.value = "Remote destination already exists and has been modified since most recent snapshot.";
mostRecentDestSnapMsg.value = `Most recent remote snapshot: ${mostRecentRemoteDestSnap.value!.name}`;
invalidConfigMsg.value = "Remote destination already exists.";
}
} else {
sendIncremental.value = false;
Expand Down Expand Up @@ -383,6 +401,7 @@ async function checkForLastCommonSnap() {
} catch (error) {
console.error('Error checking snapshot', error);
return null;
}
}
Expand Down Expand Up @@ -418,29 +437,35 @@ function compareLocalTimestamp(destinationDatasetSnaps : Snapshot[], sourceDatas
async function compareRemoteTimestamp(snapSnips : SnapSnippet[], sourceDatasetSnaps : Snapshot[], sourceSendSnap : Snapshot) {
console.log('snapSnips', snapSnips);
// console.log('snapSnips length', snapSnips.length);
mostRecentRemoteDestSnap.value = snapSnips[0];
console.log('remote mostRecentRemoteDestSnap:', mostRecentRemoteDestSnap.value);
if (snapSnips[0]) {
mostRecentRemoteDestSnap.value = snapSnips[0];
console.log('remote mostRecentRemoteDestSnap:', mostRecentRemoteDestSnap.value);
console.log('mostRecentRemoteDestSnap.value.creation', Number(getRawTimestampFromString(mostRecentRemoteDestSnap.value.creation)));
console.log('sourceSendSnap.creationTimestamp', Number(getRawTimestampFromString(convertTimestampToLocal(convertRawTimestampToString(sourceSendSnap.creationTimestamp)))));
console.log('mostRecentRemoteDestSnap.value.creation', Number(getRawTimestampFromString(mostRecentRemoteDestSnap.value.creation)));
console.log('sourceSendSnap.creationTimestamp', Number(getRawTimestampFromString(convertTimestampToLocal(convertRawTimestampToString(sourceSendSnap.creationTimestamp)))));
if (mostRecentRemoteDestSnap.value.guid == sourceSendSnap.guid) {
console.log('sendSnap is the same as mostRecentDestSnap');
return null;
} else {
if (Number(getRawTimestampFromString(mostRecentRemoteDestSnap.value.creation)) < Number(getRawTimestampFromString(convertTimestampToLocal(convertRawTimestampToString(sourceSendSnap.creationTimestamp))))) {
const sourceSnapMatch = computed(() => {
const source = sourceDatasetSnaps.find(snap => snap.guid == mostRecentRemoteDestSnap.value!.guid);
console.log('source', source);
return source;
});
console.log('remote sourceSnapMatch:', sourceSnapMatch.value);
return sourceSnapMatch.value;
} else {
console.log('invalid remote lastCommonSnap match');
if (mostRecentRemoteDestSnap.value.guid == sourceSendSnap.guid) {
console.log('sendSnap is the same as mostRecentDestSnap');
return null;
} else {
if (Number(getRawTimestampFromString(mostRecentRemoteDestSnap.value.creation)) < Number(getRawTimestampFromString(convertTimestampToLocal(convertRawTimestampToString(sourceSendSnap.creationTimestamp))))) {
const sourceSnapMatch = computed(() => {
const source = sourceDatasetSnaps.find(snap => snap.guid == mostRecentRemoteDestSnap.value!.guid);
console.log('source', source);
return source;
});
console.log('remote sourceSnapMatch:', sourceSnapMatch.value);
return sourceSnapMatch.value;
} else {
console.log('invalid remote lastCommonSnap match');
return null;
}
}
} else {
console.log('No snap snips to compare');
return null;
}
}
async function sendBtn() {
Expand Down
11 changes: 11 additions & 0 deletions zfs/src/composables/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,18 @@ export function getSnapshotTimestamp() {
return timestamp;
}

/* export function getRawTimestampFromString(timestampString) {
const rawTimestamp = new Date(timestampString).getTime() / 1000;
return rawTimestamp;
}
*/
export function getRawTimestampFromString(timestampString) {
// Check if timestampString is undefined or null
if (timestampString === undefined || timestampString === null) {
// Return an appropriate value, for example, you can return null or throw an error
return null; // or throw new Error('Timestamp string is undefined or null');
}

const rawTimestamp = new Date(timestampString).getTime() / 1000;
return rawTimestamp;
}
Expand Down
41 changes: 34 additions & 7 deletions zfs/src/composables/snapshots.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import send_dataset_script from "../scripts/send-dataset.py?raw";
import check_dataset_script from"../scripts/check-dataset.py?raw";
// @ts-ignore
import get_recent_snaps_script from"../scripts/find-last-common-snap.py?raw";
// @ts-ignore
import check_remote_snaps_script from"../scripts/check-remote-snapshots.py?raw";

//['/usr/bin/env', 'python3', '-c', script, ...args ]

Expand Down Expand Up @@ -178,6 +180,26 @@ export async function doesDatasetExist(sendingData : SendingDataset) {
}
}

export async function doesDatasetHaveSnaps(sendingData : SendingDataset) {
try {
console.log('sendingData (snapshots.ts - checkDataset):', sendingData);

const state = useSpawn(['/usr/bin/env', 'python3', '-c', check_remote_snaps_script, sendingData.recvName, sendingData.recvHost, sendingData.recvPort, sendingData.recvHostUser], { superuser: 'try', stderr: 'out'});

const output = await state.promise();
console.log(output);

if (output.stdout.includes('True')) {
return true;
} else {
return false;
}
} catch (state) {
console.error(errorString(state));
return null;
}
}

export async function getRecentSnaps(sendingData : SendingDataset) {
try {
console.log('sendingData (snapshots.ts - getRecentSnaps):', sendingData);
Expand All @@ -201,14 +223,19 @@ export async function formatRecentSnaps(sendingData : SendingDataset, snapSnips
if (rawJSON) {
const parsedJSON = (JSON.parse(rawJSON));
parsedJSON.forEach(snap => {
console.log('snap:', snap);
const snapSnip : SnapSnippet = {
name: snap.name,
guid: snap.guid,
creation: convertTimestampToLocal(convertTimestampFormat(snap.creation)),
if (snap) {
console.log('snap:', snap);
const snapSnip : SnapSnippet = {
name: snap.name,
guid: snap.guid,
creation: convertTimestampToLocal(convertTimestampFormat(snap.creation)),
}
console.log('snapSnip after:', snapSnip);
snapSnips.push(snapSnip);
} else {
console.log('no recent snaps');
}
console.log('snapSnip after:', snapSnip);
snapSnips.push(snapSnip);

});
} else {
console.error("No data received from getRecentSnaps");
Expand Down
11 changes: 6 additions & 5 deletions zfs/src/scripts/check-dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ def check_if_recv_dataset_exists(recvName, recvHost, recvPort, recvHostUser):
return False
else:
# Check if the output matches the recvName
return stdout.strip() == recvName
# return stdout.strip() == recvName
return bool(stdout.strip())

def main() :
parser = argparse.ArgumentParser(description='Send ZFS Dataset')
Expand All @@ -42,10 +43,10 @@ def main() :
recvPort = args.recvPort
recvHostUser = args.recvHostUser

# if recvPort == '22':
# print(f"ssh {recvHostUser}@{recvHost} 'zfs list -H -o name {recvName}'")
# else:
# print(f"ssh -p {recvPort} {recvHostUser}@{recvHost} 'zfs list -H -o name {recvName}'")
if recvPort == '22':
print(f"ssh {recvHostUser}@{recvHost} 'zfs list -H -o name {recvName}'")
else:
print(f"ssh -p {recvPort} {recvHostUser}@{recvHost} 'zfs list -H -o name {recvName}'")

exists = check_if_recv_dataset_exists(recvName, recvHost, recvPort, recvHostUser)

Expand Down
28 changes: 28 additions & 0 deletions zfs/src/scripts/check-remote-snapshots.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import subprocess
import argparse

def check_if_recv_dataset_has_snapshots(recvName, recvHost, recvPort, recvHostUser):
# Construct the SSH command
if recvPort == '22':
ssh_cmd = ['ssh', f'{recvHostUser}@{recvHost}', f'zfs list -H -o name -t snapshot {recvName}']
else:
ssh_cmd = ['ssh', '-p', f'{recvPort}', f'{recvHostUser}@{recvHost}', f'zfs list -H -o name -t snapshot {recvName}']

# Run the SSH command
process_check_snapshots = subprocess.Popen(
ssh_cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True, # Ensures text mode for stdout and stderr
)

# Wait for the command to complete and capture the output
stdout, stderr = process_check_snapshots.communicate()

# Check the return code
if process_check_snapshots.returncode != 0:
# raise Exception(f"Error:{stderr}")
return False
else:
# Check if the output contains snapshots
return bool(stdout.strip())
4 changes: 2 additions & 2 deletions zfs/src/scripts/send-dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ def send_dataset(sendName, recvName, sendName2="", forceOverwrite=False, compres
if recvHost != "":
remove_remote_file(recvHost, recvHostUser, recvPort)
# If force overwrite required
if forceOverwrite == True:
destroy_for_overwrite_remote(recvName, recvHostUser, recvHost, recvPort)
# if forceOverwrite == True:
# destroy_for_overwrite_remote(recvName, recvHostUser, recvHost, recvPort)

# Initial local send command
send_cmd = ['zfs', 'send', '-v']
Expand Down

0 comments on commit a260c81

Please sign in to comment.