]>
Commit | Line | Data |
---|---|---|
a31c7b27 DM |
1 | package PVE::APIClient::Config; |
2 | ||
3 | use strict; | |
4 | use warnings; | |
5 | use JSON; | |
a31c7b27 | 6 | |
a6dab5b8 | 7 | use PVE::JSONSchema; |
69aa81b3 | 8 | use PVE::SectionConfig; |
06039c7f | 9 | use PVE::Tools qw(file_get_contents file_set_contents); |
a31c7b27 | 10 | |
69aa81b3 DM |
11 | use base qw(PVE::SectionConfig); |
12 | ||
a6dab5b8 DM |
13 | my $remote_namne_regex = qw(\w+); |
14 | ||
15 | my $defaults_section = '!DEFAULTS'; | |
16 | ||
184877d4 DM |
17 | my $complete_remote_name = sub { |
18 | ||
69aa81b3 | 19 | my $config = PVE::APIClient::Config->load(); |
a6dab5b8 DM |
20 | my $list = []; |
21 | foreach my $name (keys %{$config->{ids}}) { | |
22 | push @$list, $name if $name ne $defaults_section; | |
23 | } | |
24 | return $list; | |
184877d4 DM |
25 | }; |
26 | ||
a6dab5b8 | 27 | PVE::JSONSchema::register_standard_option('pveclient-remote-name', { |
184877d4 DM |
28 | description => "The name of the remote.", |
29 | type => 'string', | |
a6dab5b8 | 30 | pattern => $remote_namne_regex, |
184877d4 DM |
31 | completion => $complete_remote_name, |
32 | }); | |
33 | ||
69aa81b3 DM |
34 | my $defaultData = { |
35 | propertyList => { | |
36 | type => { | |
37 | description => "Section type.", | |
38 | optional => 1, | |
39 | }, | |
69aa81b3 DM |
40 | }, |
41 | }; | |
06039c7f | 42 | |
69aa81b3 DM |
43 | sub private { |
44 | return $defaultData; | |
06039c7f | 45 | } |
aa570b38 | 46 | |
69aa81b3 DM |
47 | sub config_filename { |
48 | my ($class) = @_; | |
aa570b38 | 49 | |
aa5833d6 DM |
50 | my $home = $ENV{HOME}; |
51 | ||
52 | die "environment HOME not set\n" if !defined($home); | |
53 | ||
54 | return "$home/.pveclient"; | |
06039c7f | 55 | } |
aa570b38 | 56 | |
a6dab5b8 DM |
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 | ||
69aa81b3 DM |
83 | sub load { |
84 | my ($class) = @_; | |
06039c7f | 85 | |
69aa81b3 | 86 | my $filename = $class->config_filename(); |
aa570b38 | 87 | |
69aa81b3 | 88 | my $raw = ''; |
06039c7f | 89 | |
69aa81b3 DM |
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 | } | |
06039c7f | 95 | |
69aa81b3 DM |
96 | $raw = file_get_contents($filename); |
97 | } | |
06039c7f | 98 | |
69aa81b3 DM |
99 | return $class->parse_config($filename, $raw); |
100 | } | |
06039c7f | 101 | |
69aa81b3 DM |
102 | sub save { |
103 | my ($class, $cfg) = @_; | |
06039c7f | 104 | |
69aa81b3 | 105 | my $filename = $class->config_filename(); |
a6dab5b8 DM |
106 | |
107 | $cfg->{order}->{$defaults_section} = -1; # write as first section | |
69aa81b3 | 108 | my $raw = $class->write_config($filename, $cfg); |
06039c7f | 109 | |
69aa81b3 | 110 | file_set_contents($filename, $raw, 0600); |
06039c7f RJ |
111 | } |
112 | ||
a6dab5b8 DM |
113 | sub get_defaults { |
114 | my ($class, $cfg) = @_; | |
115 | ||
116 | $cfg->{ids}->{$defaults_section} //= {}; | |
117 | ||
118 | return $cfg->{ids}->{$defaults_section}; | |
119 | } | |
120 | ||
69aa81b3 DM |
121 | sub lookup_remote { |
122 | my ($class, $cfg, $name, $noerr) = @_; | |
06039c7f | 123 | |
69aa81b3 | 124 | my $data = $cfg->{ids}->{$name}; |
06039c7f | 125 | |
69aa81b3 | 126 | return $data if $noerr || defined($data); |
06039c7f | 127 | |
69aa81b3 | 128 | die "unknown remote \"$name\"\n"; |
06039c7f RJ |
129 | } |
130 | ||
131 | sub remote_conn { | |
69aa81b3 | 132 | my ($class, $cfg, $remote) = @_; |
06039c7f | 133 | |
69aa81b3 | 134 | my $section = $class->lookup_remote($cfg, $remote); |
8842464b DM |
135 | |
136 | my $password = $section->{password}; | |
137 | if (!defined($password)) { | |
138 | $password = PVE::PTY::read_password("Remote password: ") | |
139 | } | |
140 | ||
06039c7f RJ |
141 | my $conn = PVE::APIClient::LWP->new( |
142 | username => $section->{username}, | |
8842464b | 143 | password => $password, |
06039c7f | 144 | host => $section->{host}, |
8842464b | 145 | port => $section->{port} // 8006, |
06039c7f RJ |
146 | cached_fingerprints => { |
147 | $section->{fingerprint} => 1, | |
148 | } | |
149 | ); | |
aa570b38 | 150 | |
06039c7f | 151 | $conn->login; |
aa570b38 | 152 | |
06039c7f | 153 | return $conn; |
aa570b38 | 154 | } |
a31c7b27 | 155 | |
a6dab5b8 DM |
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 | ||
69aa81b3 | 245 | __PACKAGE__->register(); |
a6dab5b8 DM |
246 | |
247 | ||
248 | PVE::APIClient::Config->init(); | |
69aa81b3 | 249 | |
a31c7b27 | 250 | 1; |