]> git.proxmox.com Git - pve-client.git/blob - PVE/APIClient/Config.pm
7189d8e41c3ab74c90f6cb16e5a8a43b26eded65
[pve-client.git] / PVE / APIClient / Config.pm
1 package PVE::APIClient::Config;
2
3 use strict;
4 use warnings;
5 use JSON;
6
7 use PVE::JSONSchema;
8 use PVE::SectionConfig;
9 use PVE::APIClient::Tools qw(file_get_contents file_set_contents);
10
11 use base qw(PVE::SectionConfig);
12
13 my $remote_namne_regex = qw(\w+);
14
15 my $defaults_section = '!DEFAULTS';
16
17 my $complete_remote_name = sub {
18
19 my $config = PVE::APIClient::Config->load();
20 my $list = [];
21 foreach my $name (keys %{$config->{ids}}) {
22 push @$list, $name if $name ne $defaults_section;
23 }
24 return $list;
25 };
26
27 PVE::JSONSchema::register_standard_option('pveclient-remote-name', {
28 description => "The name of the remote.",
29 type => 'string',
30 pattern => $remote_namne_regex,
31 completion => $complete_remote_name,
32 });
33
34 my $defaultData = {
35 propertyList => {
36 type => {
37 description => "Section type.",
38 optional => 1,
39 },
40 },
41 };
42
43 sub private {
44 return $defaultData;
45 }
46
47 sub config_filename {
48 my ($class) = @_;
49
50 my $home = $ENV{HOME};
51
52 die "environment HOME not set\n" if !defined($home);
53
54 return "$home/.pveclient";
55 }
56
57 sub format_section_header {
58 my ($class, $type, $sectionId, $scfg, $done_hash) = @_;
59
60 if ($type eq 'defaults') {
61 return "defaults:\n";
62 } else {
63 return "$type: $sectionId\n";
64 }
65 }
66
67 sub parse_section_header {
68 my ($class, $line) = @_;
69
70 if ($line =~ m/^defaults:\s*$/) {
71 return ('defaults', $defaults_section, undef, {});
72 } elsif ($line =~ m/^(\S+):\s*(\S+)\s*$/) {
73 my ($type, $name) = (lc($1), $2);
74 eval {
75 die "invalid remote name '$name'\n"
76 if $name eq $defaults_section || $name !~ m/^$remote_namne_regex$/;
77 };
78 return ($type, $name, $@, {});
79 }
80 return undef;
81 }
82
83 sub load {
84 my ($class) = @_;
85
86 my $filename = $class->config_filename();
87
88 my $raw = '';
89
90 if (-e $filename) {
91 my $filemode = (stat($filename))[2] & 07777;
92 if ($filemode != 0600) {
93 die sprintf "wrong permissions on '$filename' %04o (expected 0600)\n", $filemode;
94 }
95
96 $raw = file_get_contents($filename);
97 }
98
99 return $class->parse_config($filename, $raw);
100 }
101
102 sub save {
103 my ($class, $cfg) = @_;
104
105 my $filename = $class->config_filename();
106
107 $cfg->{order}->{$defaults_section} = -1; # write as first section
108 my $raw = $class->write_config($filename, $cfg);
109
110 file_set_contents($filename, $raw, 0600);
111 }
112
113 sub get_defaults {
114 my ($class, $cfg) = @_;
115
116 $cfg->{ids}->{$defaults_section} //= {};
117
118 return $cfg->{ids}->{$defaults_section};
119 }
120
121 sub lookup_remote {
122 my ($class, $cfg, $name, $noerr) = @_;
123
124 my $data = $cfg->{ids}->{$name};
125
126 return $data if $noerr || defined($data);
127
128 die "unknown remote \"$name\"\n";
129 }
130
131 sub remote_conn {
132 my ($class, $cfg, $remote) = @_;
133
134 my $section = $class->lookup_remote($cfg, $remote);
135
136 my $password = $section->{password};
137 if (!defined($password)) {
138 $password = PVE::PTY::read_password("Remote password: ")
139 }
140
141 my $conn = PVE::APIClient::LWP->new(
142 username => $section->{username},
143 password => $password,
144 host => $section->{host},
145 port => $section->{port} // 8006,
146 cached_fingerprints => {
147 $section->{fingerprint} => 1,
148 }
149 );
150
151 $conn->login;
152
153 return $conn;
154 }
155
156 package PVE::APIClient::RemoteConfig;
157
158 use strict;
159 use warnings;
160
161 use PVE::JSONSchema qw(register_standard_option get_standard_option);
162 use PVE::SectionConfig;
163
164 use base qw( PVE::APIClient::Config);
165
166 sub type {
167 return 'remote';
168 }
169
170 sub properties {
171 return {
172 name => get_standard_option('pveclient-remote-name'),
173 host => {
174 description => "The host.",
175 type => 'string', format => 'address',
176 optional => 1,
177 },
178 username => {
179 description => "The username.",
180 type => 'string',
181 optional => 1,
182 },
183 password => {
184 description => "The users password.",
185 type => 'string',
186 optional => 1,
187 },
188 port => {
189 description => "The port.",
190 type => 'integer',
191 optional => 1,
192 default => 8006,
193 },
194 fingerprint => {
195 description => "Fingerprint.",
196 type => 'string',
197 optional => 1,
198 },
199 comment => {
200 description => "Description.",
201 type => 'string',
202 optional => 1,
203 maxLength => 4096,
204 },
205 };
206 }
207
208 sub options {
209 return {
210 name => { optional => 0 },
211 host => { optional => 0 },
212 comment => { optional => 1 },
213 username => { optional => 0 },
214 password => { optional => 1 },
215 port => { optional => 1 },
216 fingerprint => { optional => 1 },
217 };
218 }
219
220 __PACKAGE__->register();
221
222
223 package PVE::APIClient::DefaultsConfig;
224
225 use strict;
226 use warnings;
227
228 use PVE::JSONSchema qw(register_standard_option get_standard_option);
229
230 use base qw( PVE::APIClient::Config);
231
232
233 sub type {
234 return 'defaults';
235 }
236
237 sub options {
238 return {
239 name => { optional => 1 },
240 username => { optional => 1 },
241 port => { optional => 1 },
242 };
243 }
244
245 __PACKAGE__->register();
246
247
248 PVE::APIClient::Config->init();
249
250 1;