public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: "DERUMIER, Alexandre" <Alexandre.DERUMIER@groupe-cyllene.com>
To: "pve-devel@lists.proxmox.com" <pve-devel@lists.proxmox.com>
Subject: Re: [pve-devel] [PATCH v6 qemu-server 6/6] qm: add remote-migrate command
Date: Mon, 17 Oct 2022 14:40:27 +0000	[thread overview]
Message-ID: <f5d43fee-801f-61e1-867c-05157732a7af@groupe-cyllene.com> (raw)
In-Reply-To: <20220928125059.1139296-13-f.gruenbichler@proxmox.com>

Hi Fabian,


> an example invocation:
>
> $ qm remote-migrate 1234 4321 
'host=123.123.123.123,apitoken=pveapitoken=user@pve!incoming=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee,fingerprint=aa:bb:cc:dd:ee:ff:aa:bb:cc:dd:ee:ff:aa:bb:cc:dd:ee:ff:aa:bb:cc:dd:ee:ff:aa:bb:cc:dd:ee:ff:aa:bb' 
--target-bridge vmbr0 --target-storage zfs-a:rbd-b,nfs-c:dir-d,zfs-e 
--online


Maybe it could be better (optionnaly) to store the long

"'host=123.123.123.123,apitoken=pveapitoken=user@pve!incoming=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee,fingerprint=aa:bb:cc:dd:ee:ff:aa:bb:cc:dd:ee:ff:aa:bb:cc:dd:ee:ff:aa:bb:cc:dd:ee:ff:aa:bb:cc:dd:ee:ff:aa:bb' 
"

in a config file in /etc/pve/priv/<targethost>.conf ?


Like this, this should avoid to have the api token in the bash history.

maybe something like:

qm remote-migration 1234 4321 <targethost> ....

?





