summaryrefslogtreecommitdiff
path: root/morphlib/remoteartifactcache.py
blob: f5115cd6409077b6470348f3100a18a544858985 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# Copyright (C) 2012-2015  Codethink Limited
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program.  If not, see <http://www.gnu.org/licenses/>.


import cliapp
import logging
import urllib
import urllib2
import urlparse


class HeadRequest(urllib2.Request):  # pragma: no cover

    def get_method(self):
        return 'HEAD'


class GetError(cliapp.AppException):

    def __init__(self, cache, artifact):
        cliapp.AppException.__init__(
            self, 'Failed to get the artifact %s '
                  'from the artifact cache %s' %
                  (artifact.basename(), cache))


class GetArtifactMetadataError(GetError):

    def __init__(self, cache, artifact, name):
        cliapp.AppException.__init__(
            self, 'Failed to get metadata %s for the artifact %s '
                  'from the artifact cache %s' %
                  (name, artifact.basename(), cache))


class GetSourceMetadataError(GetError):

    def __init__(self, cache, source, cache_key, name):
        cliapp.AppException.__init__(
            self, 'Failed to get metadata %s for source %s '
                  'and cache key %s from the artifact cache %s' %
                  (name, source, cache_key, cache))


class RemoteArtifactCache(object):

    def __init__(self, server_url):
        self.server_url = server_url
        self.name = urlparse.urlparse(server_url).hostname
        try:
            self.method = self._get_method()
        except urllib2.URLError:
            self.method = 'tarball'
        except Exception as e: # pragma: no cover
            logging.debug('Failed to determine cache method: %s' % e)
            raise cliapp.AppException('Failed to determine method used by '
                                      'remote cache.')
        if self.method == 'ostree': # pragma: no cover
            self.ostree_url = 'http://%s:%s/' % (self.name,
                                                 self._get_ostree_info())

    def has(self, artifact):
        return self._has_file(artifact.basename())

    def has_artifact_metadata(self, artifact, name):
        return self._has_file(artifact.metadata_basename(name))

    def has_source_metadata(self, source, cachekey, name):
        filename = '%s.%s' % (cachekey, name)
        return self._has_file(filename)

    def get(self, artifact, log=logging.error):
        try:
            return self._get_file(artifact.basename())
        except urllib2.URLError as e:
            log(str(e))
            raise GetError(self, artifact)

    def get_artifact_metadata(self, artifact, name, log=logging.error):
        try:
            return self._get_file(artifact.metadata_basename(name))
        except urllib2.URLError as e:
            log(str(e))
            raise GetArtifactMetadataError(self, artifact, name)

    def get_source_metadata(self, source, cachekey, name):
        filename = '%s.%s' % (cachekey, name)
        try:
            return self._get_file(filename)
        except urllib2.URLError:
            raise GetSourceMetadataError(self, source, cachekey, name)

    def _has_file(self, filename):  # pragma: no cover
        url = self._request_url(filename)
        logging.debug('RemoteArtifactCache._has_file: url=%s' % url)
        request = HeadRequest(url)
        try:
            urllib2.urlopen(request)
            return True
        except (urllib2.HTTPError, urllib2.URLError):
            return False

    def _get_file(self, filename):  # pragma: no cover
        url = self._request_url(filename)
        logging.debug('RemoteArtifactCache._get_file: url=%s' % url)
        return urllib2.urlopen(url)

    def _request_url(self, filename):  # pragma: no cover
        server_url = self.server_url
        if not server_url.endswith('/'):
            server_url += '/'
        return urlparse.urljoin(
            server_url, '/1.0/artifacts?filename=%s' % 
            urllib.quote(filename))

    def _get_method(self): # pragma: no cover
        logging.debug('Getting cache method of %s' % self.server_url)
        request_url = urlparse.urljoin(self.server_url, '/1.0/method')
        req = urllib2.urlopen(request_url)
        return req.read()

    def _get_ostree_info(self): # pragma: no cover
        logging.debug('Getting OSTree repo info.')
        request_url = urlparse.urljoin(self.server_url, '/1.0/ostreeinfo')
        logging.debug('sending %s' % request_url)
        req = urllib2.urlopen(request_url)
        return req.read()

    def __str__(self):  # pragma: no cover
        return self.server_url