2024-07-11 15:47:27 +02:00
|
|
|
import { unlinkSync } from "fs";
|
|
|
|
import { DateTime } from "luxon";
|
|
|
|
import logger from "../config/winston.js";
|
|
|
|
import messageManager from "../tools/messageManager.js";
|
|
|
|
import * as statusTools from "../tools/status.js";
|
|
|
|
import { BackupType } from "../types/services/backupConfig.js";
|
2024-07-22 11:20:43 +02:00
|
|
|
import type {
|
|
|
|
AddonModel,
|
|
|
|
BackupDetailModel,
|
2024-07-22 17:22:24 +02:00
|
|
|
BackupUpload,
|
|
|
|
SupervisorResponse,
|
2024-07-22 11:20:43 +02:00
|
|
|
} from "../types/services/ha_os_response.js";
|
2024-04-19 16:22:30 +02:00
|
|
|
import { WorkflowType } from "../types/services/orchecstrator.js";
|
|
|
|
import * as backupConfigService from "./backupConfigService.js";
|
|
|
|
import * as homeAssistantService from "./homeAssistantService.js";
|
|
|
|
import { getBackupFolder, getWebdavConfig } from "./webdavConfigService.js";
|
|
|
|
import * as webDavService from "./webdavService.js";
|
|
|
|
|
|
|
|
export function doBackupWorkflow(type: WorkflowType) {
|
|
|
|
let name = "";
|
|
|
|
let addonsToStartStop = [] as string[];
|
|
|
|
let addonInHa = [] as AddonModel[];
|
|
|
|
let tmpBackupFile = "";
|
|
|
|
|
|
|
|
const backupConfig = backupConfigService.getBackupConfig();
|
|
|
|
const webdavConfig = getWebdavConfig();
|
|
|
|
|
|
|
|
return homeAssistantService
|
|
|
|
.getVersion()
|
|
|
|
.then((value) => {
|
|
|
|
const version = value.body.data.version;
|
|
|
|
name = backupConfigService.getFormatedName(type, version);
|
|
|
|
return homeAssistantService.getAddonList();
|
|
|
|
})
|
|
|
|
.then((response) => {
|
|
|
|
addonInHa = response.body.data.addons;
|
|
|
|
addonsToStartStop = sanitizeAddonList(
|
|
|
|
backupConfig.autoStopAddon,
|
|
|
|
response.body.data.addons
|
|
|
|
);
|
|
|
|
return webDavService.checkWebdavLogin(webdavConfig);
|
|
|
|
})
|
|
|
|
.then(() => {
|
|
|
|
return homeAssistantService.stopAddons(addonsToStartStop);
|
|
|
|
})
|
2024-07-11 15:47:27 +02:00
|
|
|
.then(() => {
|
2024-04-19 16:22:30 +02:00
|
|
|
if (backupConfig.backupType == BackupType.FULL) {
|
|
|
|
return homeAssistantService.createNewBackup(
|
|
|
|
name,
|
|
|
|
backupConfig.backupType,
|
|
|
|
backupConfig.password.enabled,
|
|
|
|
backupConfig.password.value
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
const addons = getAddonToBackup(
|
|
|
|
backupConfig.exclude?.addon as string[],
|
|
|
|
addonInHa
|
|
|
|
);
|
|
|
|
const folders = getFolderToBackup(
|
|
|
|
backupConfig.exclude?.folder as string[],
|
|
|
|
homeAssistantService.getFolderList()
|
|
|
|
);
|
|
|
|
return homeAssistantService.createNewBackup(
|
|
|
|
name,
|
|
|
|
backupConfig.backupType,
|
|
|
|
backupConfig.password.enabled,
|
|
|
|
backupConfig.password.value,
|
|
|
|
addons,
|
|
|
|
folders
|
|
|
|
);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.then((response) => {
|
|
|
|
return homeAssistantService.downloadSnapshot(response.body.data.slug);
|
|
|
|
})
|
|
|
|
.then((tmpFile) => {
|
|
|
|
tmpBackupFile = tmpFile;
|
2024-07-11 15:47:27 +02:00
|
|
|
if (webdavConfig.chunckedUpload) {
|
|
|
|
return webDavService.chunkedUpload(
|
|
|
|
tmpFile,
|
2024-07-12 14:32:53 +02:00
|
|
|
getBackupFolder(type, webdavConfig) + name + ".tar",
|
2024-07-11 15:47:27 +02:00
|
|
|
webdavConfig
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
return webDavService.webdavUploadFile(
|
|
|
|
tmpFile,
|
2024-07-12 14:32:53 +02:00
|
|
|
getBackupFolder(type, webdavConfig) + name + ".tar",
|
2024-07-11 15:47:27 +02:00
|
|
|
webdavConfig
|
|
|
|
);
|
|
|
|
}
|
2024-04-19 16:22:30 +02:00
|
|
|
})
|
2024-07-12 14:32:36 +02:00
|
|
|
.then(() => {
|
|
|
|
return homeAssistantService.startAddons(addonsToStartStop);
|
|
|
|
})
|
2024-08-02 15:56:07 +02:00
|
|
|
.then(() => {
|
|
|
|
return homeAssistantService.clean(backupConfig);
|
|
|
|
})
|
|
|
|
.then(() => {
|
|
|
|
return webDavService.clean(backupConfig, webdavConfig);
|
|
|
|
})
|
2024-04-19 16:22:30 +02:00
|
|
|
.then(() => {
|
|
|
|
logger.info("Backup workflow finished successfully !");
|
2024-07-22 11:20:43 +02:00
|
|
|
messageManager.info(
|
|
|
|
"Backup workflow finished successfully !",
|
|
|
|
`name: ${name}`
|
|
|
|
);
|
2024-04-19 16:22:30 +02:00
|
|
|
const status = statusTools.getStatus();
|
|
|
|
status.last_backup.success = true;
|
|
|
|
status.last_backup.last_try = DateTime.now();
|
|
|
|
status.last_backup.last_success = DateTime.now();
|
|
|
|
statusTools.setStatus(status);
|
|
|
|
})
|
|
|
|
.catch(() => {
|
|
|
|
backupFail();
|
|
|
|
if (tmpBackupFile != "") {
|
|
|
|
unlinkSync(tmpBackupFile);
|
|
|
|
}
|
2024-07-11 15:47:27 +02:00
|
|
|
return Promise.reject(new Error());
|
2024-04-19 16:22:30 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-07-22 11:20:43 +02:00
|
|
|
export function uploadToCloud(slug: string) {
|
|
|
|
const webdavConfig = getWebdavConfig();
|
|
|
|
let tmpBackupFile = "";
|
|
|
|
let backupInfo = {} as BackupDetailModel;
|
|
|
|
|
|
|
|
return webDavService
|
|
|
|
.checkWebdavLogin(webdavConfig)
|
|
|
|
.then(() => {
|
|
|
|
return homeAssistantService.getBackupInfo(slug);
|
|
|
|
})
|
|
|
|
.then((response) => {
|
|
|
|
backupInfo = response.body.data;
|
|
|
|
return homeAssistantService.downloadSnapshot(slug);
|
|
|
|
})
|
|
|
|
.then((tmpFile) => {
|
|
|
|
tmpBackupFile = tmpFile;
|
|
|
|
if (webdavConfig.chunckedUpload) {
|
|
|
|
return webDavService.chunkedUpload(
|
|
|
|
tmpFile,
|
|
|
|
getBackupFolder(WorkflowType.MANUAL, webdavConfig) +
|
|
|
|
backupInfo.name +
|
|
|
|
".tar",
|
|
|
|
webdavConfig
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
return webDavService.webdavUploadFile(
|
|
|
|
tmpFile,
|
|
|
|
getBackupFolder(WorkflowType.MANUAL, webdavConfig) +
|
|
|
|
backupInfo.name +
|
|
|
|
".tar",
|
|
|
|
webdavConfig
|
|
|
|
);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.then(() => {
|
|
|
|
logger.info(`Successfully uploaded ${backupInfo.name} to cloud.`);
|
|
|
|
messageManager.info(
|
|
|
|
"Successfully uploaded backup to cloud.",
|
|
|
|
`Name: ${backupInfo.name}`
|
|
|
|
);
|
|
|
|
})
|
|
|
|
.catch(() => {
|
|
|
|
if (tmpBackupFile != "") {
|
|
|
|
unlinkSync(tmpBackupFile);
|
|
|
|
}
|
|
|
|
return Promise.reject(new Error());
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-04-19 16:22:30 +02:00
|
|
|
// This methods remove addon that are no installed in HA from the conf array
|
|
|
|
function sanitizeAddonList(addonInConf: string[], addonInHA: AddonModel[]) {
|
2024-07-12 14:32:36 +02:00
|
|
|
return addonInConf.filter((value) => addonInHA.some((v) => v.slug == value));
|
2024-04-19 16:22:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function getAddonToBackup(excludedAddon: string[], addonInHA: AddonModel[]) {
|
|
|
|
const slugs: string[] = [];
|
|
|
|
for (const addon of addonInHA) {
|
|
|
|
if (!excludedAddon.includes(addon.slug)) slugs.push(addon.slug);
|
|
|
|
}
|
|
|
|
logger.debug("Addon to backup:");
|
|
|
|
logger.debug(slugs);
|
|
|
|
return slugs;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getFolderToBackup(
|
|
|
|
excludedFolder: string[],
|
|
|
|
folderInHA: { name: string; slug: string }[]
|
|
|
|
) {
|
|
|
|
const slugs = [];
|
|
|
|
for (const folder of folderInHA) {
|
|
|
|
if (!excludedFolder.includes(folder.slug)) slugs.push(folder.slug);
|
|
|
|
}
|
|
|
|
logger.debug("Folders to backup:");
|
|
|
|
logger.debug(slugs);
|
|
|
|
return slugs;
|
|
|
|
}
|
|
|
|
|
|
|
|
function backupFail() {
|
|
|
|
const status = statusTools.getStatus();
|
|
|
|
status.last_backup.success = false;
|
|
|
|
status.last_backup.last_try = DateTime.now();
|
|
|
|
statusTools.setStatus(status);
|
|
|
|
messageManager.error("Last backup as failed !");
|
|
|
|
}
|
2024-07-22 17:22:24 +02:00
|
|
|
|
|
|
|
export function restoreToHA(webdavPath: string, filename: string) {
|
|
|
|
const webdavConfig = getWebdavConfig();
|
|
|
|
return webDavService
|
|
|
|
.checkWebdavLogin(webdavConfig)
|
|
|
|
.then(() => {
|
|
|
|
return webDavService.downloadFile(webdavPath, filename, webdavConfig);
|
|
|
|
})
|
|
|
|
.then((tmpFile) => {
|
|
|
|
return homeAssistantService.uploadSnapshot(tmpFile);
|
|
|
|
})
|
|
|
|
.then((res) => {
|
|
|
|
if (res) {
|
|
|
|
const body = JSON.parse(res.body) as SupervisorResponse<BackupUpload>;
|
|
|
|
logger.info(`Successfully uploaded ${filename} to Home Assistant.`);
|
|
|
|
messageManager.info(
|
|
|
|
"Successfully uploaded backup to Home Assistant.",
|
|
|
|
`Name: ${filename} slug: ${body.data.slug}
|
|
|
|
`
|
|
|
|
);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|