]>
Commit | Line | Data |
---|---|---|
b6cf0a66 DM |
1 | #!/usr/bin/perl -w |
2 | ||
3 | use strict; | |
4 | use Getopt::Long; | |
5 | use Fcntl ':flock'; | |
6 | use File::Path; | |
7 | ||
8 | use PVE::SafeSyslog; | |
9 | use PVE::Cluster; | |
10 | use PVE::INotify; | |
11 | use PVE::RPCEnvironment; | |
12 | use PVE::Storage; | |
13 | use PVE::API2::Storage::Config; | |
14 | use PVE::API2::Storage::Content; | |
15 | use PVE::API2::Storage::Status; | |
16 | use PVE::API2::Storage::Scan; | |
17 | use PVE::JSONSchema qw(get_standard_option); | |
18 | ||
19 | use PVE::CLIHandler; | |
20 | ||
21 | use base qw(PVE::CLIHandler); | |
22 | ||
23 | $ENV{'PATH'} = '/sbin:/bin:/usr/sbin:/usr/bin'; | |
24 | ||
25 | initlog ('pvesm'); | |
26 | ||
27 | die "please run as root\n" if $> != 0; | |
28 | ||
29 | PVE::INotify::inotify_init(); | |
30 | ||
31 | my $rpcenv = PVE::RPCEnvironment->init('cli'); | |
32 | ||
33 | $rpcenv->init_request(); | |
34 | $rpcenv->set_language($ENV{LANG}); | |
35 | $rpcenv->set_user('root@pam'); | |
36 | ||
37 | __PACKAGE__->register_method ({ | |
38 | name => 'path', | |
39 | path => 'path', | |
40 | method => 'GET', | |
41 | description => "Get filesystem path for specified volume", | |
42 | parameters => { | |
43 | additionalProperties => 0, | |
44 | properties => { | |
45 | volume => { | |
46 | description => "Volume identifier", | |
47 | type => 'string', format => 'pve-volume-id', | |
48 | }, | |
49 | }, | |
50 | }, | |
51 | returns => { type => 'null' }, | |
52 | ||
53 | code => sub { | |
54 | my ($param) = @_; | |
55 | ||
56 | my $cfg = PVE::Storage::config(); | |
57 | ||
58 | my $path = PVE::Storage::path ($cfg, $param->{volume}); | |
59 | ||
60 | print "$path\n"; | |
61 | ||
62 | return undef; | |
63 | ||
64 | }}); | |
65 | ||
66 | my $print_content = sub { | |
67 | my ($list) = @_; | |
68 | ||
69 | my $maxlenname = 0; | |
70 | foreach my $info (@$list) { | |
71 | ||
72 | my $volid = $info->{volid}; | |
73 | my $sidlen = length ($volid); | |
74 | $maxlenname = $sidlen if $sidlen > $maxlenname; | |
75 | } | |
76 | ||
77 | foreach my $info (@$list) { | |
78 | next if !$info->{vmid}; | |
79 | my $volid = $info->{volid}; | |
80 | ||
81 | printf "%-${maxlenname}s %5s %10d %d\n", $volid, | |
82 | $info->{format}, $info->{size}, $info->{vmid}; | |
83 | } | |
84 | ||
85 | foreach my $info (sort { $a->{format} cmp $b->{format} } @$list) { | |
86 | next if $info->{vmid}; | |
87 | my $volid = $info->{volid}; | |
88 | ||
89 | printf "%-${maxlenname}s %5s %10d\n", $volid, | |
90 | $info->{format}, $info->{size}; | |
91 | } | |
92 | }; | |
93 | ||
94 | my $print_status = sub { | |
95 | my $res = shift; | |
96 | ||
97 | my $maxlen = 0; | |
98 | foreach my $res (@$res) { | |
99 | my $storeid = $res->{storage}; | |
100 | $maxlen = length ($storeid) if length ($storeid) > $maxlen; | |
101 | } | |
102 | $maxlen+=1; | |
103 | ||
104 | foreach my $res (sort { $a->{storage} cmp $b->{storage} } @$res) { | |
105 | my $storeid = $res->{storage}; | |
106 | ||
107 | my $sum = $res->{used} + $res->{avail}; | |
108 | my $per = $sum ? (0.5 + ($res->{used}*100)/$sum) : 100; | |
109 | ||
110 | printf "%-${maxlen}s %5s %1d %15d %15d %15d %.2f%%\n", $storeid, | |
111 | $res->{type}, $res->{active}, | |
112 | $res->{total}/1024, $res->{used}/1024, $res->{avail}/1024, $per; | |
113 | } | |
114 | }; | |
115 | ||
116 | my $nodename = PVE::INotify::nodename(); | |
117 | ||
118 | my $cmddef = { | |
119 | add => [ "PVE::API2::Storage::Config", 'create', ['storage'] ], | |
120 | set => [ "PVE::API2::Storage::Config", 'update', ['storage'] ], | |
121 | remove => [ "PVE::API2::Storage::Config", 'delete', ['storage'] ], | |
122 | status => [ "PVE::API2::Storage::Status", 'index', [], | |
123 | { node => $nodename }, $print_status ], | |
124 | list => [ "PVE::API2::Storage::Content", 'index', ['storage'], | |
125 | { node => $nodename }, $print_content ], | |
126 | alloc => [ "PVE::API2::Storage::Content", 'create', ['storage', 'vmid', 'filename', 'size'], | |
127 | { node => $nodename }, sub { | |
128 | my $volid = shift; | |
129 | print "sucessfuly created '$volid'\n"; | |
130 | }], | |
131 | free => [ "PVE::API2::Storage::Content", 'delete', ['volume'], | |
132 | { node => $nodename } ], | |
133 | nfsscan => [ "PVE::API2::Storage::Scan", 'nfsscan', ['server'], | |
134 | { node => $nodename }, sub { | |
135 | my $res = shift; | |
136 | ||
137 | my $maxlen = 0; | |
138 | foreach my $rec (@$res) { | |
139 | my $len = length ($rec->{path}); | |
140 | $maxlen = $len if $len > $maxlen; | |
141 | } | |
142 | foreach my $rec (@$res) { | |
143 | printf "%-${maxlen}s %s\n", $rec->{path}, $rec->{options}; | |
144 | } | |
145 | }], | |
146 | iscsiscan => [ "PVE::API2::Storage::Scan", 'iscsiscan', ['server'], | |
147 | { node => $nodename }, sub { | |
148 | my $res = shift; | |
149 | ||
150 | my $maxlen = 0; | |
151 | foreach my $rec (@$res) { | |
152 | my $len = length ($rec->{target}); | |
153 | $maxlen = $len if $len > $maxlen; | |
154 | } | |
155 | foreach my $rec (@$res) { | |
156 | printf "%-${maxlen}s %s\n", $rec->{target}, $rec->{portal}; | |
157 | } | |
158 | }], | |
159 | lvmscan => [ "PVE::API2::Storage::Scan", 'lvmscan', [], | |
160 | { node => $nodename }, sub { | |
161 | my $res = shift; | |
162 | foreach my $rec (@$res) { | |
163 | printf "$rec->{vg}\n"; | |
164 | } | |
165 | }], | |
166 | path => [ __PACKAGE__, 'path', ['volume']], | |
167 | }; | |
168 | ||
169 | my $cmd = shift; | |
170 | ||
171 | if ($cmd && $cmd eq 'verifyapi') { | |
172 | PVE::RESTHandler::validate_method_schemas(); | |
173 | exit 0; | |
174 | } | |
175 | ||
176 | PVE::CLIHandler::handle_cmd($cmddef, "pvesm", $cmd, \@ARGV); | |
177 | ||
178 | exit 0; | |
179 | ||
180 | __END__ | |
181 | ||
182 | =head1 NAME | |
183 | ||
184 | pvesm - PVE Storage Manager | |
185 | ||
186 | =head1 SYNOPSIS | |
187 | ||
188 | pvesm <COMMAND> [OPTIONS] | |
189 | ||
190 | # scan iscsi host for available targets | |
191 | pvesm scan iscsi <HOST[:PORT]> | |
192 | ||
193 | # scan nfs server for available exports | |
194 | pvesm scan nfs <HOST> | |
195 | ||
196 | # add storage pools | |
197 | pvesm add <STORAGE_ID> <TYPE> <OPTIONS> | |
198 | pvesm add <STORAGE_ID> dir --path <PATH> | |
199 | pvesm add <STORAGE_ID> nfs --path <PATH> --server <SERVER> --export <EXPORT> | |
200 | pvesm add <STORAGE_ID> lvm --vgname <VGNAME> | |
201 | pvesm add <STORAGE_ID> iscsi --portal <HOST[:PORT]> --target <TARGET> | |
202 | ||
203 | # disable storage pools | |
204 | pvesm set <STORAGE_ID> --disable 1 | |
205 | ||
206 | # enable storage pools | |
207 | pvesm set <STORAGE_ID> --disable 0 | |
208 | ||
209 | # change/set storage options | |
210 | pvesm set <STORAGE_ID> <OPTIONS> | |
211 | pvesm set <STORAGE_ID> --shared 1 | |
212 | pvesm set local --format qcow2 | |
213 | pvesm set <STORAGE_ID> --content iso | |
214 | ||
215 | # remove storage pools - does not delete any data | |
216 | pvesm remove <STORAGE_ID> | |
217 | ||
218 | # add single devices?? | |
219 | ||
220 | # alloc volumes | |
221 | pvesm alloc <STORAGE_ID> <VMID> <name> <size> [--format <raw|qcow2>] | |
222 | ||
223 | # alloc 4G volume in local storage - use auto generated name | |
224 | pvesm alloc local <VMID> '' 4G | |
225 | ||
226 | # free volumes (warning: destroy/deletes all volume data) | |
227 | pvesm free <VOLUME_ID> | |
228 | ||
229 | # list storage status | |
230 | pvesm status | |
231 | ||
232 | # list storage contents | |
233 | pvesm list <STORAGE_ID> [--vmid <VMID>] | |
234 | ||
235 | # list volumes allocated by VMID | |
236 | pvesm list <STORAGE_ID> --vmid <VMID> | |
237 | ||
238 | # list iso images | |
239 | pvesm list <STORAGE_ID> --iso | |
240 | ||
241 | # list openvz templates | |
242 | pvesm list <STORAGE_ID> --vztmpl | |
243 | ||
244 | # show filesystem path for a volume | |
245 | pvesm path <VOLUME_ID> | |
246 | ||
247 | # import disks ?? | |
248 | ||
249 | ||
250 | =head1 DESCRIPTION | |
251 | ||
252 | =head2 Storage pools | |
253 | ||
254 | Each storage pool is uniquely identified by its <STORAGE_ID>. | |
255 | ||
256 | =head3 Storage content | |
257 | ||
258 | A storage can support several content types, for example virtual disk | |
259 | images, cdrom iso images, openvz templates or openvz root directories | |
260 | (C<images>, C<iso>, C<vztmpl>, C<rootdir>). | |
261 | ||
262 | =head2 Volumes | |
263 | ||
264 | A volume is identified by the <STORAGE_ID>, followed by a storage type | |
265 | dependent volume name, separated by colon. A valid <VOLUME_ID> looks like: | |
266 | ||
267 | local:230/example-image.raw | |
268 | ||
269 | local:iso/debian-501-amd64-netinst.iso | |
270 | ||
271 | local:vztmpl/debian-5.0-joomla_1.5.9-1_i386.tar.gz | |
272 | ||
273 | iscsi-storage:0.0.2.scsi-14f504e46494c4500494b5042546d2d646744372d31616d61 | |
274 | ||
275 | To get the filesystem path for a <VOLUME_ID> use: | |
276 | ||
277 | pvesm path <VOLUME_ID> | |
278 |