Le 28/09/22 à 14:50, Fabian Grünbichler a écrit :
> which wraps the remote_migrate_vm API endpoint, but does the
> precondition checks that can be done up front itself.
> 
> this now just leaves the FP retrieval and target node name lookup to the
> sync part of the API endpoint, which should be do-able in <30s ..
> 
> 
> will migrate the local VM 1234 to the host 123.123.1232.123 using the
> given API token, mapping the VMID to 4321 on the target cluster, all its
> virtual NICs to the target vm bridge 'vmbr0', any volumes on storage
> zfs-a to storage rbd-b, any on storage nfs-c to storage dir-d, and any
> other volumes to storage zfs-e. the source VM will be stopped but remain
> on the source node/cluster after the migration has finished.
> 
> Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
> ---
> 
> Notes:
>      v6:
>      - mark as experimental
>      - drop `with-local-disks` parameter from API, always set to true
>      - add example invocation to commit message
>      
>      v5: rename to 'remote-migrate'
> 
>   PVE/API2/Qemu.pm |  31 -------------
>   PVE/CLI/qm.pm    | 113 +++++++++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 113 insertions(+), 31 deletions(-)
> 
> diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
> index fa31e973..57083601 100644
> --- a/PVE/API2/Qemu.pm
> +++ b/PVE/API2/Qemu.pm
> @@ -4416,17 +4416,6 @@ __PACKAGE__->register_method({
>   	    $param->{online} = 0;
>   	}
>   
> -	# FIXME: fork worker hear to avoid timeout? or poll these periodically
> -	# in pvestatd and access cached info here? all of the below is actually
> -	# checked at the remote end anyway once we call the mtunnel endpoint,
> -	# we could also punt it to the client and not do it here at all..
> -	my $resources = $api_client->get("/cluster/resources", { type => 'vm' });
> -	if (grep { defined($_->{vmid}) && $_->{vmid} eq $target_vmid } @$resources) {
> -	    raise_param_exc({ target_vmid => "Guest with ID '$target_vmid' already exists on remote cluster" });
> -	}
> -
> -	my $storages = $api_client->get("/nodes/localhost/storage", { enabled => 1 });
> -
>   	my $storecfg = PVE::Storage::config();
>   	my $target_storage = extract_param($param, 'target-storage');
>   	my $storagemap = eval { PVE::JSONSchema::parse_idmap($target_storage, 'pve-storage-id') };
> @@ -4438,26 +4427,6 @@ __PACKAGE__->register_method({
>   	raise_param_exc({ 'target-bridge' => "failed to parse bridge map: $@" })
>   	    if $@;
>   
> -	my $check_remote_storage = sub {
> -	    my ($storage) = @_;
> -	    my $found = [ grep { $_->{storage} eq $storage } @$storages ];
> -	    die "remote: storage '$storage' does not exist!\n"
> -		if !@$found;
> -
> -	    $found = @$found[0];
> -
> -	    my $content_types = [ PVE::Tools::split_list($found->{content}) ];
> -	    die "remote: storage '$storage' cannot store images\n"
> -		if !grep { $_ eq 'images' } @$content_types;
> -	};
> -
> -	foreach my $target_sid (values %{$storagemap->{entries}}) {
> -	    $check_remote_storage->($target_sid);
> -	}
> -
> -	$check_remote_storage->($storagemap->{default})
> -	    if $storagemap->{default};
> -
>   	die "remote migration requires explicit storage mapping!\n"
>   	    if $storagemap->{identity};
>   
> diff --git a/PVE/CLI/qm.pm b/PVE/CLI/qm.pm
> index ca5d25fc..a6a63566 100755
> --- a/PVE/CLI/qm.pm
> +++ b/PVE/CLI/qm.pm
> @@ -15,6 +15,7 @@ use POSIX qw(strftime);
>   use Term::ReadLine;
>   use URI::Escape;
>   
> +use PVE::APIClient::LWP;
>   use PVE::Cluster;
>   use PVE::Exception qw(raise_param_exc);
>   use PVE::GuestHelpers;
> @@ -158,6 +159,117 @@ __PACKAGE__->register_method ({
>   	return;
>       }});
>   
> +
> +__PACKAGE__->register_method({
> +    name => 'remote_migrate_vm',
> +    path => 'remote_migrate_vm',
> +    method => 'POST',
> +    description => "Migrate virtual machine to a remote cluster. Creates a new migration task. EXPERIMENTAL feature!",
> +    permissions => {
> +	check => ['perm', '/vms/{vmid}', [ 'VM.Migrate' ]],
> +    },
> +    parameters => {
> +	additionalProperties => 0,
> +	properties => {
> +	    node => get_standard_option('pve-node'),
> +	    vmid => get_standard_option('pve-vmid', { completion => \&PVE::QemuServer::complete_vmid }),
> +	    'target-vmid' => get_standard_option('pve-vmid', { optional => 1 }),
> +	    'target-endpoint' => get_standard_option('proxmox-remote', {
> +		description => "Remote target endpoint",
> +	    }),
> +	    online => {
> +		type => 'boolean',
> +		description => "Use online/live migration if VM is running. Ignored if VM is stopped.",
> +		optional => 1,
> +	    },
> +	    delete => {
> +		type => 'boolean',
> +		description => "Delete the original VM and related data after successful migration. By default the original VM is kept on the source cluster in a stopped state.",
> +		optional => 1,
> +		default => 0,
> +	    },
> +	    'target-storage' => get_standard_option('pve-targetstorage', {
> +		completion => \&PVE::QemuServer::complete_migration_storage,
> +		optional => 0,
> +	    }),
> +	    'target-bridge' => {
> +		type => 'string',
> +		description => "Mapping from source to target bridges. Providing only a single bridge ID maps all source bridges to that bridge. Providing the special value '1' will map each source bridge to itself.",
> +		format => 'bridge-pair-list',
> +	    },
> +	    bwlimit => {
> +		description => "Override I/O bandwidth limit (in KiB/s).",
> +		optional => 1,
> +		type => 'integer',
> +		minimum => '0',
> +		default => 'migrate limit from datacenter or storage config',
> +	    },
> +	},
> +    },
> +    returns => {
> +	type => 'string',
> +	description => "the task ID.",
> +    },
> +    code => sub {
> +	my ($param) = @_;
> +
> +	my $rpcenv = PVE::RPCEnvironment::get();
> +	my $authuser = $rpcenv->get_user();
> +
> +	my $source_vmid = $param->{vmid};
> +	my $target_endpoint = $param->{'target-endpoint'};
> +	my $target_vmid = $param->{'target-vmid'} // $source_vmid;
> +
> +	my $remote = PVE::JSONSchema::parse_property_string('proxmox-remote', $target_endpoint);
> +
> +	# TODO: move this as helper somewhere appropriate?
> +	my $conn_args = {
> +	    protocol => 'https',
> +	    host => $remote->{host},
> +	    port => $remote->{port} // 8006,
> +	    apitoken => $remote->{apitoken},
> +	};
> +
> +	$conn_args->{cached_fingerprints} = { uc($remote->{fingerprint}) => 1 }
> +	    if defined($remote->{fingerprint});
> +
> +	my $api_client = PVE::APIClient::LWP->new(%$conn_args);
> +	my $resources = $api_client->get("/cluster/resources", { type => 'vm' });
> +	if (grep { defined($_->{vmid}) && $_->{vmid} eq $target_vmid } @$resources) {
> +	    raise_param_exc({ target_vmid => "Guest with ID '$target_vmid' already exists on remote cluster" });
> +	}
> +
> +	my $storages = $api_client->get("/nodes/localhost/storage", { enabled => 1 });
> +
> +	my $storecfg = PVE::Storage::config();
> +	my $target_storage = $param->{'target-storage'};
> +	my $storagemap = eval { PVE::JSONSchema::parse_idmap($target_storage, 'pve-storage-id') };
> +	raise_param_exc({ 'target-storage' => "failed to parse storage map: $@" })
> +	    if $@;
> +
> +	my $check_remote_storage = sub {
> +	    my ($storage) = @_;
> +	    my $found = [ grep { $_->{storage} eq $storage } @$storages ];
> +	    die "remote: storage '$storage' does not exist!\n"
> +		if !@$found;
> +
> +	    $found = @$found[0];
> +
> +	    my $content_types = [ PVE::Tools::split_list($found->{content}) ];
> +	    die "remote: storage '$storage' cannot store images\n"
> +		if !grep { $_ eq 'images' } @$content_types;
> +	};
> +
> +	foreach my $target_sid (values %{$storagemap->{entries}}) {
> +	    $check_remote_storage->($target_sid);
> +	}
> +
> +	$check_remote_storage->($storagemap->{default})
> +	    if $storagemap->{default};
> +
> +	return PVE::API2::Qemu->remote_migrate_vm($param);
> +    }});
> +
>   __PACKAGE__->register_method ({
>       name => 'status',
>       path => 'status',
> @@ -900,6 +1012,7 @@ our $cmddef = {
>       clone => [ "PVE::API2::Qemu", 'clone_vm', ['vmid', 'newid'], { node => $nodename }, $upid_exit ],
>   
>       migrate => [ "PVE::API2::Qemu", 'migrate_vm', ['vmid', 'target'], { node => $nodename }, $upid_exit ],
> +    'remote-migrate' => [ __PACKAGE__, 'remote_migrate_vm', ['vmid', 'target-vmid', 'target-endpoint'], { node => $nodename }, $upid_exit ],
>   
>       set => [ "PVE::API2::Qemu", 'update_vm', ['vmid'], { node => $nodename } ],
>   


  reply	other threads:[~2022-10-17 14:40 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-28 12:50 [pve-devel] [PATCH-SERIES v6 0/13] remote migration Fabian Grünbichler
2022-09-28 12:50 ` [pve-devel] [PATCH v6 access-control 1/1] privs: add Sys.Incoming Fabian Grünbichler
2022-11-07 15:38   ` [pve-devel] applied: " Thomas Lamprecht
2022-09-28 12:50 ` [pve-devel] [PATCH v6 common 1/1] schema: take over 'pve-targetstorage' option Fabian Grünbichler
2022-11-07 15:31   ` [pve-devel] applied: " Thomas Lamprecht
2022-09-28 12:50 ` [pve-devel] [PATCH v6 container 1/3] migration: add remote migration Fabian Grünbichler
2022-10-03 13:22   ` [pve-devel] [PATCH FOLLOW-UP " Fabian Grünbichler
2022-09-28 12:50 ` [pve-devel] [PATCH v6 container 2/3] pct: add 'remote-migrate' command Fabian Grünbichler
2022-09-28 12:50 ` [pve-devel] [PATCH v6 container 3/3] migrate: print mapped volume in error Fabian Grünbichler
2022-09-28 12:50 ` [pve-devel] [PATCH v6 docs 1/1] pveum: mention Sys.Incoming privilege Fabian Grünbichler
2022-11-07 15:45   ` [pve-devel] applied: " Thomas Lamprecht
2022-09-28 12:50 ` [pve-devel] [PATCH v6 qemu-server 1/6] schema: move 'pve-targetstorage' to pve-common Fabian Grünbichler
2022-11-07 15:31   ` [pve-devel] applied: " Thomas Lamprecht
2022-09-28 12:50 ` [pve-devel] [PATCH v6 qemu-server 2/6] mtunnel: add API endpoints Fabian Grünbichler
2022-09-30 11:52   ` Stefan Hanreich
2022-10-03  7:11     ` Fabian Grünbichler
2022-10-03 13:22   ` [pve-devel] [PATCH FOLLOW-UP " Fabian Grünbichler
2022-10-18  6:23   ` [pve-devel] [PATCH " DERUMIER, Alexandre
2022-09-28 12:50 ` [pve-devel] [PATCH v6 qemu-server 3/6] migrate: refactor remote VM/tunnel start Fabian Grünbichler
2022-09-28 12:50 ` [pve-devel] [PATCH v6 qemu-server 4/6] migrate: add remote migration handling Fabian Grünbichler
2022-09-28 12:50 ` [pve-devel] [PATCH v6 qemu-server 5/6] api: add remote migrate endpoint Fabian Grünbichler
2022-09-28 12:50 ` [pve-devel] [PATCH v6 qemu-server 6/6] qm: add remote-migrate command Fabian Grünbichler
2022-10-17 14:40   ` DERUMIER, Alexandre [this message]
2022-10-18  6:39     ` Thomas Lamprecht
2022-10-18  6:56       ` DERUMIER, Alexandre
2022-10-17 17:22   ` DERUMIER, Alexandre
2022-09-28 12:50 ` [pve-devel] [PATCH v6 storage 1/1] (remote) export: check and untaint format Fabian Grünbichler
2022-09-29 12:39   ` [pve-devel] applied: " Thomas Lamprecht
2022-10-04 15:29 ` [pve-devel] [PATCH-SERIES v6 0/13] remote migration DERUMIER, Alexandre

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=f5d43fee-801f-61e1-867c-05157732a7af@groupe-cyllene.com \
    --to=alexandre.derumier@groupe-cyllene.com \
    --cc=pve-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal