/**
* Copyright (C) 2016 MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects
* for all of the code used other than as permitted herein. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you do not
* wish to do so, delete this exception statement from your version. If you
* delete this exception statement from all source files in the program,
* then also delete it in the license file.
*/
#include "mongo/platform/basic.h"
#include "mongo/db/s/type_shard_identity.h"
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/bson/util/bson_extract.h"
#include "mongo/util/assert_util.h"
namespace mongo {
const std::string ShardIdentityType::IdName("shardIdentity");
const BSONField ShardIdentityType::configsvrConnString("configsvrConnectionString");
const BSONField ShardIdentityType::shardName("shardName");
const BSONField ShardIdentityType::clusterId("clusterId");
StatusWith ShardIdentityType::fromBSON(const BSONObj& source) {
if (!source.hasField("_id")) {
return {ErrorCodes::NoSuchKey,
str::stream() << "missing _id field for shardIdentity document"};
}
ShardIdentityType shardIdentity;
{
std::string docId;
Status status = bsonExtractStringField(source, "_id", &docId);
if (!status.isOK()) {
return status;
}
if (docId != IdName) {
return {ErrorCodes::FailedToParse,
str::stream() << "got _id: " << docId << " instead of " << IdName};
}
}
{
std::string connString;
Status status = bsonExtractStringField(source, configsvrConnString(), &connString);
if (!status.isOK()) {
return status;
}
try {
// Note: ConnectionString::parse can uassert from HostAndPort constructor.
auto parsedConfigConnStrStatus = ConnectionString::parse(connString);
if (!parsedConfigConnStrStatus.isOK()) {
return parsedConfigConnStrStatus.getStatus();
}
auto configSvrConnStr = parsedConfigConnStrStatus.getValue();
if (configSvrConnStr.type() != ConnectionString::SET) {
return Status(ErrorCodes::UnsupportedFormat,
str::stream()
<< "config server connection string can only be replica sets: "
<< configSvrConnStr.toString());
}
shardIdentity.setConfigsvrConnString(std::move(configSvrConnStr));
} catch (const UserException& parseException) {
return parseException.toStatus();
}
}
{
std::string name;
Status status = bsonExtractStringField(source, shardName(), &name);
if (!status.isOK()) {
return status;
}
shardIdentity.setShardName(name);
}
{
OID oid;
Status status = bsonExtractOIDField(source, clusterId(), &oid);
if (!status.isOK()) {
return status;
}
shardIdentity.setClusterId(oid);
}
return shardIdentity;
}
Status ShardIdentityType::validate() const {
if (!_configsvrConnString) {
return {ErrorCodes::NoSuchKey,
str::stream() << "missing " << configsvrConnString() << " field"};
}
if (_configsvrConnString->type() != ConnectionString::SET) {
return {ErrorCodes::UnsupportedFormat,
str::stream() << "config connection string can only be replica sets, got "
<< ConnectionString::typeToString(_configsvrConnString->type())};
}
if (!_shardName || _shardName->empty()) {
return {ErrorCodes::NoSuchKey, str::stream() << "missing " << shardName() << " field"};
}
if (!_clusterId || !_clusterId->isSet()) {
return {ErrorCodes::NoSuchKey, str::stream() << "missing " << clusterId() << " field"};
}
return Status::OK();
}
BSONObj ShardIdentityType::toBSON() const {
BSONObjBuilder builder;
builder.append("_id", IdName);
if (_configsvrConnString) {
builder << configsvrConnString(_configsvrConnString->toString());
}
if (_shardName) {
builder << shardName(_shardName.get());
}
if (_clusterId) {
builder << clusterId(_clusterId.get());
}
return builder.obj();
}
std::string ShardIdentityType::toString() const {
return toBSON().toString();
}
bool ShardIdentityType::isConfigsvrConnStringSet() const {
return _configsvrConnString.is_initialized();
}
const ConnectionString& ShardIdentityType::getConfigsvrConnString() const {
invariant(_configsvrConnString);
return _configsvrConnString.get();
}
void ShardIdentityType::setConfigsvrConnString(ConnectionString connString) {
_configsvrConnString = std::move(connString);
}
bool ShardIdentityType::isShardNameSet() const {
return _shardName.is_initialized();
}
const std::string& ShardIdentityType::getShardName() const {
invariant(_shardName);
return _shardName.get();
}
void ShardIdentityType::setShardName(std::string shardName) {
_shardName = std::move(shardName);
}
bool ShardIdentityType::isClusterIdSet() const {
return _clusterId.is_initialized();
}
const OID& ShardIdentityType::getClusterId() const {
invariant(_clusterId);
return _clusterId.get();
}
void ShardIdentityType::setClusterId(OID clusterId) {
_clusterId = std::move(clusterId);
}
BSONObj ShardIdentityType::createConfigServerUpdateObject(const std::string& newConnString) {
BSONObjBuilder builder;
BSONObjBuilder setConfigBuilder(builder.subobjStart("$set"));
setConfigBuilder.append(configsvrConnString(), newConnString);
setConfigBuilder.doneFast();
return builder.obj();
}
} // namespace mongo