Merge lp:~jkrauss/duplicity/pyrax into lp:duplicity/0.6

Proposed by Kenneth Loafman
Status: Merged
Merged at revision: 938
Proposed branch: lp:~jkrauss/duplicity/pyrax
Merge into: lp:duplicity/0.6
Diff against target: 251 lines (+214/-4)
2 files modified
bin/duplicity.1 (+20/-4)
duplicity/backends/pyraxbackend.py (+194/-0)
To merge this branch: bzr merge lp:~jkrauss/duplicity/pyrax
Reviewer Review Type Date Requested Status
duplicity-team Pending
Review via email: mp+196418@code.launchpad.net

Description of the change

Rackspace has deprecated python-cloudfiles in favor of their pyrax
library, which consolidates all Rackspace Cloud API functionality into
a single library. Attached is a simple backend for pyrax, ported over
from cloudfiles. I tested it with Duplicity 0.6.21 on both Arch Linux
and FreeBSD 8.3.0.

To post a comment you must log in.
Revision history for this message
edso (ed.so) wrote :

we should probably integrate it similar to the ssh backends with a command line switch. this way it'll become clear that

- the backends are for the same protocol/service
- one is deprecated but still selectable for legacy compatibility
- old users will be switched to the new backend automatically at some point

..ede

Revision history for this message
Kenneth Loafman (kenneth-loafman) wrote :

There really is no legacy issue here. I'm thinking of just deprecating the
cloudfiles backend later, leaving it in for a couple of releases, but
removing it fairly soon. If folks have trouble using the old cloudfiles
backend, they can switch sooner.

On Sun, Nov 24, 2013 at 6:41 AM, edso <email address hidden> wrote:

> we should probably integrate it similar to the ssh backends with a command
> line switch. this way it'll become clear that
>
> - the backends are for the same protocol/service
> - one is deprecated but still selectable for legacy compatibility
> - old users will be switched to the new backend automatically at some point
>
> ..ede
>
> --
> https://code.launchpad.net/~jkrauss/duplicity/pyrax/+merge/196418
> You proposed lp:~jkrauss/duplicity/pyrax for merging.
>

Revision history for this message
edso (ed.so) wrote :

i remember you saying somthig similar when introducing the new ssh backend ;) .. ede

On 24.11.2013 15:39, Kenneth Loafman wrote:
> There really is no legacy issue here. I'm thinking of just deprecating the
> cloudfiles backend later, leaving it in for a couple of releases, but
> removing it fairly soon. If folks have trouble using the old cloudfiles
> backend, they can switch sooner.
>
>
>
> On Sun, Nov 24, 2013 at 6:41 AM, edso <email address hidden> wrote:
>
>> we should probably integrate it similar to the ssh backends with a command
>> line switch. this way it'll become clear that
>>
>> - the backends are for the same protocol/service
>> - one is deprecated but still selectable for legacy compatibility
>> - old users will be switched to the new backend automatically at some point
>>
>> ..ede
>>
>> --
>> https://code.launchpad.net/~jkrauss/duplicity/pyrax/+merge/196418
>> You proposed lp:~jkrauss/duplicity/pyrax for merging.
>>
>

Revision history for this message
Kenneth Loafman (kenneth-loafman) wrote :

With the ssh backend we had two backends registering the same protocols.
 In this case the protocols are different (cf+http and cfpyrax+http). We
could have done the same for ssh, i.e. leave the original as 'ssh' and the
new one as 'sshparamiko'. That would be less complexity than the solution
we have (no option needed).

On Sun, Nov 24, 2013 at 8:51 AM, edso <email address hidden> wrote:

