Skip to content

Commit

Permalink
Add parameter --timestamp-format #43
Browse files Browse the repository at this point in the history
  • Loading branch information
franklupo committed Dec 16, 2020
1 parent 6570c24 commit ef5312e
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 61 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/src/Corsinvest.ProxmoxVE.AutoSnap/bin/Debug/netcoreapp3.0/cv4pve-autosnap.dll",
"program": "${workspaceFolder}/src/Corsinvest.ProxmoxVE.AutoSnap/bin/Debug/netcoreapp3.1/cv4pve-autosnap.dll",
"args": [],
"cwd": "${workspaceFolder}/src/Corsinvest.ProxmoxVE.AutoSnap",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
Expand Down
38 changes: 22 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,25 @@ Proxmox VE automatic snapshot tool
Usage: cv4pve-autosnap [options] [command]
Options:
-?|-h|--help Show help information
--version Show version information
--host The host name host[:port],host1[:port],host2[:port]
--api-token Api token format 'USER@REALM!TOKENID=UUID'. Require Proxmox VE 6.2 or later
--username User name <username>@<realm>
--password The password. Specify 'file:path_file' to store password in file.
--vmid The id or name VM/CT comma separated (eg. 100,101,102,TestDebian)
-vmid or -name exclude (e.g. -200,-TestUbuntu)
'all-???' for all VM/CT in specific host (e.g. all-pve1, all-\$(hostname)),
'all' for all VM/CT in cluster
--timeout Timeout operation in seconds
-?|-h|--help Show help information
--version Show version information
--host The host name host[:port],host1[:port],host2[:port]
--api-token Api token format 'USER@REALM!TOKENID=UUID'. Require Proxmox VE 6.2 or later
--username User name <username>@<realm>
--password The password. Specify 'file:path_file' to store password in file.
--vmid The id or name VM/CT comma separated (eg. 100,101,102,TestDebian)
-vmid or -name exclude (e.g. -200,-TestUbuntu)
'all-???' for all VM/CT in specific host (e.g. all-pve1, all-\$(hostname)),
'all' for all VM/CT in cluster
--timeout Timeout operation in seconds
--timestamp-format Specify different timestamp format. Default: yyMMddHHmmss
Commands:
app-check-update Check update application
app-upgrade Upgrade application
clean Remove auto snapshots
snap Will snap one time
status Get list of all auto snapshots
app-check-update Check update application
app-upgrade Upgrade application
clean Remove auto snapshots
snap Will snap one time
status Get list of all auto snapshots
Run 'cv4pve-autosnap [command] --help' for more information about a command.
Expand Down Expand Up @@ -107,13 +108,18 @@ For the planning process using an external machine:
* Check-Update and Upgrade application
* Use Api token --api-token parameter
* Support range vmid 100:103,134,200:204,-102
* Support different timestamp format with parameter --timestamp-format

## Api token

