]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_lc_s3.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / rgw / rgw_lc_s3.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include <string.h>
5
6 #include <iostream>
7 #include <map>
8
9 #include "include/types.h"
10
11 #include "rgw_user.h"
12 #include "rgw_lc_s3.h"
13
14
15 #define dout_subsys ceph_subsys_rgw
16
17 static bool check_date(const string& _date)
18 {
19 boost::optional<ceph::real_time> date = ceph::from_iso_8601(_date);
20 if (boost::none == date) {
21 return false;
22 }
23 struct timespec time = ceph::real_clock::to_timespec(*date);
24 if (time.tv_sec % (24*60*60) || time.tv_nsec) {
25 return false;
26 }
27 return true;
28 }
29
30 void LCExpiration_S3::dump_xml(Formatter *f) const {
31 if (dm_expiration) {
32 encode_xml("ExpiredObjectDeleteMarker", "true", f);
33 } else if (!days.empty()) {
34 encode_xml("Days", days, f);
35 } else {
36 encode_xml("Date", date, f);
37 }
38 }
39
40 void LCExpiration_S3::decode_xml(XMLObj *obj)
41 {
42 bool has_days = RGWXMLDecoder::decode_xml("Days", days, obj);
43 bool has_date = RGWXMLDecoder::decode_xml("Date", date, obj);
44 string dm;
45 bool has_dm = RGWXMLDecoder::decode_xml("ExpiredObjectDeleteMarker", dm, obj);
46
47 int num = !!has_days + !!has_date + !!has_dm;
48
49 if (num != 1) {
50 throw RGWXMLDecoder::err("bad Expiration section");
51 }
52
53 if (has_date && !check_date(date)) {
54 //We need return xml error according to S3
55 throw RGWXMLDecoder::err("bad date in Date section");
56 }
57
58 if (has_dm) {
59 dm_expiration = (dm == "true");
60 }
61 }
62
63 void LCNoncurExpiration_S3::decode_xml(XMLObj *obj)
64 {
65 RGWXMLDecoder::decode_xml("NoncurrentDays", days, obj, true);
66 }
67
68 void LCNoncurExpiration_S3::dump_xml(Formatter *f) const
69 {
70 encode_xml("NoncurrentDays", days, f);
71 }
72
73 void LCMPExpiration_S3::decode_xml(XMLObj *obj)
74 {
75 RGWXMLDecoder::decode_xml("DaysAfterInitiation", days, obj, true);
76 }
77
78 void LCMPExpiration_S3::dump_xml(Formatter *f) const
79 {
80 encode_xml("DaysAfterInitiation", days, f);
81 }
82
83 void RGWLifecycleConfiguration_S3::decode_xml(XMLObj *obj)
84 {
85 if (!cct) {
86 throw RGWXMLDecoder::err("ERROR: RGWLifecycleConfiguration_S3 can't be decoded without cct initialized");
87 }
88 vector<LCRule_S3> rules;
89
90 RGWXMLDecoder::decode_xml("Rule", rules, obj, true);
91
92 for (auto& rule : rules) {
93 if (rule.get_id().empty()) {
94 string id;
95
96 // S3 generates a 48 bit random ID, maybe we could generate shorter IDs
97 static constexpr auto LC_ID_LENGTH = 48;
98
99 gen_rand_alphanumeric_lower(cct, &id, LC_ID_LENGTH);
100 rule.set_id(id);
101 }
102
103 add_rule(rule);
104 }
105
106 if (cct->_conf->rgw_lc_max_rules < rule_map.size()) {
107 stringstream ss;
108 ss << "Warn: The lifecycle config has too many rules, rule number is:"
109 << rule_map.size() << ", max number is:" << cct->_conf->rgw_lc_max_rules;
110 throw RGWXMLDecoder::err(ss.str());
111 }
112 }
113
114 void LCFilter_S3::dump_xml(Formatter *f) const
115 {
116 if (has_prefix()) {
117 encode_xml("Prefix", prefix, f);
118 }
119 bool multi = has_multi_condition();
120 if (multi) {
121 f->open_array_section("And");
122 }
123 if (has_tags()) {
124 const auto& tagset_s3 = static_cast<const RGWObjTagSet_S3 &>(obj_tags);
125 tagset_s3.dump_xml(f);
126 }
127 if (multi) {
128 f->close_section();
129 }
130 }
131
132 void LCFilter_S3::decode_xml(XMLObj *obj)
133 {
134 XMLObj *o = obj->find_first("And");
135 bool single_cond = false;
136 int num_conditions = 0;
137 // If there is an AND condition, every tag is a child of and
138 // else we only support single conditions and return false if we see multiple
139
140 if (o == nullptr){
141 o = obj;
142 single_cond = true;
143 }
144
145 RGWXMLDecoder::decode_xml("Prefix", prefix, o);
146 if (!prefix.empty())
147 num_conditions++;
148 auto tags_iter = o->find("Tag");
149 obj_tags.clear();
150 while (auto tag_xml =tags_iter.get_next()){
151 std::string _key,_val;
152 RGWXMLDecoder::decode_xml("Key", _key, tag_xml);
153 RGWXMLDecoder::decode_xml("Value", _val, tag_xml);
154 obj_tags.emplace_tag(std::move(_key), std::move(_val));
155 num_conditions++;
156 }
157
158 if (single_cond && num_conditions > 1) {
159 throw RGWXMLDecoder::err("Bad filter: badly formed multiple conditions");
160 }
161 }
162
163 void LCTransition_S3::decode_xml(XMLObj *obj)
164 {
165 bool has_days = RGWXMLDecoder::decode_xml("Days", days, obj);
166 bool has_date = RGWXMLDecoder::decode_xml("Date", date, obj);
167 if ((has_days && has_date) || (!has_days && !has_date)) {
168 throw RGWXMLDecoder::err("bad Transition section");
169 }
170
171 if (has_date && !check_date(date)) {
172 //We need return xml error according to S3
173 throw RGWXMLDecoder::err("bad Date in Transition section");
174 }
175
176 if (!RGWXMLDecoder::decode_xml("StorageClass", storage_class, obj)) {
177 throw RGWXMLDecoder::err("missing StorageClass in Transition section");
178 }
179 }
180
181 void LCTransition_S3::dump_xml(Formatter *f) const {
182 if (!days.empty()) {
183 encode_xml("Days", days, f);
184 } else {
185 encode_xml("Date", date, f);
186 }
187 encode_xml("StorageClass", storage_class, f);
188 }
189
190 void LCNoncurTransition_S3::decode_xml(XMLObj *obj)
191 {
192 if (!RGWXMLDecoder::decode_xml("NoncurrentDays", days, obj)) {
193 throw RGWXMLDecoder::err("missing NoncurrentDays in NoncurrentVersionTransition section");
194 }
195 if (!RGWXMLDecoder::decode_xml("StorageClass", storage_class, obj)) {
196 throw RGWXMLDecoder::err("missing StorageClass in NoncurrentVersionTransition section");
197 }
198 }
199
200 void LCNoncurTransition_S3::dump_xml(Formatter *f) const
201 {
202 encode_xml("NoncurrentDays", days, f);
203 encode_xml("StorageClass", storage_class, f);
204 }
205
206 void LCRule_S3::decode_xml(XMLObj *obj)
207 {
208 id.clear();
209 prefix.clear();
210 status.clear();
211 dm_expiration = false;
212
213 RGWXMLDecoder::decode_xml("ID", id, obj);
214
215 LCFilter_S3 filter_s3;
216 if (!RGWXMLDecoder::decode_xml("Filter", filter_s3, obj)) {
217 // Ideally the following code should be deprecated and we should return
218 // False here, The new S3 LC configuration xml spec. makes Filter mandatory
219 // and Prefix optional. However older clients including boto2 still generate
220 // xml according to the older spec, where Prefix existed outside of Filter
221 // and S3 itself seems to be sloppy on enforcing the mandatory Filter
222 // argument. A day will come when S3 enforces their own xml-spec, but it is
223 // not this day
224
225 if (!RGWXMLDecoder::decode_xml("Prefix", prefix, obj)) {
226 throw RGWXMLDecoder::err("missing Prefix in Filter");
227 }
228 }
229 filter = (LCFilter)filter_s3;
230
231 if (!RGWXMLDecoder::decode_xml("Status", status, obj)) {
232 throw RGWXMLDecoder::err("missing Status in Filter");
233 }
234 if (status.compare("Enabled") != 0 && status.compare("Disabled") != 0) {
235 throw RGWXMLDecoder::err("bad Status in Filter");
236 }
237
238 LCExpiration_S3 s3_expiration;
239 LCNoncurExpiration_S3 s3_noncur_expiration;
240 LCMPExpiration_S3 s3_mp_expiration;
241 LCFilter_S3 s3_filter;
242
243 bool has_expiration = RGWXMLDecoder::decode_xml("Expiration", s3_expiration, obj);
244 bool has_noncur_expiration = RGWXMLDecoder::decode_xml("NoncurrentVersionExpiration", s3_noncur_expiration, obj);
245 bool has_mp_expiration = RGWXMLDecoder::decode_xml("AbortIncompleteMultipartUpload", s3_mp_expiration, obj);
246
247 vector<LCTransition_S3> transitions;
248 vector<LCNoncurTransition_S3> noncur_transitions;
249
250 bool has_transition = RGWXMLDecoder::decode_xml("Transition", transitions, obj);
251 bool has_noncur_transition = RGWXMLDecoder::decode_xml("NoncurrentVersionTransition", noncur_transitions, obj);
252
253 if (!has_expiration &&
254 !has_noncur_expiration &&
255 !has_mp_expiration &&
256 !has_transition &&
257 !has_noncur_transition) {
258 throw RGWXMLDecoder::err("bad Rule");
259 }
260
261 if (has_expiration) {
262 if (s3_expiration.has_days() ||
263 s3_expiration.has_date()) {
264 expiration = s3_expiration;
265 } else {
266 dm_expiration = s3_expiration.get_dm_expiration();
267 }
268 }
269 if (has_noncur_expiration) {
270 noncur_expiration = s3_noncur_expiration;
271 }
272 if (has_mp_expiration) {
273 mp_expiration = s3_mp_expiration;
274 }
275 for (auto& t : transitions) {
276 if (!add_transition(t)) {
277 throw RGWXMLDecoder::err("Failed to add transition");
278 }
279 }
280 for (auto& t : noncur_transitions) {
281 if (!add_noncur_transition(t)) {
282 throw RGWXMLDecoder::err("Failed to add non-current version transition");
283 }
284 }
285 }
286
287 void LCRule_S3::dump_xml(Formatter *f) const {
288 encode_xml("ID", id, f);
289 // In case of an empty filter and an empty Prefix, we defer to Prefix.
290 if (!filter.empty()) {
291 const LCFilter_S3& lc_filter = static_cast<const LCFilter_S3&>(filter);
292 encode_xml("Filter", lc_filter, f);
293 } else {
294 encode_xml("Prefix", prefix, f);
295 }
296 encode_xml("Status", status, f);
297 if (!expiration.empty() || dm_expiration) {
298 LCExpiration_S3 expir(expiration.get_days_str(), expiration.get_date(), dm_expiration);
299 encode_xml("Expiration", expir, f);
300 }
301 if (!noncur_expiration.empty()) {
302 const LCNoncurExpiration_S3& noncur_expir = static_cast<const LCNoncurExpiration_S3&>(noncur_expiration);
303 encode_xml("NoncurrentVersionExpiration", noncur_expir, f);
304 }
305 if (!mp_expiration.empty()) {
306 const LCMPExpiration_S3& mp_expir = static_cast<const LCMPExpiration_S3&>(mp_expiration);
307 encode_xml("AbortIncompleteMultipartUpload", mp_expir, f);
308 }
309 if (!transitions.empty()) {
310 for (auto &elem : transitions) {
311 const LCTransition_S3& tran = static_cast<const LCTransition_S3&>(elem.second);
312 encode_xml("Transition", tran, f);
313 }
314 }
315 if (!noncur_transitions.empty()) {
316 for (auto &elem : noncur_transitions) {
317 const LCNoncurTransition_S3& noncur_tran = static_cast<const LCNoncurTransition_S3&>(elem.second);
318 encode_xml("NoncurrentVersionTransition", noncur_tran, f);
319 }
320 }
321 }
322
323 int RGWLifecycleConfiguration_S3::rebuild(RGWRados *store, RGWLifecycleConfiguration& dest)
324 {
325 int ret = 0;
326 multimap<string, LCRule>::iterator iter;
327 for (iter = rule_map.begin(); iter != rule_map.end(); ++iter) {
328 LCRule& src_rule = iter->second;
329 ret = dest.check_and_add_rule(src_rule);
330 if (ret < 0)
331 return ret;
332 }
333 if (!dest.valid()) {
334 ret = -ERR_INVALID_REQUEST;
335 }
336 return ret;
337 }
338
339
340 void RGWLifecycleConfiguration_S3::dump_xml(Formatter *f) const
341 {
342 for (auto iter = rule_map.begin(); iter != rule_map.end(); ++iter) {
343 const LCRule_S3& rule = static_cast<const LCRule_S3&>(iter->second);
344 encode_xml("Rule", rule, f);
345 }
346 }
347