> i remember you saying somthig similar when introducing the new ssh backend
> ;) .. ede
>
> On 24.11.2013 15:39, Kenneth Loafman wrote:
> > There really is no legacy issue here. I'm thinking of just deprecating
> the
> > cloudfiles backend later, leaving it in for a couple of releases, but
> > removing it fairly soon. If folks have trouble using the old cloudfiles
> > backend, they can switch sooner.
> >
> >
> >
> > On Sun, Nov 24, 2013 at 6:41 AM, edso <email address hidden> wrote:
> >
> >> we should probably integrate it similar to the ssh backends with a
> command
> >> line switch. this way it'll become clear that
> >>
> >> - the backends are for the same protocol/service
> >> - one is deprecated but still selectable for legacy compatibility
> >> - old users will be switched to the new backend automatically at some
> point
> >>
> >> ..ede
> >>
> >> --
> >> https://code.launchpad.net/~jkrauss/duplicity/pyrax/+merge/196418
> >> You proposed lp:~jkrauss/duplicity/pyrax for merging.
> >>
> >
>
> --
> https://code.launchpad.net/~jkrauss/duplicity/pyrax/+merge/196418
> You proposed lp:~jkrauss/duplicity/pyrax for merging.
>

Revision history for this message
edso (ed.so) wrote :

i' argue it's till the same protocol 'cloudfiles stack'.. or did they change their API's as well?

i see why you think it's easier this way, having an option is just more elegant. users would use the new backend automatically, when we'd switch the default in the future.

your call.. just my 2 cents.. ede

On 24.11.2013 16:30, Kenneth Loafman wrote:
> With the ssh backend we had two backends registering the same protocols.
> In this case the protocols are different (cf+http and cfpyrax+http). We
> could have done the same for ssh, i.e. leave the original as 'ssh' and the
> new one as 'sshparamiko'. That would be less complexity than the solution
> we have (no option needed).
>
>
>
>
> On Sun, Nov 24, 2013 at 8:51 AM, edso <email address hidden> wrote:
>
>> i remember you saying somthig similar when introducing the new ssh backend
>> ;) .. ede
>>
>> On 24.11.2013 15:39, Kenneth Loafman wrote:
>>> There really is no legacy issue here. I'm thinking of just deprecating
>> the
>>> cloudfiles backend later, leaving it in for a couple of releases, but
>>> removing it fairly soon. If folks have trouble using the old cloudfiles
>>> backend, they can switch sooner.
>>>
>>>
>>>
>>> On Sun, Nov 24, 2013 at 6:41 AM, edso <email address hidden> wrote:
>>>
>>>> we should probably integrate it similar to the ssh backends with a
>> command
>>>> line switch. this way it'll become clear that
>>>>
>>>> - the backends are for the same protocol/service
>>>> - one is deprecated but still selectable for legacy compatibility
>>>> - old users will be switched to the new backend automatically at some
>> point
>>>>
>>>> ..ede
>>>>
>>>> --
>>>> https://code.launchpad.net/~jkrauss/duplicity/pyrax/+merge/196418
>>>> You proposed lp:~jkrauss/duplicity/pyrax for merging.
>>>>
>>>
>>
>> --
>> https://code.launchpad.net/~jkrauss/duplicity/pyrax/+merge/196418
>> You proposed lp:~jkrauss/duplicity/pyrax for merging.
>>
>

Revision history for this message
Kenneth Loafman (kenneth-loafman) wrote :

OK. For consistency I'll make the change. Really not a problem.

On Sun, Nov 24, 2013 at 9:36 AM, edso <email address hidden> wrote:

