Statistics
| Branch: | Tag: | Revision:

root / snf-image-host / pithcat @ 29c0b1d1

History | View | Annotate | Download (5.3 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
        size = int(url.size)
96
        try:
97
            hashmap = [hexlify(x)
98
                       for x in backend.store.map_get(unhexlify(url.hash))]
99
        except TypeError:
100
            fullhash = "archip:%s" % url.hash
101
            hashmap = backend.store.map_get_archipelago(fullhash, size)
102
    else:
103
        raise Exception("Invalid URL")
104

    
105
    for hash in hashmap:
106
        block = backend.get_block(hash)
107
        if len(block) > size:
108
            block = block[:size]
109
        stdout.write(block)
110
        size -= len(block)
111

    
112

    
113
def main():
114
    options, args = parser.parse_args()
115
    if len(args) != 1:
116
        parser.print_help()
117
        exit(1)
118

    
119
    url = parse_url(args[0])
120

    
121
    if not options.data and 'PITHCAT_INPUT_DATA' not in environ:
122
        stderr.write(
123
            "Pithos data directory path is missing.\n"
124
            "Use the PITHCAT_INPUT_DATA environmental variable (recommended) "
125
            "or the --data command line option to define it.\n")
126
        exit(1)
127

    
128
    data_path = environ['PITHCAT_INPUT_DATA'] if not options.data else \
129
        options.data
130

    
131
    if options.db is None and 'PITHCAT_INPUT_DB' not in environ and \
132
            type(url) is LocationURL:
133
        stderr.write(
134
            "Pithos database uri is missing.\n"
135
            "Use the PITHCAT_INPUT_DB environmental variable (recommended) "
136
            "or the --db command line option to define it.\n")
137
        exit(1)
138

    
139
    db_uri = environ['PITHCAT_INPUT_DB'] if not options.db else options.db
140

    
141
    backend = ModularBackend(None,
142
                             db_uri if type(url) is LocationURL else None,
143
                             None,
144
                             data_path)
145

    
146
    try:
147
        if options.size:
148
            print_size(backend, url)
149
        else:
150
            print_data(backend, url)
151
    finally:
152
        xseg_ctx = backend.store.mapper.archip_map.ioctx_pool.pool_get()
153
        xseg_ctx.shutdown()
154

    
155
if __name__ == '__main__':
156
    main()
157

    
158
# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :