]>
Commit | Line | Data |
---|---|---|
52389a07 DM |
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; | |
7c92bb72 | 17 | use PVE::LXC::Config; |
52389a07 | 18 | use PVE::LXC::Create; |
52389a07 | 19 | use PVE::JSONSchema qw(get_standard_option); |
1e17438e | 20 | |
52389a07 DM |
21 | use 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 | ||
85 | my $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 | |
de41bced | 147 | my $code = sub { |
6517e001 | 148 | |
de41bced DC |
149 | my $conf = PVE::LXC::Config->load_config($vmid); |
150 | PVE::LXC::Config->check_lock($conf); | |
6517e001 | 151 | |
de41bced | 152 | PVE::Tools::assert_if_modified($digest, $conf->{digest}); |
52389a07 | 153 | |
de41bced DC |
154 | my $unprivileged = $conf->{unprivileged}; |
155 | PVE::LXC::check_ct_modify_config_perm($rpcenv, $authuser, $vmid, undef, $conf, {}, [@delete], $unprivileged); | |
156 | PVE::LXC::check_ct_modify_config_perm($rpcenv, $authuser, $vmid, undef, $conf, {}, [@revert], $unprivileged); | |
6517e001 | 157 | |
de41bced DC |
158 | foreach my $opt (@revert) { |
159 | raise_param_exc({ revert => "unknown option '$opt'" }) | |
160 | if !PVE::LXC::Config->option_exists($opt); | |
52389a07 | 161 | |
de41bced DC |
162 | raise_param_exc({ revert => "you can't use '-$opt' and '-revert $opt' at the same time" }) |
163 | if defined($param->{$opt}); | |
164 | } | |
52389a07 | 165 | |
de41bced DC |
166 | foreach my $opt (@delete) { |
167 | raise_param_exc({ delete => "unknown option '$opt'" }) | |
168 | if !PVE::LXC::Config->option_exists($opt); | |
2aee38e5 | 169 | |
de41bced DC |
170 | raise_param_exc({ delete => "you can't use '-$opt' and -delete $opt' at the same time" }) |
171 | if defined($param->{$opt}); | |
52389a07 | 172 | |
de41bced DC |
173 | raise_param_exc({ delete => "you can't use '-delete $opt' and '-revert $opt' at the same time" }) |
174 | if grep(/^$opt$/, @revert); | |
175 | } | |
52389a07 | 176 | |
de41bced DC |
177 | PVE::LXC::check_ct_modify_config_perm($rpcenv, $authuser, $vmid, undef, $conf, $param, [], $unprivileged); |
178 | ||
179 | my $storage_cfg = PVE::Storage::config(); | |
180 | ||
181 | my $repl_conf = PVE::ReplicationConfig->new(); | |
182 | my $is_replicated = $repl_conf->check_for_existing_jobs($vmid, 1); | |
183 | if ($is_replicated) { | |
184 | PVE::LXC::Config->foreach_volume($param, sub { | |
185 | my ($opt, $mountpoint) = @_; | |
186 | my $volid = $mountpoint->{volume}; | |
187 | return if !$volid || !($mountpoint->{replicate}//1); | |
188 | if ($mountpoint->{type} eq 'volume') { | |
189 | my ($storeid, $format); | |
190 | if ($volid =~ $PVE::LXC::NEW_DISK_RE) { | |
191 | $storeid = $1; | |
192 | $format = $mountpoint->{format} || PVE::Storage::storage_default_format($storage_cfg, $storeid); | |
193 | } else { | |
194 | ($storeid, undef) = PVE::Storage::parse_volume_id($volid, 1); | |
195 | $format = (PVE::Storage::parse_volname($storage_cfg, $volid))[6]; | |
196 | } | |
197 | return if PVE::Storage::storage_can_replicate($storage_cfg, $storeid, $format); | |
198 | my $scfg = PVE::Storage::storage_config($storage_cfg, $storeid); | |
199 | return if $scfg->{shared}; | |
200 | } | |
201 | die "cannot add non-replicatable volume to a replicated VM\n"; | |
202 | }); | |
203 | } | |
52389a07 DM |
204 | |
205 | my $running = PVE::LXC::check_running($vmid); | |
206 | ||
6517e001 | 207 | my $errors = PVE::LXC::Config->update_pct_config($vmid, $conf, $running, $param, \@delete, \@revert); |
87c36547 | 208 | PVE::LXC::Config->write_config($vmid, $conf); |
6517e001 | 209 | $conf = PVE::LXC::Config->load_config($vmid); |
52389a07 | 210 | |
f91f3669 | 211 | PVE::LXC::update_lxc_config($vmid, $conf); |
6517e001 | 212 | raise_param_exc($errors) if scalar(keys %$errors); |
52389a07 DM |
213 | }; |
214 | ||
67afe46e | 215 | PVE::LXC::Config->lock_config($vmid, $code); |
52389a07 DM |
216 | |
217 | return undef; | |
218 | }}); | |
219 | ||
220 | 1; |