]>
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}); | |
630f436a | 35 | $rpcenv->set_user('root@pam'); |
b6cf0a66 DM |
36 | |
37 | __PACKAGE__->register_method ({ | |
630f436a | 38 | name => 'path', |
b6cf0a66 DM |
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' }, | |
630f436a | 52 | |
b6cf0a66 DM |
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 | ||
630f436a DM |
81 | printf "%-${maxlenname}s %5s %10d %d\n", $volid, |
82 | $info->{format}, $info->{size}, $info->{vmid}; | |
b6cf0a66 DM |
83 | } |
84 | ||
85 | foreach my $info (sort { $a->{format} cmp $b->{format} } @$list) { | |
86 | next if $info->{vmid}; | |
87 | my $volid = $info->{volid}; | |
88 | ||
630f436a DM |
89 | printf "%-${maxlenname}s %5s %10d\n", $volid, |
90 | $info->{format}, $info->{size}; | |
b6cf0a66 DM |
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; | |
630f436a | 103 | |
b6cf0a66 DM |
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 | ||
630f436a | 110 | printf "%-${maxlen}s %5s %1d %15d %15d %15d %.2f%%\n", $storeid, |
b6cf0a66 | 111 | $res->{type}, $res->{active}, |
630f436a | 112 | $res->{total}/1024, $res->{used}/1024, $res->{avail}/1024, $per; |
b6cf0a66 DM |
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'] ], | |
630f436a | 122 | status => [ "PVE::API2::Storage::Status", 'index', [], |
b6cf0a66 | 123 | { node => $nodename }, $print_status ], |
630f436a | 124 | list => [ "PVE::API2::Storage::Content", 'index', ['storage'], |
b6cf0a66 | 125 | { node => $nodename }, $print_content ], |
630f436a | 126 | alloc => [ "PVE::API2::Storage::Content", 'create', ['storage', 'vmid', 'filename', 'size'], |
b6cf0a66 DM |
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 | ||
630f436a | 171 | PVE::CLIHandler::handle_cmd($cmddef, "pvesm", $cmd, \@ARGV, undef, $0); |
b6cf0a66 DM |
172 | |
173 | exit 0; | |
174 | ||
175 | __END__ | |
176 | ||
177 | =head1 NAME | |
178 | ||
179 | pvesm - PVE Storage Manager | |
180 | ||
181 | =head1 SYNOPSIS | |
182 | ||
630f436a | 183 | =include synopsis |
b6cf0a66 | 184 | |
630f436a | 185 | =head1 DESCRIPTION |
b6cf0a66 | 186 | |
630f436a | 187 | =head2 Storage pools |
b6cf0a66 | 188 | |
630f436a | 189 | Each storage pool is uniquely identified by its <STORAGE_ID>. |
b6cf0a66 | 190 | |
630f436a | 191 | =head3 Storage content |
b6cf0a66 | 192 | |
630f436a DM |
193 | A storage can support several content types, for example virtual disk |
194 | images, cdrom iso images, openvz templates or openvz root directories | |
195 | (C<images>, C<iso>, C<vztmpl>, C<rootdir>). | |
b6cf0a66 | 196 | |
630f436a | 197 | =head2 Volumes |
b6cf0a66 | 198 | |
630f436a DM |
199 | A volume is identified by the <STORAGE_ID>, followed by a storage type |
200 | dependent volume name, separated by colon. A valid <VOLUME_ID> looks like: | |
b6cf0a66 | 201 | |
630f436a | 202 | local:230/example-image.raw |
b6cf0a66 | 203 | |
630f436a | 204 | local:iso/debian-501-amd64-netinst.iso |
b6cf0a66 | 205 | |
630f436a | 206 | local:vztmpl/debian-5.0-joomla_1.5.9-1_i386.tar.gz |
b6cf0a66 | 207 | |
630f436a | 208 | iscsi-storage:0.0.2.scsi-14f504e46494c4500494b5042546d2d646744372d31616d61 |
b6cf0a66 | 209 | |
630f436a | 210 | To get the filesystem path for a <VOLUME_ID> use: |
b6cf0a66 | 211 | |
630f436a | 212 | pvesm path <VOLUME_ID> |
b6cf0a66 | 213 | |
b6cf0a66 | 214 | |
630f436a | 215 | =head1 EXAMPLES |
b6cf0a66 | 216 | |
630f436a DM |
217 | # scan iscsi host for available targets |
218 | pvesm scan iscsi <HOST[:PORT]> | |
b6cf0a66 | 219 | |
630f436a DM |
220 | # scan nfs server for available exports |
221 | pvesm scan nfs <HOST> | |
b6cf0a66 | 222 | |
630f436a DM |
223 | # add storage pools |
224 | pvesm add <STORAGE_ID> <TYPE> <OPTIONS> | |
225 | pvesm add <STORAGE_ID> dir --path <PATH> | |
226 | pvesm add <STORAGE_ID> nfs --path <PATH> --server <SERVER> --export <EXPORT> | |
227 | pvesm add <STORAGE_ID> lvm --vgname <VGNAME> | |
228 | pvesm add <STORAGE_ID> iscsi --portal <HOST[:PORT]> --target <TARGET> | |
b6cf0a66 | 229 | |
630f436a DM |
230 | # disable storage pools |
231 | pvesm set <STORAGE_ID> --disable 1 | |
b6cf0a66 | 232 | |
630f436a DM |
233 | # enable storage pools |
234 | pvesm set <STORAGE_ID> --disable 0 | |
b6cf0a66 | 235 | |
630f436a DM |
236 | # change/set storage options |
237 | pvesm set <STORAGE_ID> <OPTIONS> | |
238 | pvesm set <STORAGE_ID> --shared 1 | |
239 | pvesm set local --format qcow2 | |
240 | pvesm set <STORAGE_ID> --content iso | |
b6cf0a66 | 241 | |
630f436a DM |
242 | # remove storage pools - does not delete any data |
243 | pvesm remove <STORAGE_ID> | |
b6cf0a66 | 244 | |
630f436a DM |
245 | # alloc volumes |
246 | pvesm alloc <STORAGE_ID> <VMID> <name> <size> [--format <raw|qcow2>] | |
b6cf0a66 | 247 | |
630f436a DM |
248 | # alloc 4G volume in local storage - use auto generated name |
249 | pvesm alloc local <VMID> '' 4G | |
b6cf0a66 | 250 | |
630f436a DM |
251 | # free volumes (warning: destroy/deletes all volume data) |
252 | pvesm free <VOLUME_ID> | |
b6cf0a66 | 253 | |
630f436a DM |
254 | # list storage status |
255 | pvesm status | |
b6cf0a66 | 256 | |
630f436a DM |
257 | # list storage contents |
258 | pvesm list <STORAGE_ID> [--vmid <VMID>] | |
b6cf0a66 | 259 | |
630f436a DM |
260 | # list volumes allocated by VMID |
261 | pvesm list <STORAGE_ID> --vmid <VMID> | |
b6cf0a66 | 262 | |
630f436a DM |
263 | # list iso images |
264 | pvesm list <STORAGE_ID> --iso | |
b6cf0a66 | 265 | |
630f436a DM |
266 | # list openvz templates |
267 | pvesm list <STORAGE_ID> --vztmpl | |
268 | ||
269 | # show filesystem path for a volume | |
b6cf0a66 DM |
270 | pvesm path <VOLUME_ID> |
271 | ||
630f436a | 272 | =include pve_copyright |