]> git.proxmox.com Git - pve-container.git/blame - src/PVE/API2/LXC/Config.pm
create_vm: avoid premature write_config caused by update_pct_config
[pve-container.git] / src / PVE / API2 / LXC / Config.pm
CommitLineData
52389a07
DM
1package PVE::API2::LXC::Config;
2
3use strict;
4use warnings;
5
6use PVE::SafeSyslog;
7use PVE::Tools qw(extract_param run_command);
8use PVE::Exception qw(raise raise_param_exc);
9use PVE::INotify;
10use PVE::Cluster qw(cfs_read_file);
11use PVE::AccessControl;
12use PVE::Firewall;
13use PVE::Storage;
14use PVE::RESTHandler;
15use PVE::RPCEnvironment;
16use PVE::LXC;
7c92bb72 17use PVE::LXC::Config;
52389a07 18use PVE::LXC::Create;
52389a07 19use PVE::JSONSchema qw(get_standard_option);
1e17438e 20
52389a07
DM
21use base qw(PVE::RESTHandler);
22
52389a07
DM
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 => {
1e17438e 33 additionalProperties => 0,
52389a07
DM
34 properties => {
35 node => get_standard_option('pve-node'),
68e8f3c5 36 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid }),
52e8da5d
OB
37 current => {
38 description => "Get current values (instead of pending values).",
39 optional => 1,
40 default => 0,
41 type => 'boolean',
42 },
98f59049
TL
43 snapshot => get_standard_option('pve-snapshot-name', {
44 description => "Fetch config values from given snapshot.",
45 optional => 1,
46 completion => sub {
47 my ($cmd, $pname, $cur, $args) = @_;
48 PVE::LXC::Config->snapshot_list($args->[0]);
49 },
50 }),
52389a07
DM
51 },
52 },
53 returns => {
54 type => "object",
7c92bb72
DM
55 properties => PVE::LXC::Config->json_config_properties({
56 lxc => {
57 description => "Array of lxc low-level configurations ([[key1, value1], [key2, value2] ...]).",
58 type => 'array',
59 items => { type => 'array', items => { type => 'string' }},
60 optional => 1,
61 },
52389a07
DM
62 digest => {
63 type => 'string',
64 description => 'SHA1 digest of configuration file. This can be used to prevent concurrent modifications.',
65 }
7c92bb72 66 }),
52389a07
DM
67 },
68 code => sub {
69 my ($param) = @_;
70
52e8da5d
OB
71 raise_param_exc({ snapshot => "cannot use 'snapshot' parameter with 'current'",
72 current => "cannot use 'snapshot' parameter with 'current'"})
73 if ($param->{snapshot} && $param->{current});
52389a07 74
52e8da5d
OB
75 my $conf;
76 if ($param->{snapshot}) {
77 $conf = PVE::LXC::Config->load_snapshot_config($param->{vmid}, $param->{snapshot});
78 } else {
79 $conf = PVE::LXC::Config->load_current_config($param->{vmid}, $param->{current});
0a507a2d
RV
80 }
81
52389a07
DM
82 return $conf;
83 }});
84
85my $vm_config_perm_list = [
1e17438e
TL
86 'VM.Config.Disk',
87 'VM.Config.CPU',
88 'VM.Config.Memory',
89 'VM.Config.Network',
90 'VM.Config.Options',
91];
52389a07
DM
92
93__PACKAGE__->register_method({
94 name => 'update_vm',
95 path => '',
96 method => 'PUT',
97 protected => 1,
98 proxyto => 'node',
99 description => "Set container options.",
100 permissions => {
101 check => ['perm', '/vms/{vmid}', $vm_config_perm_list, any => 1],
9d294016 102 description => 'non-volume mount points in rootfs and mp[n] are restricted to root@pam',
52389a07
DM
103 },
104 parameters => {
1e17438e 105 additionalProperties => 0,
1b4cf758 106 properties => PVE::LXC::Config->json_config_properties(
52389a07
DM
107 {
108 node => get_standard_option('pve-node'),
68e8f3c5 109 vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid }),
52389a07
DM
110 delete => {
111 type => 'string', format => 'pve-configid-list',
112 description => "A list of settings you want to delete.",
113 optional => 1,
114 },
6517e001
OB
115 revert => {
116 type => 'string', format => 'pve-configid-list',
117 description => "Revert a pending change.",
118 optional => 1,
119 },
52389a07
DM
120 digest => {
121 type => 'string',
122 description => 'Prevent changes if current configuration file has different SHA1 digest. This can be used to prevent concurrent modifications.',
123 maxLength => 40,
124 optional => 1,
125 }
126 }),
127 },
128 returns => { type => 'null'},
129 code => sub {
130 my ($param) = @_;
131
132 my $rpcenv = PVE::RPCEnvironment::get();
52389a07
DM
133 my $authuser = $rpcenv->get_user();
134
135 my $node = extract_param($param, 'node');
52389a07
DM
136 my $vmid = extract_param($param, 'vmid');
137
138 my $digest = extract_param($param, 'digest');
139
140 die "no options specified\n" if !scalar(keys %$param);
141
142 my $delete_str = extract_param($param, 'delete');
143 my @delete = PVE::Tools::split_list($delete_str);
6517e001
OB
144 my $revert_str = extract_param($param, 'revert');
145 my @revert = PVE::Tools::split_list($revert_str);
52389a07 146
f1ba1a4b 147 PVE::LXC::check_ct_modify_config_perm($rpcenv, $authuser, $vmid, undef, {}, [@delete]);
6517e001
OB
148 PVE::LXC::check_ct_modify_config_perm($rpcenv, $authuser, $vmid, undef, {}, [@revert]);
149
150 foreach my $opt (@revert) {
151 raise_param_exc({ revert => "unknown option '$opt'" })
152 if !PVE::LXC::Config->option_exists($opt);
153
154 raise_param_exc({ revert => "you can't use '-$opt' and '-revert $opt' at the same time" })
155 if defined($param->{$opt});
156 }
52389a07
DM
157
158 foreach my $opt (@delete) {
6517e001
OB
159 raise_param_exc({ delete => "unknown option '$opt'" })
160 if !PVE::LXC::Config->option_exists($opt);
161
1e17438e 162 raise_param_exc({ delete => "you can't use '-$opt' and -delete $opt' at the same time" })
52389a07
DM
163 if defined($param->{$opt});
164
6517e001
OB
165 raise_param_exc({ delete => "you can't use '-delete $opt' and '-revert $opt' at the same time" })
166 if grep(/^$opt$/, @revert);
52389a07
DM
167 }
168
f1ba1a4b 169 PVE::LXC::check_ct_modify_config_perm($rpcenv, $authuser, $vmid, undef, $param, []);
52389a07 170
6517e001 171 my $storage_cfg = PVE::Storage::config();
52389a07 172
2aee38e5
WB
173 my $repl_conf = PVE::ReplicationConfig->new();
174 my $is_replicated = $repl_conf->check_for_existing_jobs($vmid, 1);
175 if ($is_replicated) {
015740e6 176 PVE::LXC::Config->foreach_volume($param, sub {
2aee38e5
WB
177 my ($opt, $mountpoint) = @_;
178 my $volid = $mountpoint->{volume};
179 return if !$volid || !($mountpoint->{replicate}//1);
180 if ($mountpoint->{type} eq 'volume') {
181 my ($storeid, $format);
182 if ($volid =~ $PVE::LXC::NEW_DISK_RE) {
183 $storeid = $1;
184 $format = $mountpoint->{format} || PVE::Storage::storage_default_format($storage_cfg, $storeid);
185 } else {
186 ($storeid, undef) = PVE::Storage::parse_volume_id($volid, 1);
187 $format = (PVE::Storage::parse_volname($storage_cfg, $volid))[6];
188 }
189 return if PVE::Storage::storage_can_replicate($storage_cfg, $storeid, $format);
03b3e188
WB
190 my $scfg = PVE::Storage::storage_config($storage_cfg, $storeid);
191 return if $scfg->{shared};
2aee38e5
WB
192 }
193 die "cannot add non-replicatable volume to a replicated VM\n";
194 });
195 }
196
52389a07
DM
197 my $code = sub {
198
67afe46e
FG
199 my $conf = PVE::LXC::Config->load_config($vmid);
200 PVE::LXC::Config->check_lock($conf);
52389a07
DM
201
202 PVE::Tools::assert_if_modified($digest, $conf->{digest});
203
204 my $running = PVE::LXC::check_running($vmid);
205
6517e001 206 my $errors = PVE::LXC::Config->update_pct_config($vmid, $conf, $running, $param, \@delete, \@revert);
87c36547 207 PVE::LXC::Config->write_config($vmid, $conf);
6517e001 208 $conf = PVE::LXC::Config->load_config($vmid);
52389a07 209
f91f3669 210 PVE::LXC::update_lxc_config($vmid, $conf);
6517e001 211 raise_param_exc($errors) if scalar(keys %$errors);
52389a07
DM
212 };
213
67afe46e 214 PVE::LXC::Config->lock_config($vmid, $code);
52389a07
DM
215
216 return undef;
217 }});
218
2191;