]>
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 }), |
98f59049 TL |
37 | snapshot => get_standard_option('pve-snapshot-name', { |
38 | description => "Fetch config values from given snapshot.", | |
39 | optional => 1, | |
40 | completion => sub { | |
41 | my ($cmd, $pname, $cur, $args) = @_; | |
42 | PVE::LXC::Config->snapshot_list($args->[0]); | |
43 | }, | |
44 | }), | |
52389a07 DM |
45 | }, |
46 | }, | |
47 | returns => { | |
48 | type => "object", | |
7c92bb72 DM |
49 | properties => PVE::LXC::Config->json_config_properties({ |
50 | lxc => { | |
51 | description => "Array of lxc low-level configurations ([[key1, value1], [key2, value2] ...]).", | |
52 | type => 'array', | |
53 | items => { type => 'array', items => { type => 'string' }}, | |
54 | optional => 1, | |
55 | }, | |
52389a07 DM |
56 | digest => { |
57 | type => 'string', | |
58 | description => 'SHA1 digest of configuration file. This can be used to prevent concurrent modifications.', | |
59 | } | |
7c92bb72 | 60 | }), |
52389a07 DM |
61 | }, |
62 | code => sub { | |
63 | my ($param) = @_; | |
64 | ||
67afe46e | 65 | my $conf = PVE::LXC::Config->load_config($param->{vmid}); |
52389a07 | 66 | |
b7d72f30 | 67 | if (my $snapname = $param->{snapshot}) { |
0a507a2d | 68 | my $snapshot = $conf->{snapshots}->{$snapname}; |
b7d72f30 | 69 | die "snapshot '$snapname' does not exist\n" if !defined($snapshot); |
0a507a2d RV |
70 | |
71 | # we need the digest of the file | |
72 | $snapshot->{digest} = $conf->{digest}; | |
73 | $conf = $snapshot; | |
74 | } | |
75 | ||
52389a07 | 76 | delete $conf->{snapshots}; |
52389a07 DM |
77 | |
78 | return $conf; | |
79 | }}); | |
80 | ||
81 | my $vm_config_perm_list = [ | |
1e17438e TL |
82 | 'VM.Config.Disk', |
83 | 'VM.Config.CPU', | |
84 | 'VM.Config.Memory', | |
85 | 'VM.Config.Network', | |
86 | 'VM.Config.Options', | |
87 | ]; | |
52389a07 DM |
88 | |
89 | __PACKAGE__->register_method({ | |
90 | name => 'update_vm', | |
91 | path => '', | |
92 | method => 'PUT', | |
93 | protected => 1, | |
94 | proxyto => 'node', | |
95 | description => "Set container options.", | |
96 | permissions => { | |
97 | check => ['perm', '/vms/{vmid}', $vm_config_perm_list, any => 1], | |
9d294016 | 98 | description => 'non-volume mount points in rootfs and mp[n] are restricted to root@pam', |
52389a07 DM |
99 | }, |
100 | parameters => { | |
1e17438e | 101 | additionalProperties => 0, |
1b4cf758 | 102 | properties => PVE::LXC::Config->json_config_properties( |
52389a07 DM |
103 | { |
104 | node => get_standard_option('pve-node'), | |
68e8f3c5 | 105 | vmid => get_standard_option('pve-vmid', { completion => \&PVE::LXC::complete_ctid }), |
52389a07 DM |
106 | delete => { |
107 | type => 'string', format => 'pve-configid-list', | |
108 | description => "A list of settings you want to delete.", | |
109 | optional => 1, | |
110 | }, | |
111 | digest => { | |
112 | type => 'string', | |
113 | description => 'Prevent changes if current configuration file has different SHA1 digest. This can be used to prevent concurrent modifications.', | |
114 | maxLength => 40, | |
115 | optional => 1, | |
116 | } | |
117 | }), | |
118 | }, | |
119 | returns => { type => 'null'}, | |
120 | code => sub { | |
121 | my ($param) = @_; | |
122 | ||
123 | my $rpcenv = PVE::RPCEnvironment::get(); | |
52389a07 DM |
124 | my $authuser = $rpcenv->get_user(); |
125 | ||
126 | my $node = extract_param($param, 'node'); | |
52389a07 DM |
127 | my $vmid = extract_param($param, 'vmid'); |
128 | ||
129 | my $digest = extract_param($param, 'digest'); | |
130 | ||
131 | die "no options specified\n" if !scalar(keys %$param); | |
132 | ||
133 | my $delete_str = extract_param($param, 'delete'); | |
134 | my @delete = PVE::Tools::split_list($delete_str); | |
135 | ||
f1ba1a4b | 136 | PVE::LXC::check_ct_modify_config_perm($rpcenv, $authuser, $vmid, undef, {}, [@delete]); |
52389a07 DM |
137 | |
138 | foreach my $opt (@delete) { | |
1e17438e | 139 | raise_param_exc({ delete => "you can't use '-$opt' and -delete $opt' at the same time" }) |
52389a07 DM |
140 | if defined($param->{$opt}); |
141 | ||
1b4cf758 | 142 | if (!PVE::LXC::Config->option_exists($opt)) { |
52389a07 DM |
143 | raise_param_exc({ delete => "unknown option '$opt'" }); |
144 | } | |
145 | } | |
146 | ||
f1ba1a4b | 147 | PVE::LXC::check_ct_modify_config_perm($rpcenv, $authuser, $vmid, undef, $param, []); |
52389a07 DM |
148 | |
149 | my $storage_cfg = cfs_read_file("storage.cfg"); | |
150 | ||
2aee38e5 WB |
151 | my $repl_conf = PVE::ReplicationConfig->new(); |
152 | my $is_replicated = $repl_conf->check_for_existing_jobs($vmid, 1); | |
153 | if ($is_replicated) { | |
154 | PVE::LXC::Config->foreach_mountpoint_full($param, 0, sub { | |
155 | my ($opt, $mountpoint) = @_; | |
156 | my $volid = $mountpoint->{volume}; | |
157 | return if !$volid || !($mountpoint->{replicate}//1); | |
158 | if ($mountpoint->{type} eq 'volume') { | |
159 | my ($storeid, $format); | |
160 | if ($volid =~ $PVE::LXC::NEW_DISK_RE) { | |
161 | $storeid = $1; | |
162 | $format = $mountpoint->{format} || PVE::Storage::storage_default_format($storage_cfg, $storeid); | |
163 | } else { | |
164 | ($storeid, undef) = PVE::Storage::parse_volume_id($volid, 1); | |
165 | $format = (PVE::Storage::parse_volname($storage_cfg, $volid))[6]; | |
166 | } | |
167 | return if PVE::Storage::storage_can_replicate($storage_cfg, $storeid, $format); | |
03b3e188 WB |
168 | my $scfg = PVE::Storage::storage_config($storage_cfg, $storeid); |
169 | return if $scfg->{shared}; | |
2aee38e5 WB |
170 | } |
171 | die "cannot add non-replicatable volume to a replicated VM\n"; | |
172 | }); | |
173 | } | |
174 | ||
52389a07 DM |
175 | my $code = sub { |
176 | ||
67afe46e FG |
177 | my $conf = PVE::LXC::Config->load_config($vmid); |
178 | PVE::LXC::Config->check_lock($conf); | |
52389a07 DM |
179 | |
180 | PVE::Tools::assert_if_modified($digest, $conf->{digest}); | |
181 | ||
182 | my $running = PVE::LXC::check_running($vmid); | |
183 | ||
1b4cf758 | 184 | PVE::LXC::Config->update_pct_config($vmid, $conf, $running, $param, \@delete); |
52389a07 | 185 | |
67afe46e | 186 | PVE::LXC::Config->write_config($vmid, $conf); |
f91f3669 | 187 | PVE::LXC::update_lxc_config($vmid, $conf); |
52389a07 DM |
188 | }; |
189 | ||
67afe46e | 190 | PVE::LXC::Config->lock_config($vmid, $code); |
52389a07 DM |
191 | |
192 | return undef; | |
193 | }}); | |
194 | ||
195 | 1; |