> i' argue it's till the same protocol 'cloudfiles stack'.. or did they
> change their API's as well?
>
> i see why you think it's easier this way, having an option is just more
> elegant. users would use the new backend automatically, when we'd switch
> the default in the future.
>
> your call.. just my 2 cents.. ede
>
> On 24.11.2013 16:30, Kenneth Loafman wrote:
> > With the ssh backend we had two backends registering the same protocols.
> > In this case the protocols are different (cf+http and cfpyrax+http). We
> > could have done the same for ssh, i.e. leave the original as 'ssh' and
> the
> > new one as 'sshparamiko'. That would be less complexity than the
> solution
> > we have (no option needed).
> >
> >
> >
> >
> > On Sun, Nov 24, 2013 at 8:51 AM, edso <email address hidden> wrote:
> >
> >> i remember you saying somthig similar when introducing the new ssh
> backend
> >> ;) .. ede
> >>
> >> On 24.11.2013 15:39, Kenneth Loafman wrote:
> >>> There really is no legacy issue here. I'm thinking of just deprecating
> >> the
> >>> cloudfiles backend later, leaving it in for a couple of releases, but
> >>> removing it fairly soon. If folks have trouble using the old
> cloudfiles
> >>> backend, they can switch sooner.
> >>>
> >>>
> >>>
> >>> On Sun, Nov 24, 2013 at 6:41 AM, edso <email address hidden> wrote:
> >>>
> >>>> we should probably integrate it similar to the ssh backends with a
> >> command
> >>>> line switch. this way it'll become clear that
> >>>>
> >>>> - the backends are for the same protocol/service
> >>>> - one is deprecated but still selectable for legacy compatibility
> >>>> - old users will be switched to the new backend automatically at some
> >> point
> >>>>
> >>>> ..ede
> >>>>
> >>>> --
> >>>> https://code.launchpad.net/~jkrauss/duplicity/pyrax/+merge/196418
> >>>> You proposed lp:~jkrauss/duplicity/pyrax for merging.
> >>>>
> >>>
> >>
> >> --
> >> https://code.launchpad.net/~jkrauss/duplicity/pyrax/+merge/196418
> >> You proposed lp:~jkrauss/duplicity/pyrax for merging.
> >>
> >
>
> --
> https://code.launchpad.net/~jkrauss/duplicity/pyrax/+merge/196418
> You proposed lp:~jkrauss/duplicity/pyrax for merging.
>

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/duplicity.1'
2--- bin/duplicity.1 2013-08-18 14:12:02 +0000
3+++ bin/duplicity.1 2013-11-23 11:28:28 +0000
4@@ -60,10 +60,14 @@
5 .B boto version 2.0+
6 - http://github.com/boto/boto
7 .TP
8-.BR "cloudfiles backend" " (e.g. Rackspace Open Cloud)"
9-.B Cloud Files Python API
10+.BR "cloudfiles backend (deprecated)" " (e.g. Rackspace Open Cloud)"
11+.B Cloud Files Python API (deprecated)
12 - http://www.rackspace.com/knowledge_center/article/python-api-installation-for-cloud-files
13 .TP
14+.BR "cfpyrax backend" " (Rackspace Cloud)"
15+.B Rackspace CloudFiles Pyrax API
16+- http://docs.rackspace.com/sdks/guide/content/python.html
17+.TP
18 .B "dpbx backend" (Dropbox)
19 .B Dropbox Python SDK
20 - https://www.dropbox.com/developers/reference/sdk
21@@ -982,8 +986,12 @@
22 Formats of each of the URL schemes follow:
23 .RS
24 .PP
25+.BI "Rackspace Cloud Files"
26+.br
27 cf+http://container_name
28 .br
29+cfpyrax+http://container_name
30+.br
31 See also
32 .B "A NOTE ON CLOUD FILES ACCESS"
33 .PP
34@@ -1349,8 +1357,16 @@
35 if /home/ben/1234567 existed.
36
37 .SH A NOTE ON CLOUD FILES ACCESS
38-Cloudfiles is Rackspace's implementation of OpenStack Object Storage
39-protocol.
40+Pyrax is Rackspace's next-generation Cloud management API, including
41+Cloud Files access. The cfpyrax backend requires the pyrax library to
42+be installed on the system.
43+See
44+.B REQUIREMENTS
45+above.
46+
47+Cloudfiles is Rackspace's now deprecated implementation of OpenStack
48+Object Storage protocol. Users wishing to use Duplicity with Rackspace
49+Cloud Files should migrate to the new Pyrax plugin to ensure support.
50
51 The backend requires python-cloudfiles to be installed on the system.
52 See
53
54=== added file 'duplicity/backends/pyraxbackend.py'
55--- duplicity/backends/pyraxbackend.py 1970-01-01 00:00:00 +0000
56+++ duplicity/backends/pyraxbackend.py 2013-11-23 11:28:28 +0000
57@@ -0,0 +1,194 @@
58+# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
59+#
60+# Copyright 2013 J.P. Krauss <jkrauss@asymworks.com>
61+#
62+# This file is part of duplicity.
63+#
64+# Duplicity is free software; you can redistribute it and/or modify it
65+# under the terms of the GNU General Public License as published by the
66+# Free Software Foundation; either version 2 of the License, or (at your
67+# option) any later version.
68+#
69+# Duplicity is distributed in the hope that it will be useful, but
70+# WITHOUT ANY WARRANTY; without even the implied warranty of
71+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
72+# General Public License for more details.
73+#
74+# You should have received a copy of the GNU General Public License
75+# along with duplicity; if not, write to the Free Software Foundation,
76+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
77+
78+import os
79+import time
80+
81+import duplicity.backend
82+from duplicity import globals
83+from duplicity import log
84+from duplicity.errors import * #@UnusedWildImport
85+from duplicity.util import exception_traceback
86+from duplicity.backend import retry
87+
88+class PyraxBackend(duplicity.backend.Backend):
89+ """
90+ Backend for Rackspace's CloudFiles using Pyrax
91+ """
92+ def __init__(self, parsed_url):
93+ try:
94+ import pyrax
95+ except ImportError:
96+ raise BackendException("This backend requires the pyrax "
97+ "library available from Rackspace.")
98+
99+ # Inform Pyrax that we're talking to Rackspace
100+ # per Jesus Monzon (gsusmonzon)
101+ pyrax.set_setting("identity_type", "rackspace")
102+
103+ conn_kwargs = {}
104+
105+ if not os.environ.has_key('CLOUDFILES_USERNAME'):
106+ raise BackendException('CLOUDFILES_USERNAME environment variable'
107+ 'not set.')
108+
109+ if not os.environ.has_key('CLOUDFILES_APIKEY'):
110+ raise BackendException('CLOUDFILES_APIKEY environment variable not set.')
111+
112+ conn_kwargs['username'] = os.environ['CLOUDFILES_USERNAME']
113+ conn_kwargs['api_key'] = os.environ['CLOUDFILES_APIKEY']
114+
115+ if os.environ.has_key('CLOUDFILES_REGION'):
116+ conn_kwargs['region'] = os.environ['CLOUDFILES_REGION']
117+
118+ container = parsed_url.path.lstrip('/')
119+
120+ try:
121+ pyrax.set_credentials(**conn_kwargs)
122+ except Exception, e:
123+ log.FatalError("Connection failed, please check your credentials: %s %s"
124+ % (e.__class__.__name__, str(e)),
125+ log.ErrorCode.connection_failed)
126+
127+ self.client_exc = pyrax.exceptions.ClientException
128+ self.nso_exc = pyrax.exceptions.NoSuchObject
129+ self.cloudfiles = pyrax.cloudfiles
130+ self.container = pyrax.cloudfiles.create_container(container)
131+
132+ def put(self, source_path, remote_filename = None):
133+ if not remote_filename:
134+ remote_filename = source_path.get_filename()
135+
136+ for n in range(1, globals.num_retries+1):
137+ log.Info("Uploading '%s/%s' " % (self.container, remote_filename))
138+ try:
139+ self.container.upload_file(source_path.name, remote_filename)
140+ return
141+ except self.client_exc, error:
142+ log.Warn("Upload of '%s' failed (attempt %d): pyrax returned: %s %s"
143+ % (remote_filename, n, error.__class__.__name__, error.message))
144+ except Exception, e:
145+ log.Warn("Upload of '%s' failed (attempt %s): %s: %s"
146+ % (remote_filename, n, e.__class__.__name__, str(e)))
147+ log.Debug("Backtrace of previous error: %s"
148+ % exception_traceback())
149+ time.sleep(30)
150+ log.Warn("Giving up uploading '%s' after %s attempts"
151+ % (remote_filename, globals.num_retries))
152+ raise BackendException("Error uploading '%s'" % remote_filename)
153+
154+ def get(self, remote_filename, local_path):
155+ for n in range(1, globals.num_retries+1):
156+ log.Info("Downloading '%s/%s'" % (self.container, remote_filename))
157+ try:
158+ sobject = self.container.get_object(remote_filename)
159+ f = open(local_path.name, 'w')
160+ f.write(sobject.get())
161+ local_path.setdata()
162+ return
163+ except self.nso_exc:
164+ return
165+ except self.client_exc, resperr:
166+ log.Warn("Download of '%s' failed (attempt %s): pyrax returned: %s %s"
167+ % (remote_filename, n, resperr.__class__.__name__, resperr.message))
168+ except Exception, e:
169+ log.Warn("Download of '%s' failed (attempt %s): %s: %s"
170+ % (remote_filename, n, e.__class__.__name__, str(e)))
171+ log.Debug("Backtrace of previous error: %s"
172+ % exception_traceback())
173+ time.sleep(30)
174+ log.Warn("Giving up downloading '%s' after %s attempts"
175+ % (remote_filename, globals.num_retries))
176+ raise BackendException("Error downloading '%s/%s'"
177+ % (self.container, remote_filename))
178+
179+ def list(self):
180+ for n in range(1, globals.num_retries+1):
181+ log.Info("Listing '%s'" % (self.container))
182+ try:
183+ # Cloud Files will return a max of 10,000 objects. We have
184+ # to make multiple requests to get them all.
185+ objs = self.container.get_object_names()
186+ keys = objs
187+ while len(objs) == 10000:
188+ objs = self.container.get_object_names(marker=keys[-1])
189+ keys += objs
190+ return keys
191+ except self.client_exc, resperr:
192+ log.Warn("Listing of '%s' failed (attempt %s): pyrax returned: %s %s"
193+ % (self.container, n, resperr.__class__.__name__, resperr.message))
194+ except Exception, e:
195+ log.Warn("Listing of '%s' failed (attempt %s): %s: %s"
196+ % (self.container, n, e.__class__.__name__, str(e)))
197+ log.Debug("Backtrace of previous error: %s"
198+ % exception_traceback())
199+ time.sleep(30)
200+ log.Warn("Giving up listing of '%s' after %s attempts"
201+ % (self.container, globals.num_retries))
202+ raise BackendException("Error listing '%s'"
203+ % (self.container))
204+
205+ def delete_one(self, remote_filename):
206+ for n in range(1, globals.num_retries+1):
207+ log.Info("Deleting '%s/%s'" % (self.container, remote_filename))
208+ try:
209+ self.container.delete_object(remote_filename)
210+ return
211+ except self.client_exc, resperr:
212+ if n > 1 and resperr.status == 404:
213+ # We failed on a timeout, but delete succeeded on the server
214+ log.Warn("Delete of '%s' missing after retry - must have succeded earler" % remote_filename )
215+ return
216+ log.Warn("Delete of '%s' failed (attempt %s): pyrax returned: %s %s"
217+ % (remote_filename, n, resperr.__class__.__name__, resperr.message))
218+ except Exception, e:
219+ log.Warn("Delete of '%s' failed (attempt %s): %s: %s"
220+ % (remote_filename, n, e.__class__.__name__, str(e)))
221+ log.Debug("Backtrace of previous error: %s"
222+ % exception_traceback())
223+ time.sleep(30)
224+ log.Warn("Giving up deleting '%s' after %s attempts"
225+ % (remote_filename, globals.num_retries))
226+ raise BackendException("Error deleting '%s/%s'"
227+ % (self.container, remote_filename))
228+
229+ def delete(self, filename_list):
230+ for file_ in filename_list:
231+ self.delete_one(file_)
232+ log.Debug("Deleted '%s/%s'" % (self.container, file_))
233+
234+ @retry
235+ def _query_file_info(self, filename, raise_errors=False):
236+ try:
237+ sobject = self.container.get_object(filename)
238+ return {'size': sobject.total_bytes}
239+ except self.nso_exc:
240+ return {'size': -1}
241+ except Exception, e:
242+ log.Warn("Error querying '%s/%s': %s"
243+ "" % (self.container,
244+ filename,
245+ str(e)))
246+ if raise_errors:
247+ raise e
248+ else:
249+ return {'size': None}
250+
251+duplicity.backend.register_backend("cfpyrax+http", PyraxBackend)

Subscribers

People subscribed via source and target branches