Skip to content

Commit

Permalink
rgw: improve support for Swift's object versioning.
Browse files Browse the repository at this point in the history
This patch allows RadosGW to pass the RefStack with an accuracy
to the RFC7230 violation issue which is clearly a Tempest bug.

Fixes: http://tracker.ceph.com/issues/15925
Signed-off-by: Radoslaw Zarzynski <rzarzynski@mirantis.com>
(cherry picked from commit 237ad12)

Conflicts:
	src/rgw/rgw_op.cc
          In contrast to master, Jewel doesn't support
          container quota of Swift API. All tracks of this
          feature have been eradicated from the patch.
	src/rgw/rgw_rest_swift.cc
          Jewel doesn't include boost/optional.hpp but has
          boost/utility/in_place_factory.hpp. The conflict
          has been resolved to pull in both headers.
  • Loading branch information
rzarzynski committed Aug 16, 2016
1 parent ec14cf5 commit dbf8cf0
Show file tree
Hide file tree
Showing 8 changed files with 331 additions and 64 deletions.
14 changes: 14 additions & 0 deletions doc/radosgw/config-ref.rst
Expand Up @@ -778,6 +778,20 @@ Swift Settings
:Default: ``auth``


``rgw swift versioning enabled``

:Description: Enables the Object Versioning of OpenStack Object Storage API.
This allows clients to put the ``X-Versions-Location`` attribute
on containers that should be versioned. The attribute specifies
the name of container storing archived versions. It must be owned
by the same user that the versioned container due to access
control verification - ACLs are NOT taken into consideration.
Those containers cannot be versioned by the S3 object versioning
mechanism.
:Type: Boolean
:Default: ``false``



Logging Settings
================
Expand Down
2 changes: 1 addition & 1 deletion doc/radosgw/swift.rst
Expand Up @@ -67,7 +67,7 @@ The following table describes the support status for current Swift functional fe
+---------------------------------+-----------------+----------------------------------------+
| **Expiring Objects** | Supported | |
+---------------------------------+-----------------+----------------------------------------+
| **Object Versioning** | Not Supported | |
| **Object Versioning** | Supported | |
+---------------------------------+-----------------+----------------------------------------+
| **CORS** | Not Supported | |
+---------------------------------+-----------------+----------------------------------------+
Expand Down
7 changes: 5 additions & 2 deletions src/rgw/rgw_common.h
Expand Up @@ -992,11 +992,14 @@ struct RGWBucketInfo

void decode_json(JSONObj *obj);

bool versioned() { return (flags & BUCKET_VERSIONED) != 0; }
bool versioned() const { return (flags & BUCKET_VERSIONED) != 0; }
int versioning_status() { return flags & (BUCKET_VERSIONED | BUCKET_VERSIONS_SUSPENDED); }
bool versioning_enabled() { return versioning_status() == BUCKET_VERSIONED; }

bool has_swift_versioning() { return swift_versioning; }
bool has_swift_versioning() const {
/* A bucket may be versioned through one mechanism only. */
return swift_versioning && !versioned();
}

RGWBucketInfo() : flags(0), has_instance_obj(false), num_shards(0), bucket_index_shard_hash_type(MOD), requester_pays(false),
has_website(false), swift_versioning(false) {}
Expand Down
100 changes: 74 additions & 26 deletions src/rgw/rgw_op.cc
Expand Up @@ -2000,10 +2000,17 @@ void RGWCreateBucket::execute()

s->bucket.tenant = s->bucket_tenant; /* ignored if bucket exists */
s->bucket.name = s->bucket_name;

/* Handle updates of the metadata for Swift's object versioning. */
if (swift_ver_location) {
s->bucket_info.swift_ver_location = *swift_ver_location;
s->bucket_info.swift_versioning = (! swift_ver_location->empty());
}

op_ret = store->create_bucket(*(s->user), s->bucket, zonegroup_id,
placement_rule, swift_ver_location, attrs,
info, pobjv, &ep_objv, creation_time,
pmaster_bucket, true);
placement_rule, s->bucket_info.swift_ver_location,
attrs, info, pobjv, &ep_objv, creation_time,
pmaster_bucket, true);
/* continue if EEXIST and create_bucket will fail below. this way we can
* recover from a partial create by retrying it. */
ldout(s->cct, 20) << "rgw_create_bucket returned ret=" << op_ret << " bucket=" << s->bucket << dendl;
Expand Down Expand Up @@ -2071,6 +2078,12 @@ void RGWCreateBucket::execute()
prepare_add_del_attrs(s->bucket_attrs, rmattr_names, attrs);
populate_with_generic_attrs(s, attrs);

/* Handle updates of the metadata for Swift's object versioning. */
if (swift_ver_location) {
s->bucket_info.swift_ver_location = *swift_ver_location;
s->bucket_info.swift_versioning = (! swift_ver_location->empty());
}

op_ret = rgw_bucket_set_attrs(store, s->bucket_info, attrs,
&s->bucket_info.objv_tracker);
} while (op_ret == -ECANCELED && tries++ < 20);
Expand Down Expand Up @@ -2414,6 +2427,18 @@ void RGWPutObj::execute()

processor = select_processor(*static_cast<RGWObjectCtx *>(s->obj_ctx), &multipart);

