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