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