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