root / snf-image-host / pithcat @ master
History | View | Annotate | Download (5 kB)
1 |
#!/usr/bin/env python |
---|---|
2 |
|
3 |
# Copyright (C) 2011-2013 GRNET S.A. |
4 |
# |
5 |
# This program is free software; you can redistribute it and/or modify |
6 |
# it under the terms of the GNU General Public License as published by |
7 |
# the Free Software Foundation; either version 2 of the License, or |
8 |
# (at your option) any later version. |
9 |
# |
10 |
# This program is distributed in the hope that it will be useful, but |
11 |
# WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 |
# General Public License for more details. |
14 |
# |
15 |
# You should have received a copy of the GNU General Public License |
16 |
# along with this program; if not, write to the Free Software |
17 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
18 |
# 02110-1301, USA. |
19 |
|
20 |
""" |
21 |
A tool that connects to the Pithos backend and returns the size and contents |
22 |
of a pithos object. |
23 |
|
24 |
Since the backend does not have a "root" account we use the account given in |
25 |
the URL as the user when connecting to the backend. |
26 |
""" |
27 |
|
28 |
from optparse import OptionParser, OptionGroup |
29 |
from sys import exit, stdout, stderr |
30 |
from os import environ |
31 |
from binascii import hexlify, unhexlify |
32 |
from collections import namedtuple |
33 |
|
34 |
try: |
35 |
from pithos.backends.modular import ModularBackend |
36 |
except ImportError: |
37 |
stderr.write("Pithos backend was not found.\n") |
38 |
exit(2) |
39 |
|
40 |
|
41 |
parser = OptionParser(usage='%prog [options] <URL>') |
42 |
parser.add_option('--data', dest='data', metavar='DIR', |
43 |
help='path to the directory where data are stored') |
44 |
parser.add_option('-s', action='store_true', dest='size', default=False, |
45 |
help='print file size and exit') |
46 |
group = OptionGroup( |
47 |
parser, "Dangerous Options", |
48 |
"Caution: If the <URL> is a LocationURL (pithos://...), then you'll also " |
49 |
"need to define a database URI. You can use the `--db' option to do so, " |
50 |
"but this raises security concerns. For database URI's and pithos data " |
51 |
"paths, the recommended way to define them is to use the PITHCAT_INPUT_DB " |
52 |
"and PITHCAT_INPUT_DATA environmental variables respectfully.") |
53 |
group.add_option('--db', dest='db', metavar='URI', |
54 |
help='SQLAlchemy URI of the database', default=None) |
55 |
parser.add_option_group(group) |
56 |
|
57 |
LocationURL = namedtuple('LocationURL', ['account', 'container', 'object']) |
58 |
HashmapURL = namedtuple('HashmapURL', ['hash', 'size']) |
59 |
|
60 |
|
61 |
def parse_url(url): |
62 |
if url.startswith('pithos://'): |
63 |
t = url.split('/', 4) |
64 |
assert len(t) == 5, "Invalid URL" |
65 |
return LocationURL(*t[2:5]) |
66 |
elif url.startswith('pithosmap://'): |
67 |
t = url.split('/', 3) |
68 |
assert len(t) == 4, "Invalid URL" |
69 |
return HashmapURL(*t[2:4]) |
70 |
else: |
71 |
raise Exception("Invalid URL") |
72 |
|
73 |
|
74 |
def print_size(backend, url): |
75 |
"""Writes object's size to stdout.""" |
76 |
if type(url) is LocationURL: |
77 |
account, container, object = url |
78 |
meta = backend.get_object_meta(account, account, container, object, |
79 |
None) |
80 |
print meta['bytes'] |
81 |
elif type(url) is HashmapURL: |
82 |
print url.size |
83 |
else: |
84 |
raise Exception("Invalid URL") |
85 |
|
86 |
|
87 |
def print_data(backend, url): |
88 |
"""Writes object's size to stdout.""" |
89 |
|
90 |
if type(url) is LocationURL: |
91 |
account, container, object = url |
92 |
size, hashmap = backend.get_object_hashmap(account, account, container, |
93 |
object) |
94 |
elif type(url) is HashmapURL: |
95 |
hashmap = [hexlify(x) |
96 |
for x in backend.store.map_get(unhexlify(url.hash))] |
97 |
size = int(url.size) |
98 |
else: |
99 |
raise Exception("Invalid URL") |
100 |
|
101 |
for hash in hashmap: |
102 |
block = backend.get_block(hash) |
103 |
if len(block) > size: |
104 |
block = block[:size] |
105 |
stdout.write(block) |
106 |
size -= len(block) |
107 |
|
108 |
|
109 |
def main(): |
110 |
options, args = parser.parse_args() |
111 |
if len(args) != 1: |
112 |
parser.print_help() |
113 |
exit(1) |
114 |
|
115 |
url = parse_url(args[0]) |
116 |
|
117 |
if not options.data and 'PITHCAT_INPUT_DATA' not in environ: |
118 |
stderr.write( |
119 |
"Pithos data directory path is missing.\n" |
120 |
"Use the PITHCAT_INPUT_DATA environmental variable (recommended) " |
121 |
"or the --data command line option to define it.\n") |
122 |
exit(1) |
123 |
|
124 |
data_path = environ['PITHCAT_INPUT_DATA'] if not options.data else \ |
125 |
options.data |
126 |
|
127 |
if options.db is None and 'PITHCAT_INPUT_DB' not in environ and \ |
128 |
type(url) is LocationURL: |
129 |
stderr.write( |
130 |
"Pithos database uri is missing.\n" |
131 |
"Use the PITHCAT_INPUT_DB environmental variable (recommended) " |
132 |
"or the --db command line option to define it.\n") |
133 |
exit(1) |
134 |
|
135 |
db_uri = environ['PITHCAT_INPUT_DB'] if not options.db else options.db |
136 |
|
137 |
backend = ModularBackend(None, |
138 |
db_uri if type(url) is LocationURL else None, |
139 |
None, |
140 |
data_path) |
141 |
|
142 |
if options.size: |
143 |
print_size(backend, url) |
144 |
else: |
145 |
print_data(backend, url) |
146 |
|
147 |
if __name__ == '__main__': |
148 |
main() |
149 |
|
150 |
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai : |