/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* * Copyright 2020-2021 Couchbase, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "bucket_create.hxx" #include "core/utils/join_strings.hxx" #include "core/utils/json.hxx" #include "core/utils/url_codec.hxx" #include "error_utils.hxx" #include namespace couchbase::core::operations::management { std::error_code bucket_create_request::encode_to(encoded_request_type& encoded, http_context& /* context */) const { encoded.method = "POST"; encoded.path = fmt::format("/pools/default/buckets"); encoded.headers["content-type"] = "application/x-www-form-urlencoded"; encoded.body.append(fmt::format("name={}", utils::string_codec::form_encode(bucket.name))); switch (bucket.bucket_type) { case couchbase::core::management::cluster::bucket_type::couchbase: encoded.body.append("&bucketType=couchbase"); break; case couchbase::core::management::cluster::bucket_type::memcached: encoded.body.append("&bucketType=memcached"); break; case couchbase::core::management::cluster::bucket_type::ephemeral: encoded.body.append("&bucketType=ephemeral"); break; case couchbase::core::management::cluster::bucket_type::unknown: break; } if (bucket.ram_quota_mb == 0) { encoded.body.append(fmt::format("&ramQuotaMB={}", 100)); // If not explicitly set, set to prior default value of 100 } else { encoded.body.append(fmt::format("&ramQuotaMB={}", bucket.ram_quota_mb)); } if (bucket.bucket_type != couchbase::core::management::cluster::bucket_type::memcached && bucket.num_replicas.has_value()) { encoded.body.append(fmt::format("&replicaNumber={}", bucket.num_replicas.value())); } if (bucket.max_expiry.has_value()) { encoded.body.append(fmt::format("&maxTTL={}", bucket.max_expiry.value())); } if (bucket.bucket_type != couchbase::core::management::cluster::bucket_type::ephemeral && bucket.replica_indexes.has_value()) { encoded.body.append(fmt::format("&replicaIndex={}", bucket.replica_indexes.value() ? "1" : "0")); } if (bucket.history_retention_collection_default.has_value()) { encoded.body.append( fmt::format("&historyRetentionCollectionDefault={}", bucket.history_retention_collection_default.value() ? "true" : "false")); } if (bucket.history_retention_bytes.has_value()) { encoded.body.append(fmt::format("&historyRetentionBytes={}", bucket.history_retention_bytes.value())); } if (bucket.history_retention_duration.has_value()) { encoded.body.append(fmt::format("&historyRetentionSeconds={}", bucket.history_retention_duration.value())); } if (bucket.flush_enabled.has_value()) { encoded.body.append(fmt::format("&flushEnabled={}", bucket.flush_enabled.value() ? "1" : "0")); } switch (bucket.eviction_policy) { case couchbase::core::management::cluster::bucket_eviction_policy::full: encoded.body.append("&evictionPolicy=fullEviction"); break; case couchbase::core::management::cluster::bucket_eviction_policy::value_only: encoded.body.append("&evictionPolicy=valueOnly"); break; case couchbase::core::management::cluster::bucket_eviction_policy::no_eviction: encoded.body.append("&evictionPolicy=noEviction"); break; case couchbase::core::management::cluster::bucket_eviction_policy::not_recently_used: encoded.body.append("&evictionPolicy=nruEviction"); break; case couchbase::core::management::cluster::bucket_eviction_policy::unknown: break; } switch (bucket.compression_mode) { case couchbase::core::management::cluster::bucket_compression::off: encoded.body.append("&compressionMode=off"); break; case couchbase::core::management::cluster::bucket_compression::active: encoded.body.append("&compressionMode=active"); break; case couchbase::core::management::cluster::bucket_compression::passive: encoded.body.append("&compressionMode=passive"); break; case couchbase::core::management::cluster::bucket_compression::unknown: break; } switch (bucket.conflict_resolution_type) { case couchbase::core::management::cluster::bucket_conflict_resolution::timestamp: encoded.body.append("&conflictResolutionType=lww"); break; case couchbase::core::management::cluster::bucket_conflict_resolution::sequence_number: encoded.body.append("&conflictResolutionType=seqno"); break; case couchbase::core::management::cluster::bucket_conflict_resolution::custom: encoded.body.append("&conflictResolutionType=custom"); break; case couchbase::core::management::cluster::bucket_conflict_resolution::unknown: break; } if (bucket.minimum_durability_level.has_value()) { switch (bucket.minimum_durability_level.value()) { case durability_level::none: encoded.body.append("&durabilityMinLevel=none"); break; case durability_level::majority: encoded.body.append("&durabilityMinLevel=majority"); break; case durability_level::majority_and_persist_to_active: encoded.body.append("&durabilityMinLevel=majorityAndPersistActive"); break; case durability_level::persist_to_majority: encoded.body.append("&durabilityMinLevel=persistToMajority"); break; } } switch (bucket.storage_backend) { case couchbase::core::management::cluster::bucket_storage_backend::unknown: break; case couchbase::core::management::cluster::bucket_storage_backend::couchstore: encoded.body.append("&storageBackend=couchstore"); break; case couchbase::core::management::cluster::bucket_storage_backend::magma: encoded.body.append("&storageBackend=magma"); break; } return {}; } bucket_create_response bucket_create_request::make_response(error_context::http&& ctx, const encoded_response_type& encoded) const { bucket_create_response response{ std::move(ctx) }; if (!response.ctx.ec) { switch (encoded.status_code) { case 404: response.ctx.ec = errc::common::bucket_not_found; break; case 400: { tao::json::value payload{}; try { payload = utils::json::parse(encoded.body.data()); } catch (const tao::pegtl::parse_error&) { response.ctx.ec = errc::common::parsing_failure; return response; } response.ctx.ec = errc::common::invalid_argument; auto* errors = payload.find("errors"); if (errors != nullptr) { std::vector error_list{}; for (const auto& [code, message] : errors->get_object()) { if (message.get_string().find("Bucket with given name already exists") != std::string::npos) { response.ctx.ec = errc::management::bucket_exists; } error_list.emplace_back(message.get_string()); } if (!error_list.empty()) { response.error_message = utils::join_strings(error_list, ". "); } } } break; case 200: case 202: break; default: response.ctx.ec = extract_common_error_code(encoded.status_code, encoded.body.data()); break; } } return response; } } // namespace couchbase::core::operations::management