From version 6.2 of Proxmox VE is possible to use [Api token](https://pve.proxmox.com/pve-docs/pveum-plain.html).
This feature permit execute Api without using user and password.
If using **Privilege Separation** when create api token remember specify in permission.

## Custom timestamp format

Timestamp format is based on [C# date and time format string](https://docs.microsoft.com/it-it/dotnet/standard/base-types/custom-date-and-time-format-strings).

## Configuration and use

E.g. install on linux 64
Expand Down
75 changes: 45 additions & 30 deletions src/Corsinvest.ProxmoxVE.AutoSnap.Api/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,27 @@ public class Application
{
private static readonly string PREFIX = "auto";

private static readonly string TIMESTAMP_FORMAT = "yyMMddHHmmss";
/// <summary>
/// Default time stamp format
/// </summary>
public static readonly string DEFAULT_TIMESTAMP_FORMAT = "yyMMddHHmmss";

/// <summary>
/// Application name
/// </summary>
public static readonly string NAME = "cv4pve-autosnap";

private static string GetTimestampFormat(string timestampFormat)
=> string.IsNullOrWhiteSpace(timestampFormat) ? DEFAULT_TIMESTAMP_FORMAT : timestampFormat;

/// <summary>
/// Get label from description
/// </summary>
/// <param name="name"></param>
/// <param name="timestampFormat"></param>
/// <returns></returns>
public static string GetLabelFromName(string name) => name[PREFIX.Length..^TIMESTAMP_FORMAT.Length];
public static string GetLabelFromName(string name, string timestampFormat)
=> name[PREFIX.Length..^GetTimestampFormat(timestampFormat).Length];

/// <summary>
/// Old application name
Expand Down Expand Up @@ -119,13 +127,6 @@ private void CallPhaseEvent(HookPhase phase,
status));
}

/// <summary>
/// Status auto snapshot.
/// </summary>
/// <param name="vmIdsOrNames"></param>
/// <returns></returns>
public IEnumerable<Snapshot> Status(string vmIdsOrNames) => Status(vmIdsOrNames, null);

private IEnumerable<VMInfo> GetVMs(string vmIdsOrNames)
=> _client.GetVMs(vmIdsOrNames).Where(a => a.Status != "unknown");

Expand All @@ -134,21 +135,24 @@ private IEnumerable<VMInfo> GetVMs(string vmIdsOrNames)
/// </summary>
/// <param name="vmIdsOrNames"></param>
/// <param name="label"></param>
public IEnumerable<Snapshot> Status(string vmIdsOrNames, string label)
/// <param name="timestampFormat"></param>
public IEnumerable<Snapshot> Status(string vmIdsOrNames, string label, string timestampFormat)
{
//select snapshot and filter
var snapshots = FilterApp(GetVMs(vmIdsOrNames).SelectMany(a => a.Snapshots));
return string.IsNullOrWhiteSpace(label) ? snapshots : FilterLabel(snapshots, label);
return string.IsNullOrWhiteSpace(label) ? snapshots : FilterLabel(snapshots, label, timestampFormat);
}

private static IEnumerable<Snapshot> FilterApp(IEnumerable<Snapshot> snapshots)
=> snapshots.Where(a => (a.Description == NAME || a.Description == OLD_NAME));

private static string GetPrefix(string label) => PREFIX + label;

private static IEnumerable<Snapshot> FilterLabel(IEnumerable<Snapshot> snapshots, string label)
=> FilterApp(snapshots.Where(a => (a.Name.Length - TIMESTAMP_FORMAT.Length) > 0 &&
a.Name.Substring(0, a.Name.Length - TIMESTAMP_FORMAT.Length) == GetPrefix(label)));
private static IEnumerable<Snapshot> FilterLabel(IEnumerable<Snapshot> snapshots,
string label,
string timestampFormat)
=> FilterApp(snapshots.Where(a => (a.Name.Length - GetTimestampFormat(timestampFormat).Length) > 0 &&
a.Name.Substring(0, a.Name.Length - GetTimestampFormat(timestampFormat).Length) == GetPrefix(label)));

/// <summary>
/// Execute a autosnap.
Expand All @@ -158,15 +162,24 @@ private static IEnumerable<Snapshot> FilterLabel(IEnumerable<Snapshot> snapshots
/// <param name="keep"></param>
/// <param name="state"></param>
/// <param name="timeout"></param>
/// <param name="timestampFormat"></param>
/// <returns></returns>
public ResultSnap Snap(string vmIdsOrNames, string label, int keep, bool state, long timeout)
public ResultSnap Snap(string vmIdsOrNames,
string label,
int keep,
bool state,
long timeout,
string timestampFormat)
{
timestampFormat = GetTimestampFormat(timestampFormat);

_out.WriteLine($@"ACTION Snap
VMs: {vmIdsOrNames}
Label: {label}
Keep: {keep}
State: {state}
Timeout: {timeout}");
VMs: {vmIdsOrNames}
Label: {label}
Keep: {keep}
State: {state}
Timeout: {timeout}
Timestamp format: {timestampFormat}");

var ret = new ResultSnap();
ret.Start();
Expand Down Expand Up @@ -198,7 +211,7 @@ public ResultSnap Snap(string vmIdsOrNames, string label, int keep, bool state,
}

//create snapshot
var snapName = GetPrefix(label) + DateTime.Now.ToString(TIMESTAMP_FORMAT);
var snapName = GetPrefix(label) + DateTime.Now.ToString(timestampFormat);

CallPhaseEvent(HookPhase.SnapCreatePre, vm, label, keep, snapName, state, 0, true);

Expand Down Expand Up @@ -227,7 +240,7 @@ public ResultSnap Snap(string vmIdsOrNames, string label, int keep, bool state,
}

//remove old snapshot
if (!SnapshotsRemove(vm, label, keep, timeout))
if (!SnapshotsRemove(vm, label, keep, timeout, timestampFormat))
{
execSnapVm.Stop();
continue;
Expand Down Expand Up @@ -259,14 +272,16 @@ public ResultSnap Snap(string vmIdsOrNames, string label, int keep, bool state,
/// <param name="label"></param>
/// <param name="keep"></param>
/// <param name="timeout"></param>
/// <param name="timestampFormat"></param>
/// <returns></returns>
public bool Clean(string vmIdsOrNames, string label, int keep, long timeout)
public bool Clean(string vmIdsOrNames, string label, int keep, long timeout, string timestampFormat)
{
_out.WriteLine($@"ACTION Clean
VMs: {vmIdsOrNames}
Label: {label}
Keep: {keep}
Timeout: {timeout}");
VMs: {vmIdsOrNames}
Label: {label}
Keep: {keep}
Timeout: {timeout}
Timestamp format: {timestampFormat}");

var watch = new Stopwatch();
watch.Start();
Expand All @@ -284,7 +299,7 @@ public bool Clean(string vmIdsOrNames, string label, int keep, long timeout)
}

_out.WriteLine($"----- VM {vm.Id} {vm.Type} -----");
if (!SnapshotsRemove(vm, label, keep, timeout)) { ret = false; }
if (!SnapshotsRemove(vm, label, keep, timeout, timestampFormat)) { ret = false; }
}

watch.Stop();
Expand All @@ -293,9 +308,9 @@ public bool Clean(string vmIdsOrNames, string label, int keep, long timeout)
return ret;
}

private bool SnapshotsRemove(VMInfo vm, string label, int keep, long timeout)
private bool SnapshotsRemove(VMInfo vm, string label, int keep, long timeout, string timstampFormat)
{
foreach (var snapshot in FilterLabel(vm.Snapshots, label).Reverse().Skip(keep).Reverse())
foreach (var snapshot in FilterLabel(vm.Snapshots, label, timstampFormat).Reverse().Skip(keep).Reverse())
{
var watch = new Stopwatch();
watch.Start();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<TargetFramework>netstandard2.1</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>

<Version>1.6.13</Version>
<Version>1.7.0</Version>
<Company>Corsinvest Srl</Company>
<Authors>Daniele Corsini</Authors>
<Copyright>Corsinvest Srl</Copyright>
Expand Down
14 changes: 13 additions & 1 deletion src/Corsinvest.ProxmoxVE.AutoSnap.Api/ResultBaseSnap.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
using System;
/*
* This file is part of the cv4pve-autosnap https://github.com/Corsinvest/cv4pve-autosnap,
*
* This source file is available under two different licenses:
* - GNU General Public License version 3 (GPLv3)
* - Corsinvest Enterprise License (CEL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* Copyright (C) 2016 Corsinvest Srl GPLv3 and CEL
*/

using System;
using System.Diagnostics;

namespace Corsinvest.ProxmoxVE.AutoSnap.Api
Expand Down
12 changes: 12 additions & 0 deletions src/Corsinvest.ProxmoxVE.AutoSnap.Api/ResultSnap.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
/*
* This file is part of the cv4pve-autosnap https://github.com/Corsinvest/cv4pve-autosnap,
*
* This source file is available under two different licenses:
* - GNU General Public License version 3 (GPLv3)
* - Corsinvest Enterprise License (CEL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* Copyright (C) 2016 Corsinvest Srl GPLv3 and CEL
*/

using System.Collections.Generic;
using System.Linq;

Expand Down
12 changes: 11 additions & 1 deletion src/Corsinvest.ProxmoxVE.AutoSnap.Api/ResultSnapVm.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
using System.Linq;
/*
* This file is part of the cv4pve-autosnap https://github.com/Corsinvest/cv4pve-autosnap,
*
* This source file is available under two different licenses:
* - GNU General Public License version 3 (GPLv3)
* - Corsinvest Enterprise License (CEL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* Copyright (C) 2016 Corsinvest Srl GPLv3 and CEL
*/

namespace Corsinvest.ProxmoxVE.AutoSnap.Api
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<Version>1.9.11</Version>
<Version>1.10.0</Version>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AssemblyName>cv4pve-autosnap</AssemblyName>
<Company>Corsinvest Srl</Company>
Expand All @@ -22,7 +22,7 @@
<PackageReference Include="Corsinvest.ProxmoxVE.Api.Shell" Version="2.7.0" />

<!-- <ProjectReference Include="..\Corsinvest.ProxmoxVE.AutoSnap.Api\Corsinvest.ProxmoxVE.AutoSnap.Api.csproj" /> -->
<PackageReference Include="Corsinvest.ProxmoxVE.AutoSnap.Api" Version="1.6.13" />
<PackageReference Include="Corsinvest.ProxmoxVE.AutoSnap.Api" Version="1.7.0" />
</ItemGroup>

<Target Name="SpicNSpan" AfterTargets="Clean">
Expand Down
34 changes: 25 additions & 9 deletions src/Corsinvest.ProxmoxVE.AutoSnap/ShellCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,13 @@ public ShellCommands(CommandLineApplication parent)
.DependOn(parent, CommandOptionExtension.HOST_OPTION_NAME);
var optTimeout = parent.TimeoutOption();

Snap(parent, optVmIds, optTimeout);
Clean(parent, optVmIds, optTimeout);
Status(parent, optVmIds);
var optTimestampFormat = parent.Option("--timestamp-format",
$"Specify different timestamp format. Default: {Application.DEFAULT_TIMESTAMP_FORMAT} ",
CommandOptionType.SingleValue);

Snap(parent, optVmIds, optTimeout, optTimestampFormat);
Clean(parent, optVmIds, optTimeout, optTimestampFormat);
Status(parent, optVmIds, optTimestampFormat);
}

private Application CreateApp(CommandLineApplication parent)
Expand Down Expand Up @@ -76,7 +80,9 @@ private void App_PhaseEvent(object sender, PhaseEventArgs e)
if (!string.IsNullOrWhiteSpace(StandardOutput)) { _out.Write(StandardOutput); }
}

private void Status(CommandLineApplication parent, CommandOption optVmIds)
private void Status(CommandLineApplication parent,
CommandOption optVmIds,
CommandOption optTimestampFormat)
{
parent.Command("status", cmd =>
{
Expand All @@ -88,13 +94,18 @@ private void Status(CommandLineApplication parent, CommandOption optVmIds)
cmd.OnExecute(() =>
{
var snapshots = CreateApp(parent).Status(optVmIds.Value(), optLabel.Value());
var snapshots = CreateApp(parent).Status(optVmIds.Value(),
optLabel.Value(),
optTimestampFormat.Value());
parent.Out.Write(snapshots.Info(true, optOutput.GetEnumValue<TableOutputType>()));
});
});
}

private void Clean(CommandLineApplication parent, CommandOption optVmIds, CommandOption<long> optTimeout)
private void Clean(CommandLineApplication parent,
CommandOption optVmIds,
CommandOption<long> optTimeout,
CommandOption optTimestampFormat)
{
parent.Command("clean", cmd =>
{
Expand All @@ -116,12 +127,16 @@ private void Clean(CommandLineApplication parent, CommandOption optVmIds, Comman
optKeep.ParsedValue,
optTimeout.HasValue() ?
optTimeout.ParsedValue * 1000 :
ResultExtension.DEFAULT_TIMEOUT) ? 0 : 1;
ResultExtension.DEFAULT_TIMEOUT,
optTimestampFormat.Value()) ? 0 : 1;
});
});
}

private void Snap(CommandLineApplication parent, CommandOption optVmIds, CommandOption<long> optTimeout)
private void Snap(CommandLineApplication parent,
CommandOption optVmIds,
CommandOption<long> optTimeout,
CommandOption optTimestampFormat)
{
parent.Command("snap", cmd =>
{
Expand All @@ -142,7 +157,8 @@ private void Snap(CommandLineApplication parent, CommandOption optVmIds, Command
optState.HasValue(),
optTimeout.HasValue() ?
optTimeout.ParsedValue * 1000 :
ResultExtension.DEFAULT_TIMEOUT).Status ? 0 : 1;
ResultExtension.DEFAULT_TIMEOUT,
optTimestampFormat.Value()).Status ? 0 : 1;
});
});
}
Expand Down

0 comments on commit ef5312e

Please sign in to comment.