YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/ent/src/yb/integration-tests/encryption-test.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) YugaByte, Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4
// in compliance with the License.  You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software distributed under the License
9
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
10
// or implied.  See the License for the specific language governing permissions and limitations
11
// under the License.
12
//
13
14
#include <gtest/gtest.h>
15
16
#include "yb/client/table.h"
17
#include "yb/client/table_handle.h"
18
#include "yb/client/yb_table_name.h"
19
20
#include "yb/integration-tests/cluster_itest_util.h"
21
#include "yb/integration-tests/yb_table_test_base.h"
22
#include "yb/integration-tests/yb_mini_cluster_test_base.h"
23
#include "yb/integration-tests/cluster_verifier.h"
24
25
#include "yb/master/encryption_manager.h"
26
27
#include "yb/tools/yb-admin_client.h"
28
29
#include "yb/util/test_util.h"
30
#include "yb/util/random_util.h"
31
#include "yb/util/status_log.h"
32
#include "yb/util/stol_utils.h"
33
#include "yb/util/string_util.h"
34
35
DECLARE_int64(db_write_buffer_size);
36
DECLARE_int32(memstore_size_mb);
37
DECLARE_int32(load_balancer_max_concurrent_tablet_remote_bootstraps);
38
DECLARE_int32(heartbeat_interval_ms);
39
DECLARE_int64(encryption_counter_min);
40
DECLARE_int64(encryption_counter_max);
41
42
using namespace std::chrono_literals;
43
44
namespace yb {
45
namespace integration_tests {
46
47
constexpr uint32_t kNumKeys = 1024;
48
constexpr uint32_t kNumFlushes = 8;
49
constexpr uint32_t kNumCompactions = 2;
50
constexpr uint32_t kKeySize = 100;
51
constexpr uint32_t kCounterOverflowDefault = 0xFFFFFFE0;
52
53
54
class EncryptionTest : public YBTableTestBase, public testing::WithParamInterface<bool> {
55
 public:
56
57
0
  bool use_external_mini_cluster() override { return true; }
58
59
0
  bool use_yb_admin_client() override { return true; }
60
61
0
  bool enable_ysql() override { return false; }
62
63
0
  size_t num_tablet_servers() override {
64
0
    return 3;
65
0
  }
66
67
0
  size_t num_masters() override {
68
0
    return 3;
69
0
  }
70
71
0
  int num_tablets() override {
72
0
    return 3;
73
0
  }
74
75
0
  void SetUp() override {
76
0
    FLAGS_load_balancer_max_concurrent_tablet_remote_bootstraps = 1;
77
78
0
    YBTableTestBase::SetUp();
79
0
  }
80
81
  void BeforeCreateTable() override {
82
    ASSERT_NO_FATALS(AddUniverseKeys());
83
    ASSERT_NO_FATALS(RotateKey());
84
    // Wait for the key to be propagated to tserver through heartbeat.
85
    SleepFor(MonoDelta::FromMilliseconds(2 * FLAGS_heartbeat_interval_ms));
86
  }
87
88
0
  void WriteWorkload(uint32_t start, uint32_t end) {
89
0
    auto total_num_keys = end - start;
90
0
    for (uint32_t i = start; i < end; i++) {
91
0
      string s(kKeySize, 'a' + (i % 26));
92
0
      PutKeyValue(Format("k_$0", i), s);
93
0
      auto num_keys_written = i - start + 1;
94
0
      if (num_keys_written % (total_num_keys / kNumFlushes) == 0) {
95
0
        ASSERT_OK(client_->FlushTables({table_->id()}, false, 30, false));
96
0
      }
97
0
      if (num_keys_written % (total_num_keys / kNumCompactions) == 0) {
98
0
        ASSERT_OK(client_->FlushTables({table_->id()}, false, 30, true));
99
0
      }
100
0
    }
101
0
  }
102
103
0
  void VerifyWrittenRecords() {
104
0
    auto result_kvs = GetScanResults(client::TableRange(table_));
105
0
    for (uint32_t i = 0; i < result_kvs.size(); i++) {
106
0
      auto split = StringSplit(result_kvs[i].first, '_');
107
0
      int32_t key = CHECK_RESULT(CheckedStoInt<int32_t>(split.back()));
108
0
      ASSERT_EQ(Format("k_$0", key), result_kvs[i].first);
109
0
      ASSERT_TRUE(string(kKeySize, 'a' + (key % 26)) == result_kvs[i].second);
110
0
    }
111
0
  }
112
113
0
  void AddUniverseKeys() {
114
0
    current_key_id_ = RandomHumanReadableString(16);
115
0
    auto bytes = RandomBytes(32);
116
0
    ASSERT_OK(yb_admin_client_->AddUniverseKeyToAllMasters(
117
0
        current_key_id_, std::string(bytes.begin(), bytes.end())));
118
0
  }
119
120
0
  CHECKED_STATUS WaitForAllMastersHaveLatestKeyInMemory() {
121
0
    return LoggedWaitFor([&]() -> Result<bool> {
122
0
      return yb_admin_client_->AllMastersHaveUniverseKeyInMemory(current_key_id_).ok();
123
0
    }, 30s, "Wait for all masters to have key in memory");
124
0
  }
125
126
0
  void RotateKey() {
127
0
    ASSERT_OK(WaitForAllMastersHaveLatestKeyInMemory());
128
0
    ASSERT_OK(yb_admin_client_->RotateUniverseKeyInMemory(current_key_id_));
129
0
    ASSERT_OK(yb_admin_client_->IsEncryptionEnabled());
130
0
  }
131
132
0
  CHECKED_STATUS WaitForLoadBalanced() {
133
0
    SleepFor(MonoDelta::FromSeconds(5));
134
0
    return LoggedWaitFor([&]() -> Result<bool> {
135
0
      return client_->IsLoadBalanced(3);
136
0
    }, MonoDelta::FromSeconds(30), "Wait for load balanced");
137
0
  }
138
139
0
  void DisableEncryption() {
140
0
    ASSERT_OK(yb_admin_client_->DisableEncryptionInMemory());
141
0
  }
142
 private:
143
  std::string current_key_id_ = "";
144
};
145
146
INSTANTIATE_TEST_CASE_P(TestWithCounterOverflow, EncryptionTest, ::testing::Bool());
147
148
0
TEST_P(EncryptionTest, BasicWriteRead) {
149
0
  if (GetParam()) {
150
    // If testing with counter overflow, make sure we set counter to a value that will overflow
151
    // for sst files.
152
0
    FLAGS_encryption_counter_min = kCounterOverflowDefault;
153
0
    FLAGS_encryption_counter_max = kCounterOverflowDefault;
154
0
  }
155
156
0
  WriteWorkload(0, kNumKeys);
157
0
  ASSERT_NO_FATALS(VerifyWrittenRecords());
158
0
  ClusterVerifier cv(external_mini_cluster());
159
0
  ASSERT_NO_FATALS(cv.CheckCluster());
160
0
}
161
162
0
TEST_F(EncryptionTest, MasterLeaderRestart) {
163
0
  WriteWorkload(0, kNumKeys);
164
  // Restart the master leader.
165
0
  auto* master_leader = external_mini_cluster()->GetLeaderMaster();
166
0
  master_leader->Shutdown();
167
0
  ASSERT_OK(master_leader->Restart());
168
  // Recreate the admin client after restarting master leader.
169
0
  CreateAdminClient();
170
0
  ASSERT_OK(WaitForAllMastersHaveLatestKeyInMemory());
171
  // Restart the tablet servers and make sure they can contact the new master leader for the key.
172
0
  for (size_t i = 0; i < external_mini_cluster()->num_tablet_servers(); i++) {
173
0
    external_mini_cluster()->tablet_server(i)->Shutdown();
174
0
    CHECK_OK(external_mini_cluster()->tablet_server(i)->Restart());
175
0
    SleepFor(MonoDelta::FromSeconds(5));\
176
    /*ASSERT_OK(external_mini_cluster()->WaitForTabletsRunning(
177
        external_mini_cluster()->tablet_server(i), MonoDelta::FromSeconds(30)));*/
178
0
  }
179
180
0
  ASSERT_OK(WaitForLoadBalanced());
181
0
  WriteWorkload(kNumKeys, 2 * kNumKeys);
182
0
  ASSERT_NO_FATALS(VerifyWrittenRecords());
183
0
  ClusterVerifier cv(external_mini_cluster());
184
0
  ASSERT_NO_FATALS(cv.CheckCluster());
185
0
}
186
187
0
TEST_F(EncryptionTest, AllMastersRestart) {
188
0
  WriteWorkload(0, kNumKeys);
189
0
  for (size_t i = 0; i < external_mini_cluster()->num_masters(); i++) {
190
0
    external_mini_cluster()->master(i)->Shutdown();
191
0
    CHECK_OK(external_mini_cluster()->master(i)->Restart());
192
0
  }
193
194
0
  ASSERT_OK(WaitForLoadBalanced());
195
0
  WriteWorkload(kNumKeys, 2 * kNumKeys);
196
0
  ASSERT_NO_FATALS(VerifyWrittenRecords());
197
0
  ClusterVerifier cv(external_mini_cluster());
198
0
  ASSERT_NO_FATALS(cv.CheckCluster());
199
0
}
200
201
0
TEST_F(EncryptionTest, RollingMasterRestart) {
202
0
  WriteWorkload(0, kNumKeys);
203
0
  for (size_t i = 0; i < external_mini_cluster()->num_masters(); i++) {
204
0
    external_mini_cluster()->master(i)->Shutdown();
205
0
    CHECK_OK(external_mini_cluster()->master(i)->Restart());
206
0
    ASSERT_OK(WaitForAllMastersHaveLatestKeyInMemory());
207
0
  }
208
  // Recreate the admin client after rolling the masters.
209
0
  CreateAdminClient();
210
  // Test that each master bootstraps from each other.
211
0
  ASSERT_NO_FATALS(AddUniverseKeys());
212
0
  ASSERT_NO_FATALS(RotateKey());
213
214
0
  ASSERT_OK(WaitForLoadBalanced());
215
0
  WriteWorkload(kNumKeys, 2 * kNumKeys);
216
0
  ASSERT_NO_FATALS(VerifyWrittenRecords());
217
0
  ClusterVerifier cv(external_mini_cluster());
218
0
  ASSERT_NO_FATALS(cv.CheckCluster());
219
0
}
220
221
0
TEST_F(EncryptionTest, AddServer) {
222
  // Write 1000 values, add a server, and write 1000 more.
223
0
  WriteWorkload(0, kNumKeys);
224
0
  ASSERT_OK(external_mini_cluster()->AddTabletServer());
225
0
  ASSERT_OK(WaitForLoadBalanced());
226
0
  WriteWorkload(kNumKeys, 2 * kNumKeys);
227
0
  ASSERT_NO_FATALS(VerifyWrittenRecords());
228
0
  ClusterVerifier cv(external_mini_cluster());
229
0
  ASSERT_NO_FATALS(cv.CheckCluster());
230
0
}
231
232
TEST_F(EncryptionTest, RotateKey) {
233
  // Write 1000 values, rotate a new key, and write 1000 more.
234
  WriteWorkload(0, kNumKeys);
235
  ASSERT_NO_FATALS(VerifyWrittenRecords());
236
  ASSERT_NO_FATALS(AddUniverseKeys());
237
  ASSERT_NO_FATALS(RotateKey());
238
  WriteWorkload(kNumKeys, 2 * kNumKeys);
239
  ASSERT_NO_FATALS(VerifyWrittenRecords());
240
  ClusterVerifier cv(external_mini_cluster());
241
  ASSERT_NO_FATALS(cv.CheckCluster());
242
}
243
244
TEST_F(EncryptionTest, DisableEncryption) {
245
  // Write 1000 values, disable encryption, and write 1000 more.
246
  WriteWorkload(0, kNumKeys);
247
  ASSERT_NO_FATALS(VerifyWrittenRecords());
248
  ASSERT_NO_FATALS(DisableEncryption());
249
  WriteWorkload(kNumKeys, 2 * kNumKeys);
250
  ASSERT_NO_FATALS(VerifyWrittenRecords());
251
  ClusterVerifier cv(external_mini_cluster());
252
  ASSERT_NO_FATALS(cv.CheckCluster());
253
}
254
255
0
TEST_F(EncryptionTest, EmptyTable) {
256
  // No values added, make sure add server works with empty tables.
257
0
  ASSERT_OK(external_mini_cluster()->AddTabletServer());
258
0
  ASSERT_OK(WaitForLoadBalanced());
259
0
  ClusterVerifier cv(external_mini_cluster());
260
0
  ASSERT_NO_FATALS(cv.CheckCluster());
261
0
}
262
263
TEST_F(EncryptionTest, EnableEncryption) {
264
  // Disable encryption, add 1000 values, enable, and write 1000 more.
265
  ASSERT_NO_FATALS(DisableEncryption());
266
  WriteWorkload(0, kNumKeys);
267
  ASSERT_NO_FATALS(VerifyWrittenRecords());
268
  ASSERT_NO_FATALS(AddUniverseKeys());
269
  ASSERT_NO_FATALS(RotateKey());
270
  WriteWorkload(kNumKeys, 2 * kNumKeys);
271
  ASSERT_NO_FATALS(VerifyWrittenRecords());
272
  ClusterVerifier cv(external_mini_cluster());
273
  ASSERT_NO_FATALS(cv.CheckCluster());
274
}
275
276
0
TEST_F(EncryptionTest, ServerRestart) {
277
0
  WriteWorkload(0, kNumKeys);
278
0
  auto* tablet_server = external_mini_cluster()->tablet_server(0);
279
0
  tablet_server->Shutdown();
280
0
  ASSERT_OK(tablet_server->Restart());
281
0
  ASSERT_OK(external_mini_cluster()->WaitForTabletsRunning(
282
0
      tablet_server, MonoDelta::FromSeconds(30)));
283
0
  ClusterVerifier cv(external_mini_cluster());
284
0
  ASSERT_NO_FATALS(cv.CheckCluster());
285
0
}
286
287
} // namespace integration_tests
288
} // namespace yb