Skip to content

Commit

Permalink
Add backend that supports container tokens
Browse files Browse the repository at this point in the history
To the moon!

initial commit
  • Loading branch information
thurloat committed Jan 9, 2015
1 parent bc8efbd commit a5aa8d3
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 13 deletions.
50 changes: 37 additions & 13 deletions README → README.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,42 @@
INSTALLATION:
# Notes

Thank you for trying duplicity. To install, run:
This is a fork of duplicity, which adds a `swiftkeys://` storage backend
that supports Swift Container Keys
(https://www.clouda.ca/blog/tech/dash/bulk-storage-container-api-keys/). For
more the original project information, check the announcement blog post
(https://www.clouda.ca/blog/general/using-bulk-storage-container-keys-with-duplicity/)

# Installation

python setup.py install
If you have not downloaded it yet, you can grab the latest stable version from
the repo archive page, and continue using the regular install steps below.

The build process can be also be run separately:
```
wget https://bitbucket.org/clouda/duplicity/get/321.tar.gz
tar -zxvf 321.tar.gz
cd duplicity-swiftkeys-xxx/
```

Thank you for trying duplicity. To install, run:

python setup.py build
```
pip install python-swiftclient lockfile
python setup.py install
```

The default prefix is /usr, so files are put in /usr/bin,
/usr/share/man/, etc. An alternate prefix can be specified using the
--prefix=<prefix> option. For example:
# Usage

python setup.py install --prefix=/usr/local
export PYTHONPATH='/usr/local/lib/python2.x/site-packages/'
/usr/local/bin/duplicity -V
```
export SWIFT_STORAGE_URL="https://<swift-endpoint>/v1/AUTH_<tenant_id>"
export SWIFT_CONTAINER_FULL_TOKEN="<full-XXXX-token>"
duplicity <backup_path> swiftkeys://<container_name>
```

You can get your tenant\_id filled bulk storage URL from the Dashboard under
API Access and listed as Object Store.

REQUIREMENTS:

# Requirements

* Python v2.6 or later
* librsync v0.9.6 or later
Expand Down Expand Up @@ -62,7 +81,7 @@ the class to gpginterface in the hope that package maintainers will stumble
over it and stop this problematic behaviour for good.


HELP:
# Help

For more information see the duplicity home page at:

Expand All @@ -71,3 +90,8 @@ For more information see the duplicity home page at:
or post to the mailing list at

http://mail.nongnu.org/mailman/listinfo/duplicity-talk/

If there is an issue with the storage backend, you can log a bug on the
project at

https://github.com/cloudbrewery/duplicity-swiftkeys/issues
96 changes: 96 additions & 0 deletions duplicity/backends/swiftkeysbackend.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Copyright 2015 (c) Cloud Brewery Inc.
#
# This file is part of duplicity.
#
# Duplicity 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; either version 2 of the License, or (at your
# option) any later version.
#
# Duplicity 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 duplicity; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

import os

import duplicity.backend
from duplicity import log
from duplicity.errors import BackendException

import swiftclient.client
from swiftclient.client import HTTPConnection as _HTTPConnection


class ContainerKeyHTTPConnection(_HTTPConnection):

def _request(self, *args, **kwargs):
kwargs['headers']['X-Container-Meta-Full-Key'] = \
os.environ['SWIFT_CONTAINER_FULL_TOKEN']
kwargs['headers'].pop('X-Auth-Token', None)
kwargs['headers'].pop('x-auth-token', None)
return _HTTPConnection._request(self, *args, **kwargs)


swiftclient.client.HTTPConnection = ContainerKeyHTTPConnection


class SwiftKeysBackend(duplicity.backend.Backend):
"""
A Backend for Swift using Container Keys
"""
def __init__(self, parsed_url):

from swiftclient import Connection, ClientException

self.resp_exc = ClientException
conn_kwargs = {}
if 'SWIFT_CONTAINER_FULL_TOKEN' not in os.environ:
raise BackendException('SWIFT_CONTAINER_FULL_TOKEN environment '
'variable not set.')
if 'SWIFT_STORAGE_URL' not in os.environ:
raise BackendException('SWIFT_STORAGE_URL environment variable '
'not set.')

self.container_full_token = os.environ['SWIFT_CONTAINER_FULL_TOKEN']
self.swift_storage_url = os.environ['SWIFT_STORAGE_URL']

conn_kwargs['preauthurl'] = self.swift_storage_url
conn_kwargs['preauthtoken'] = 'discarded'

self.container = parsed_url.path.lstrip('/')

self.conn = Connection(**conn_kwargs)

def _error_code(self, operation, e):
if isinstance(e, self.resp_exc):
if e.http_status == 404:
return log.ErrorCode.backend_not_found

def _put(self, source_path, remote_filename):
self.conn.put_object(self.container, remote_filename,
file(source_path.name))

def _get(self, remote_filename, local_path):
headers, body = self.conn.get_object(self.container, remote_filename)
with open(local_path.name, 'wb') as f:
for chunk in body:
f.write(chunk)

def _list(self):
headers, objs = self.conn.get_container(self.container)
return [o['name'] for o in objs]

def _delete(self, filename):
self.conn.delete_object(self.container, filename)

def _query(self, filename):
sobject = self.conn.head_object(self.container, filename)
return {'size': int(sobject['content-length'])}


duplicity.backend.register_backend("swiftkeys", SwiftKeysBackend)

0 comments on commit a5aa8d3

Please sign in to comment.