]> git.proxmox.com Git - pve-client.git/blob - PVE/APIClient/Commands/remote.pm
implement config file locking
[pve-client.git] / PVE / APIClient / Commands / remote.pm
1 package PVE::APIClient::Commands::remote;
2
3 use strict;
4 use warnings;
5
6 use PVE::APIClient::Helpers;
7 use PVE::APIClient::JSONSchema qw(get_standard_option);
8 use PVE::APIClient::Tools qw(extract_param);
9 use PVE::APIClient::Config;
10
11 use PVE::APIClient::CLIHandler;
12
13 use PVE::APIClient::LWP;
14 use PVE::APIClient::PTY;
15
16 use base qw(PVE::APIClient::CLIHandler);
17
18 sub read_password {
19 return PVE::APIClient::PTY::read_password("Remote password: ")
20 }
21
22 __PACKAGE__->register_method ({
23 name => 'list',
24 path => 'list',
25 method => 'GET',
26 description => "List remotes from your config file.",
27 parameters => {
28 additionalProperties => 0,
29 },
30 returns => { type => 'null' },
31 code => sub {
32 my $config = PVE::APIClient::Config->load();
33
34 printf("%10s %10s %10s %10s %100s\n", "Name", "Host", "Port", "Username", "Fingerprint");
35 for my $name (keys %{$config->{ids}}) {
36 my $data = $config->{ids}->{$name};
37 next if $data->{type} ne 'remote';
38 printf("%10s %10s %10s %10s %100s\n", $name, $data->{'host'},
39 $data->{'port'} // '-', $data->{'username'}, $data->{'fingerprint'} // '-');
40 }
41
42 return undef;
43 }});
44
45 __PACKAGE__->register_method ({
46 name => 'add',
47 path => 'add',
48 method => 'POST',
49 description => "Add a remote to your config file.",
50 parameters => PVE::APIClient::RemoteConfig->createSchema(1),
51 returns => { type => 'null'},
52 code => sub {
53 my ($param) = @_;
54
55 my $remote = $param->{name};
56
57 # Note: we try to keep lock time sort, and lock later when we have all info
58 my $config = PVE::APIClient::Config->load();
59
60 die "Remote '$remote' already exists\n"
61 if $config->{ids}->{$remote};
62
63 my $last_fp = 0;
64
65 my $password = $param->{password};
66 if (!defined($password)) {
67 $password = PVE::APIClient::PTY::read_password("Remote password: ");
68 }
69
70 my $setup = {
71 username => $param->{username},
72 password => $password,
73 host => $param->{host},
74 port => $param->{port} // 8006,
75 };
76
77 if ($param->{fingerprint}) {
78 $setup->{cached_fingerprints} = {
79 $param->{fingerprint} => 1,
80 };
81 } else {
82 $setup->{manual_verification} = 1;
83 $setup->{register_fingerprint_cb} = sub {
84 my $fp = shift @_;
85 $last_fp = $fp;
86 };
87 }
88
89 my $api = PVE::APIClient::LWP->new(%$setup);
90 $api->login();
91
92 $param->{fingerprint} = $last_fp if !defined($param->{fingerprint});
93
94 my $plugin = PVE::APIClient::Config->lookup('remote');
95
96 my $code = sub {
97
98 $config = PVE::APIClient::Config->load(); # reload
99
100 # check again (file is locked now)
101 die "Remote '$remote' already exists\n"
102 if $config->{ids}->{$remote};
103
104 my $opts = $plugin->check_config($remote, $param, 1, 1);
105
106 $config->{ids}->{$remote} = $opts;
107
108 PVE::APIClient::Config->save($config);
109 };
110
111 PVE::APIClient::Config->lock_config(undef, $code);
112
113 return undef;
114 }});
115
116 __PACKAGE__->register_method ({
117 name => 'update',
118 path => 'update',
119 method => 'PUT',
120 description => "Update a remote configuration.",
121 parameters => PVE::APIClient::RemoteConfig->updateSchema(1),
122 returns => { type => 'null'},
123 code => sub {
124 my ($param) = @_;
125
126 my $name = extract_param($param, 'name');
127 my $digest = extract_param($param, 'digest');
128 my $delete = extract_param($param, 'delete');
129
130 my $code = sub {
131 my $config = PVE::APIClient::Config->load();
132 my $remote = PVE::APIClient::Config->lookup_remote($config, $name);
133
134 my $plugin = PVE::APIClient::Config->lookup('remote');
135 my $opts = $plugin->check_config($name, $param, 0, 1);
136
137 foreach my $k (%$opts) {
138 $remote->{$k} = $opts->{$k};
139 }
140
141 if ($delete) {
142 my $options = $plugin->private()->{options}->{'remote'};
143 foreach my $k (PVE::APIClient::Tools::APIClient::split_list($delete)) {
144 my $d = $options->{$k} ||
145 die "no such option '$k'\n";
146 die "unable to delete required option '$k'\n"
147 if !$d->{optional};
148 die "unable to delete fixed option '$k'\n"
149 if $d->{fixed};
150 delete $remote->{$k};
151 }
152 }
153
154 PVE::APIClient::Config->save($config);
155 };
156
157 PVE::APIClient::Config->lock_config(undef, $code);
158
159 return undef;
160 }});
161
162 __PACKAGE__->register_method ({
163 name => 'remove',
164 path => 'remove',
165 method => 'DELETE',
166 description => "Removes a remote from your config file.",
167 parameters => {
168 additionalProperties => 0,
169 properties => {
170 name => get_standard_option('pveclient-remote-name'),
171 },
172 },
173 returns => { type => 'null'},
174 code => sub {
175 my ($param) = @_;
176
177 my $code = sub {
178 my $config = PVE::APIClient::Config->load();
179 delete $config->{ids}->{$param->{name}};
180 PVE::APIClient::Config->save($config);
181 };
182
183 PVE::APIClient::Config->lock_config(undef, $code);
184
185 return undef;
186 }});
187
188 our $cmddef = {
189 add => [ __PACKAGE__, 'add', ['name', 'host', 'username']],
190 update => [ __PACKAGE__, 'update', ['name']],
191 remove => [ __PACKAGE__, 'remove', ['name']],
192 list => [__PACKAGE__, 'list'],
193 };
194
195 1;