]> git.proxmox.com Git - pve-container.git/blob - src/PVE/API2/LXC/Config.pm
refuse to add non-replicatable disks to replicating VMs
[pve-container.git] / src / PVE / API2 / LXC / Config.pm
1 package PVE::API2::LXC::Config;
2
3 use strict;
4 use warnings;
5
6 use PVE::SafeSyslog;
7 use PVE::Tools qw(extract_param run_command);
8 use PVE::Exception qw(raise raise_param_exc);
9 use PVE::INotify;
10 use PVE::Cluster qw(cfs_read_file);
11 use PVE::AccessControl;
12 use PVE::Firewall;
13 use PVE::Storage;
14 use PVE::RESTHandler;
15 use PVE::RPCEnvironment;
16 use PVE::LXC;
17 use PVE::LXC::Create;
18 use PVE::JSONSchema qw(get_standard_option);
19 use base qw(PVE::RESTHandler);
20
21 use Data::Dumper; # fixme: remove
22
23 __PACKAGE__->register_method({
24 name => 'vm_config',
25 path => '',
26 method => 'GET',
27 proxyto => 'node',
28 description => "Get container configuration.",
29 permissions => {
30 check => ['perm', '/vms/{vmid}', [ 'VM.Audit' ]],
31 },
32 parameters => {
33 additionalProperties => 0,
34 properties => {
35 node => get_standard_option('pve-node'),
36 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid }),
37 },
38 },
39 returns => {
40 type => "object",
41 properties => {
42 digest => {
43 type => 'string',
44 description => 'SHA1 digest of configuration file. This can be used to prevent concurrent modifications.',
45 }
46 },
47 },
48 code => sub {
49 my ($param) = @_;
50
51 my $conf = PVE::LXC::Config->load_config($param->{vmid});
52
53 delete $conf->{snapshots};
54
55 return $conf;
56 }});
57
58 my $vm_config_perm_list = [
59 'VM.Config.Disk',
60 'VM.Config.CPU',
61 'VM.Config.Memory',
62 'VM.Config.Network',
63 'VM.Config.Options',
64 ];
65
66 __PACKAGE__->register_method({
67 name => 'update_vm',
68 path => '',
69 method => 'PUT',
70 protected => 1,
71 proxyto => 'node',
72 description => "Set container options.",
73 permissions => {
74 check => ['perm', '/vms/{vmid}', $vm_config_perm_list, any => 1],
75 description => 'non-volume mount points in rootfs and mp[n] are restricted to root@pam',
76 },
77 parameters => {
78 additionalProperties => 0,
79 properties => PVE::LXC::Config->json_config_properties(
80 {
81 node => get_standard_option('pve-node'),
82 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid }),
83 delete => {
84 type => 'string', format => 'pve-configid-list',
85 description => "A list of settings you want to delete.",
86 optional => 1,
87 },
88 digest => {
89 type => 'string',
90 description => 'Prevent changes if current configuration file has different SHA1 digest. This can be used to prevent concurrent modifications.',
91 maxLength => 40,
92 optional => 1,
93 }
94 }),
95 },
96 returns => { type => 'null'},
97 code => sub {
98 my ($param) = @_;
99
100 my $rpcenv = PVE::RPCEnvironment::get();
101
102 my $authuser = $rpcenv->get_user();
103
104 my $node = extract_param($param, 'node');
105
106 my $vmid = extract_param($param, 'vmid');
107
108 my $digest = extract_param($param, 'digest');
109
110 die "no options specified\n" if !scalar(keys %$param);
111
112 my $delete_str = extract_param($param, 'delete');
113 my @delete = PVE::Tools::split_list($delete_str);
114
115 PVE::LXC::check_ct_modify_config_perm($rpcenv, $authuser, $vmid, undef, {}, [@delete]);
116
117 foreach my $opt (@delete) {
118 raise_param_exc({ delete => "you can't use '-$opt' and " .
119 "-delete $opt' at the same time" })
120 if defined($param->{$opt});
121
122 if (!PVE::LXC::Config->option_exists($opt)) {
123 raise_param_exc({ delete => "unknown option '$opt'" });
124 }
125 }
126
127 PVE::LXC::check_ct_modify_config_perm($rpcenv, $authuser, $vmid, undef, $param, []);
128
129 my $storage_cfg = cfs_read_file("storage.cfg");
130
131 my $repl_conf = PVE::ReplicationConfig->new();
132 my $is_replicated = $repl_conf->check_for_existing_jobs($vmid, 1);
133 if ($is_replicated) {
134 PVE::LXC::Config->foreach_mountpoint_full($param, 0, sub {
135 my ($opt, $mountpoint) = @_;
136 my $volid = $mountpoint->{volume};
137 return if !$volid || !($mountpoint->{replicate}//1);
138 if ($mountpoint->{type} eq 'volume') {
139 my ($storeid, $format);
140 if ($volid =~ $PVE::LXC::NEW_DISK_RE) {
141 $storeid = $1;
142 $format = $mountpoint->{format} || PVE::Storage::storage_default_format($storage_cfg, $storeid);
143 } else {
144 ($storeid, undef) = PVE::Storage::parse_volume_id($volid, 1);
145 $format = (PVE::Storage::parse_volname($storage_cfg, $volid))[6];
146 }
147 return if PVE::Storage::storage_can_replicate($storage_cfg, $storeid, $format);
148 }
149 die "cannot add non-replicatable volume to a replicated VM\n";
150 });
151 }
152
153 my $code = sub {
154
155 my $conf = PVE::LXC::Config->load_config($vmid);
156 PVE::LXC::Config->check_lock($conf);
157
158 PVE::Tools::assert_if_modified($digest, $conf->{digest});
159
160 my $running = PVE::LXC::check_running($vmid);
161
162 PVE::LXC::Config->update_pct_config($vmid, $conf, $running, $param, \@delete);
163
164 PVE::LXC::Config->write_config($vmid, $conf);
165 PVE::LXC::update_lxc_config($vmid, $conf);
166 };
167
168 PVE::LXC::Config->lock_config($vmid, $code);
169
170 return undef;
171 }});
172
173 1;