]> git.proxmox.com Git - pve-client.git/blame - PVE/APIClient/Config.pm
update files from pve-common
[pve-client.git] / PVE / APIClient / Config.pm
CommitLineData
a31c7b27
DM
1package PVE::APIClient::Config;
2
3use strict;
4use warnings;
5use JSON;
bcd2a4df
DM
6use File::Basename qw(dirname);
7use File::Path qw(make_path);
a31c7b27 8
bcd2a4df 9use PVE::APIClient::Helpers;
c9138c03
DM
10use PVE::APIClient::JSONSchema;
11use PVE::APIClient::SectionConfig;
269f8ffa 12use PVE::APIClient::PTY;
ca3269f4 13use PVE::APIClient::Tools qw(file_get_contents file_set_contents);
a31c7b27 14
c9138c03 15use base qw(PVE::APIClient::SectionConfig);
69aa81b3 16
a6dab5b8
DM
17my $remote_namne_regex = qw(\w+);
18
19my $defaults_section = '!DEFAULTS';
20
184877d4
DM
21my $complete_remote_name = sub {
22
69aa81b3 23 my $config = PVE::APIClient::Config->load();
a6dab5b8
DM
24 my $list = [];
25 foreach my $name (keys %{$config->{ids}}) {
26 push @$list, $name if $name ne $defaults_section;
27 }
28 return $list;
184877d4
DM
29};
30
c9138c03 31PVE::APIClient::JSONSchema::register_standard_option('pveclient-remote-name', {
184877d4
DM
32 description => "The name of the remote.",
33 type => 'string',
a6dab5b8 34 pattern => $remote_namne_regex,
184877d4
DM
35 completion => $complete_remote_name,
36});
37
69aa81b3
DM
38my $defaultData = {
39 propertyList => {
40 type => {
41 description => "Section type.",
42 optional => 1,
43 },
69aa81b3
DM
44 },
45};
06039c7f 46
69aa81b3
DM
47sub private {
48 return $defaultData;
06039c7f 49}
aa570b38 50
69aa81b3
DM
51sub config_filename {
52 my ($class) = @_;
aa570b38 53
bcd2a4df 54 my $dir = PVE::APIClient::Helpers::configuration_directory();
aa5833d6 55
bcd2a4df 56 return "$dir/config";
06039c7f 57}
aa570b38 58
b4007425
DM
59sub lock_config {
60 my ($class, $timeout, $code, @param) = @_;
61
ace4a6df
RJ
62 my $dir = PVE::APIClient::Helpers::configuration_directory();
63 make_path($dir);
64
65 my $filename = "$dir/.config.lck";
b4007425
DM
66
67 my $res = PVE::APIClient::Tools::lock_file($filename, $timeout, $code, @param);
68
69 die $@ if $@;
70
71 return $res;
72}
73
a6dab5b8
DM
74sub format_section_header {
75 my ($class, $type, $sectionId, $scfg, $done_hash) = @_;
76
77 if ($type eq 'defaults') {
78 return "defaults:\n";
79 } else {
80 return "$type: $sectionId\n";
81 }
82}
83
84sub parse_section_header {
85 my ($class, $line) = @_;
86
87 if ($line =~ m/^defaults:\s*$/) {
88 return ('defaults', $defaults_section, undef, {});
89 } elsif ($line =~ m/^(\S+):\s*(\S+)\s*$/) {
90 my ($type, $name) = (lc($1), $2);
91 eval {
92 die "invalid remote name '$name'\n"
93 if $name eq $defaults_section || $name !~ m/^$remote_namne_regex$/;
94 };
95 return ($type, $name, $@, {});
96 }
97 return undef;
98}
99
69aa81b3
DM
100sub load {
101 my ($class) = @_;
06039c7f 102
69aa81b3 103 my $filename = $class->config_filename();
aa570b38 104
69aa81b3 105 my $raw = '';
06039c7f 106
69aa81b3
DM
107 if (-e $filename) {
108 my $filemode = (stat($filename))[2] & 07777;
109 if ($filemode != 0600) {
110 die sprintf "wrong permissions on '$filename' %04o (expected 0600)\n", $filemode;
111 }
06039c7f 112
69aa81b3
DM
113 $raw = file_get_contents($filename);
114 }
06039c7f 115
69aa81b3
DM
116 return $class->parse_config($filename, $raw);
117}
06039c7f 118
69aa81b3
DM
119sub save {
120 my ($class, $cfg) = @_;
06039c7f 121
69aa81b3 122 my $filename = $class->config_filename();
a6dab5b8 123
bcd2a4df
DM
124 make_path(dirname($filename));
125
a6dab5b8 126 $cfg->{order}->{$defaults_section} = -1; # write as first section
69aa81b3 127 my $raw = $class->write_config($filename, $cfg);
06039c7f 128
69aa81b3 129 file_set_contents($filename, $raw, 0600);
06039c7f
RJ
130}
131
a6dab5b8
DM
132sub get_defaults {
133 my ($class, $cfg) = @_;
134
135 $cfg->{ids}->{$defaults_section} //= {};
136
137 return $cfg->{ids}->{$defaults_section};
138}
139
69aa81b3
DM
140sub lookup_remote {
141 my ($class, $cfg, $name, $noerr) = @_;
06039c7f 142
69aa81b3 143 my $data = $cfg->{ids}->{$name};
06039c7f 144
69aa81b3 145 return $data if $noerr || defined($data);
06039c7f 146
69aa81b3 147 die "unknown remote \"$name\"\n";
06039c7f
RJ
148}
149
150sub remote_conn {
69aa81b3 151 my ($class, $cfg, $remote) = @_;
06039c7f 152
69aa81b3 153 my $section = $class->lookup_remote($cfg, $remote);
8842464b 154
05d328ef
DM
155 my $trylogin = sub {
156 my ($ticket_or_password) = @_;
157
158 if (!defined($ticket_or_password)) {
159 $ticket_or_password = PVE::APIClient::PTY::read_password("Remote password: ")
160 }
161
162 my $setup = {
163 username => $section->{username},
164 password => $ticket_or_password,
165 host => $section->{host},
166 port => $section->{port} // 8006,
167 cached_fingerprints => {
168 $section->{fingerprint} => 1,
169 }
170 };
171
172 my $conn = PVE::APIClient::LWP->new(%$setup);
173
174 $conn->login();
175
176 return $conn;
177 };
178
8842464b 179 my $password = $section->{password};
8842464b 180
05d328ef
DM
181 my $conn;
182
183 if (defined($password)) {
184 $conn = $trylogin->($password);
185 } else {
186
187 if (my $ticket = PVE::APIClient::Helpers::ticket_cache_lookup($remote)) {
188 eval { $conn = $trylogin->($ticket); };
189 if (my $err = $@) {
190 PVE::APIClient::Helpers::ticket_cache_update($remote, undef);
191 if (ref($err) && (ref($err) eq 'PVE::APIClient::Exception') && ($err->{code} == 401)) {
192 $conn = $trylogin->();
193 } else {
194 die $err;
195 }
196 }
197 } else {
198 $conn = $trylogin->();
06039c7f 199 }
05d328ef 200 }
aa570b38 201
05d328ef 202 PVE::APIClient::Helpers::ticket_cache_update($remote, $conn->{ticket});
aa570b38 203
06039c7f 204 return $conn;
aa570b38 205}
a31c7b27 206
a6dab5b8
DM
207package PVE::APIClient::RemoteConfig;
208
209use strict;
210use warnings;
211
c9138c03
DM
212use PVE::APIClient::JSONSchema qw(register_standard_option get_standard_option);
213use PVE::APIClient::SectionConfig;
a6dab5b8
DM
214
215use base qw( PVE::APIClient::Config);
216
217sub type {
218 return 'remote';
219}
220
221sub properties {
222 return {
223 name => get_standard_option('pveclient-remote-name'),
224 host => {
225 description => "The host.",
226 type => 'string', format => 'address',
227 optional => 1,
228 },
229 username => {
230 description => "The username.",
231 type => 'string',
232 optional => 1,
233 },
234 password => {
235 description => "The users password.",
236 type => 'string',
237 optional => 1,
238 },
239 port => {
240 description => "The port.",
241 type => 'integer',
242 optional => 1,
243 default => 8006,
244 },
245 fingerprint => {
246 description => "Fingerprint.",
247 type => 'string',
248 optional => 1,
249 },
250 comment => {
251 description => "Description.",
252 type => 'string',
253 optional => 1,
254 maxLength => 4096,
255 },
256 };
257}
258
259sub options {
260 return {
261 name => { optional => 0 },
262 host => { optional => 0 },
263 comment => { optional => 1 },
264 username => { optional => 0 },
265 password => { optional => 1 },
266 port => { optional => 1 },
267 fingerprint => { optional => 1 },
268 };
269}
270
271__PACKAGE__->register();
272
273
274package PVE::APIClient::DefaultsConfig;
275
276use strict;
277use warnings;
278
c9138c03 279use PVE::APIClient::JSONSchema qw(register_standard_option get_standard_option);
a6dab5b8
DM
280
281use base qw( PVE::APIClient::Config);
282
283
284sub type {
285 return 'defaults';
286}
287
288sub options {
289 return {
290 name => { optional => 1 },
291 username => { optional => 1 },
292 port => { optional => 1 },
293 };
294}
295
69aa81b3 296__PACKAGE__->register();
a6dab5b8
DM
297
298
299PVE::APIClient::Config->init();
69aa81b3 300
a31c7b27 3011;