Statistics
| Branch: | Tag: | Revision:

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 :