/* Handle object versioning of Swift API. */
if (! multipart) {
rgw_obj obj(s->bucket, s->object);
op_ret = store->swift_versioning_copy(*static_cast<RGWObjectCtx *>(s->obj_ctx),
s->bucket_owner.get_id(),
s->bucket_info,
obj);
if (op_ret < 0) {
return;
}
}

op_ret = processor->prepare(store, NULL);
if (op_ret < 0) {
ldout(s->cct, 20) << "processor->prepare() returned ret=" << op_ret
Expand Down Expand Up @@ -2883,8 +2908,10 @@ void RGWPutMetadataBucket::execute()
prepare_add_del_attrs(s->bucket_attrs, rmattr_names, attrs);
populate_with_generic_attrs(s, attrs);

s->bucket_info.swift_ver_location = swift_ver_location;
s->bucket_info.swift_versioning = (!swift_ver_location.empty());
if (swift_ver_location) {
s->bucket_info.swift_ver_location = *swift_ver_location;
s->bucket_info.swift_versioning = (! swift_ver_location->empty());
}

op_ret = rgw_bucket_set_attrs(store, s->bucket_info, attrs,
&s->bucket_info.objv_tracker);
Expand Down Expand Up @@ -3056,35 +3083,46 @@ void RGWDeleteObj::execute()
}

RGWObjectCtx *obj_ctx = static_cast<RGWObjectCtx *>(s->obj_ctx);

obj_ctx->set_atomic(obj);

RGWRados::Object del_target(store, s->bucket_info, *obj_ctx, obj);
RGWRados::Object::Delete del_op(&del_target);

op_ret = get_system_versioning_params(s, &del_op.params.olh_epoch,
&del_op.params.marker_version_id);
bool ver_restored = false;
op_ret = store->swift_versioning_restore(*obj_ctx, s->bucket_owner.get_id(),
s->bucket_info, obj, ver_restored);
if (op_ret < 0) {
return;
}

del_op.params.bucket_owner = s->bucket_owner.get_id();
del_op.params.versioning_status = s->bucket_info.versioning_status();
del_op.params.obj_owner = s->owner;
del_op.params.unmod_since = unmod_since;
del_op.params.high_precision_time = s->system_request; /* system request uses high precision time */
if (!ver_restored) {
/* Swift's versioning mechanism hasn't found any previous version of
* the object that could be restored. This means we should proceed
* with the regular delete path. */
RGWRados::Object del_target(store, s->bucket_info, *obj_ctx, obj);
RGWRados::Object::Delete del_op(&del_target);

op_ret = del_op.delete_obj();
if (op_ret >= 0) {
delete_marker = del_op.result.delete_marker;
version_id = del_op.result.version_id;
}
op_ret = get_system_versioning_params(s, &del_op.params.olh_epoch,
&del_op.params.marker_version_id);
if (op_ret < 0) {
return;
}

/* Check whether the object has expired. Swift API documentation
* stands that we should return 404 Not Found in such case. */
if (need_object_expiration() && object_is_expired(attrs)) {
op_ret = -ENOENT;
return;
del_op.params.bucket_owner = s->bucket_owner.get_id();
del_op.params.versioning_status = s->bucket_info.versioning_status();
del_op.params.obj_owner = s->owner;
del_op.params.unmod_since = unmod_since;
del_op.params.high_precision_time = s->system_request; /* system request uses high precision time */

op_ret = del_op.delete_obj();
if (op_ret >= 0) {
delete_marker = del_op.result.delete_marker;
version_id = del_op.result.version_id;
}

/* Check whether the object has expired. Swift API documentation
* stands that we should return 404 Not Found in such case. */
if (need_object_expiration() && object_is_expired(attrs)) {
op_ret = -ENOENT;
return;
}
}

if (op_ret == -ERR_PRECONDITION_FAILED && no_precondition_error) {
Expand Down Expand Up @@ -3306,6 +3344,16 @@ void RGWCopyObj::execute()

bool high_precision_time = (s->system_request);

/* Handle object versioning of Swift API. In case of copying to remote this
* should fail gently (op_ret == 0) as the dst_obj will not exist here. */
op_ret = store->swift_versioning_copy(obj_ctx,
dest_bucket_info.owner,
dest_bucket_info,
dst_obj);
if (op_ret < 0) {
return;
}

op_ret = store->copy_obj(obj_ctx,
s->user->user_id,
client_id,
Expand Down
6 changes: 4 additions & 2 deletions src/rgw/rgw_op.h
Expand Up @@ -18,6 +18,8 @@
#include <set>
#include <map>

#include <boost/optional.hpp>

#include "common/armor.h"
#include "common/mime.h"
#include "common/utf8.h"
Expand Down Expand Up @@ -535,7 +537,7 @@ class RGWCreateBucket : public RGWOp {
obj_version ep_objv;
bool has_cors;
RGWCORSConfiguration cors_config;
string swift_ver_location;
boost::optional<std::string> swift_ver_location;
map<string, buffer::list> attrs;
set<string> rmattr_names;

Expand Down Expand Up @@ -781,7 +783,7 @@ class RGWPutMetadataBucket : public RGWOp {
RGWAccessControlPolicy policy;
RGWCORSConfiguration cors_config;
string placement_rule;
string swift_ver_location;
boost::optional<std::string> swift_ver_location;

public:
RGWPutMetadataBucket()
Expand Down

0 comments on commit dbf8cf0

Please sign in to comment.