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