1 
2 /**
3  *    Copyright (C) 2018-present MongoDB, Inc.
4  *
5  *    This program is free software: you can redistribute it and/or modify
6  *    it under the terms of the Server Side Public License, version 1,
7  *    as published by MongoDB, Inc.
8  *
9  *    This program is distributed in the hope that it will be useful,
10  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *    Server Side Public License for more details.
13  *
14  *    You should have received a copy of the Server Side Public License
15  *    along with this program. If not, see
16  *    <http://www.mongodb.com/licensing/server-side-public-license>.
17  *
18  *    As a special exception, the copyright holders give permission to link the
19  *    code of portions of this program with the OpenSSL library under certain
20  *    conditions as described in each individual source file and distribute
21  *    linked combinations including the program with the OpenSSL library. You
22  *    must comply with the Server Side Public License in all respects for
23  *    all of the code used other than as permitted herein. If you modify file(s)
24  *    with this exception, you may extend this exception to your version of the
25  *    file(s), but you are not obligated to do so. If you do not wish to do so,
26  *    delete this exception statement from your version. If you delete this
27  *    exception statement from all source files in the program, then also delete
28  *    it in the license file.
29  */
30 
31 #include "mongo/platform/basic.h"
32 
33 #include "mongo/db/s/type_shard_identity.h"
34 
35 #include "mongo/bson/bsonobjbuilder.h"
36 #include "mongo/bson/util/bson_extract.h"
37 #include "mongo/util/assert_util.h"
38 
39 namespace mongo {
40 
41 const std::string ShardIdentityType::IdName("shardIdentity");
42 
43 const BSONField<std::string> ShardIdentityType::configsvrConnString("configsvrConnectionString");
44 const BSONField<std::string> ShardIdentityType::shardName("shardName");
45 const BSONField<OID> ShardIdentityType::clusterId("clusterId");
46 
fromBSON(const BSONObj & source)47 StatusWith<ShardIdentityType> ShardIdentityType::fromBSON(const BSONObj& source) {
48     if (!source.hasField("_id")) {
49         return {ErrorCodes::NoSuchKey,
50                 str::stream() << "missing _id field for shardIdentity document"};
51     }
52 
53     ShardIdentityType shardIdentity;
54 
55     {
56         std::string docId;
57         Status status = bsonExtractStringField(source, "_id", &docId);
58         if (!status.isOK()) {
59             return status;
60         }
61 
62         if (docId != IdName) {
63             return {ErrorCodes::FailedToParse,
64                     str::stream() << "got _id: " << docId << " instead of " << IdName};
65         }
66     }
67 
68     {
69         std::string connString;
70         Status status = bsonExtractStringField(source, configsvrConnString(), &connString);
71         if (!status.isOK()) {
72             return status;
73         }
74 
75         try {
76             // Note: ConnectionString::parse can uassert from HostAndPort constructor.
77             auto parsedConfigConnStrStatus = ConnectionString::parse(connString);
78             if (!parsedConfigConnStrStatus.isOK()) {
79                 return parsedConfigConnStrStatus.getStatus();
80             }
81 
82             auto configSvrConnStr = parsedConfigConnStrStatus.getValue();
83             if (configSvrConnStr.type() != ConnectionString::SET) {
84                 return Status(ErrorCodes::UnsupportedFormat,
85                               str::stream()
86                                   << "config server connection string can only be replica sets: "
87                                   << configSvrConnStr.toString());
88             }
89 
90             shardIdentity.setConfigsvrConnString(std::move(configSvrConnStr));
91         } catch (const AssertionException& parseException) {
92             return parseException.toStatus();
93         }
94     }
95 
96     {
97         std::string name;
98         Status status = bsonExtractStringField(source, shardName(), &name);
99         if (!status.isOK()) {
100             return status;
101         }
102 
103         shardIdentity.setShardName(name);
104     }
105 
106     {
107         OID oid;
108         Status status = bsonExtractOIDField(source, clusterId(), &oid);
109         if (!status.isOK()) {
110             return status;
111         }
112 
113         shardIdentity.setClusterId(oid);
114     }
115 
116     return shardIdentity;
117 }
118 
validate() const119 Status ShardIdentityType::validate() const {
120     if (!_configsvrConnString) {
121         return {ErrorCodes::NoSuchKey,
122                 str::stream() << "missing " << configsvrConnString() << " field"};
123     }
124 
125     if (_configsvrConnString->type() != ConnectionString::SET) {
126         return {ErrorCodes::UnsupportedFormat,
127                 str::stream() << "config connection string can only be replica sets, got "
128                               << ConnectionString::typeToString(_configsvrConnString->type())};
129     }
130 
131     if (!_shardName || _shardName->empty()) {
132         return {ErrorCodes::NoSuchKey, str::stream() << "missing " << shardName() << " field"};
133     }
134 
135     if (!_clusterId || !_clusterId->isSet()) {
136         return {ErrorCodes::NoSuchKey, str::stream() << "missing " << clusterId() << " field"};
137     }
138 
139     return Status::OK();
140 }
141 
toBSON() const142 BSONObj ShardIdentityType::toBSON() const {
143     BSONObjBuilder builder;
144 
145     builder.append("_id", IdName);
146 
147     if (_configsvrConnString) {
148         builder << configsvrConnString(_configsvrConnString->toString());
149     }
150 
151     if (_shardName) {
152         builder << shardName(_shardName.get());
153     }
154 
155     if (_clusterId) {
156         builder << clusterId(_clusterId.get());
157     }
158 
159     return builder.obj();
160 }
161 
toString() const162 std::string ShardIdentityType::toString() const {
163     return toBSON().toString();
164 }
165 
isConfigsvrConnStringSet() const166 bool ShardIdentityType::isConfigsvrConnStringSet() const {
167     return _configsvrConnString.is_initialized();
168 }
169 
getConfigsvrConnString() const170 const ConnectionString& ShardIdentityType::getConfigsvrConnString() const {
171     invariant(_configsvrConnString);
172     return _configsvrConnString.get();
173 }
174 
setConfigsvrConnString(ConnectionString connString)175 void ShardIdentityType::setConfigsvrConnString(ConnectionString connString) {
176     _configsvrConnString = std::move(connString);
177 }
178 
isShardNameSet() const179 bool ShardIdentityType::isShardNameSet() const {
180     return _shardName.is_initialized();
181 }
182 
getShardName() const183 const std::string& ShardIdentityType::getShardName() const {
184     invariant(_shardName);
185     return _shardName.get();
186 }
187 
setShardName(std::string shardName)188 void ShardIdentityType::setShardName(std::string shardName) {
189     _shardName = std::move(shardName);
190 }
191 
isClusterIdSet() const192 bool ShardIdentityType::isClusterIdSet() const {
193     return _clusterId.is_initialized();
194 }
195 
getClusterId() const196 const OID& ShardIdentityType::getClusterId() const {
197     invariant(_clusterId);
198     return _clusterId.get();
199 }
200 
setClusterId(OID clusterId)201 void ShardIdentityType::setClusterId(OID clusterId) {
202     _clusterId = std::move(clusterId);
203 }
204 
createConfigServerUpdateObject(const std::string & newConnString)205 BSONObj ShardIdentityType::createConfigServerUpdateObject(const std::string& newConnString) {
206     BSONObjBuilder builder;
207     BSONObjBuilder setConfigBuilder(builder.subobjStart("$set"));
208     setConfigBuilder.append(configsvrConnString(), newConnString);
209     setConfigBuilder.doneFast();
210     return builder.obj();
211 }
212 
213 }  // namespace mongo
214