|
15 | 15 | -include("ns_common.hrl"). |
16 | 16 | -include_lib("ns_common/include/cut.hrl"). |
17 | 17 | -include("cb_cluster_secrets.hrl"). |
| 18 | +-ifdef(TEST). |
| 19 | +-include_lib("eunit/include/eunit.hrl"). |
| 20 | +-endif. |
18 | 21 |
|
19 | 22 | -export([handle_get_secrets/1, |
20 | 23 | handle_get_secret/2, |
@@ -125,9 +128,10 @@ handle_delete_secret(IdStr, Req) -> |
125 | 128 | menelaus_util:reply(Req, 200); |
126 | 129 | {error, not_found} -> |
127 | 130 | menelaus_util:reply_not_found(Req); |
128 | | - {error, Reason} -> |
| 131 | + {error, {used_by, UsedByList}} -> |
| 132 | + Formatted = format_secrets_used_by_list(UsedByList), |
129 | 133 | menelaus_util:reply_global_error( |
130 | | - Req, io_lib:format("Error: ~p", [Reason])) |
| 134 | + Req, io_lib:format("Can't be removed because ~s", [Formatted])) |
131 | 135 | end. |
132 | 136 |
|
133 | 137 | handle_rotate(IdStr, Req) -> |
@@ -402,3 +406,84 @@ parse_id(Str) when is_list(Str) -> |
402 | 406 | _:_ -> |
403 | 407 | menelaus_util:web_exception(404, menelaus_util:reply_text_404()) |
404 | 408 | end. |
| 409 | + |
| 410 | +format_secrets_used_by_list(UsedByMap) -> |
| 411 | + UsedByCfg = maps:get(by_config, UsedByMap, []), |
| 412 | + Secrets = maps:get(by_secrets, UsedByMap, []), |
| 413 | + UsedByDeks = maps:get(by_deks, UsedByMap, []), |
| 414 | + |
| 415 | + FormatUsages = |
| 416 | + fun (Usages) -> |
| 417 | + {Buckets, Other} = misc:partitionmap( |
| 418 | + fun ({bucket_encryption, B}) -> {left, B}; |
| 419 | + (K) -> {right, K} |
| 420 | + end, Usages), |
| 421 | + FormattedUsages = lists:map(fun (config_encryption) -> |
| 422 | + "configuration" |
| 423 | + end, Other), |
| 424 | + Buckets2 = ["\"" ++ B ++ "\"" || B <- Buckets], |
| 425 | + BucketsStr = |
| 426 | + case length(Buckets) of |
| 427 | + 0 -> []; |
| 428 | + 1 -> ["bucket " ++ Buckets2]; |
| 429 | + _ -> ["buckets " ++ lists:join(", ", Buckets2)] |
| 430 | + end, |
| 431 | + FormattedUsages ++ BucketsStr |
| 432 | + end, |
| 433 | + Kind2Usage = ?cut(maps:get(required_usage, cb_deks:dek_config(_))), |
| 434 | + UsagesUsedByCfg = lists:uniq(lists:map(Kind2Usage, UsedByCfg)), |
| 435 | + UsagesUsedByDeks = lists:uniq(lists:map(Kind2Usage, UsedByDeks)), |
| 436 | + SecretsStrs = ["secrets " ++ lists:join(", ", Secrets) || Secrets /= []], |
| 437 | + Strings1 = FormatUsages(UsagesUsedByCfg) ++ SecretsStrs, |
| 438 | + Strings2 = FormatUsages(UsagesUsedByDeks -- UsagesUsedByCfg), |
| 439 | + |
| 440 | + case {Strings1, Strings2} of |
| 441 | + {_, []} -> |
| 442 | + "this secret is configured to encrypt " ++ |
| 443 | + lists:join(", ", Strings1); |
| 444 | + {[], _} -> |
| 445 | + "this secret still encrypts some data in " ++ |
| 446 | + lists:join(", ", Strings2); |
| 447 | + {_ , _} -> |
| 448 | + "this secret is configured to encrypt " ++ |
| 449 | + lists:join(", ", Strings1) ++ |
| 450 | + "; it also still encrypts some data in " ++ |
| 451 | + lists:join(", ", Strings2) |
| 452 | + end. |
| 453 | + |
| 454 | +-ifdef(TEST). |
| 455 | + |
| 456 | +format_secrets_used_by_list_test() -> |
| 457 | + All = cb_deks:dek_kinds_list(#{bucket_names => {["b1", "b2"], 1}}), |
| 458 | + Secrets = ["s1", "s2"], |
| 459 | + F = ?cut(lists:flatten(format_secrets_used_by_list(_))), |
| 460 | + ?assertEqual("this secret is configured to encrypt configuration, " |
| 461 | + "buckets \"b1\", \"b2\"", |
| 462 | + F(#{by_deks => All, by_config => All, by_secrets => []})), |
| 463 | + ?assertEqual("this secret is configured to encrypt configuration, " |
| 464 | + "buckets \"b1\", \"b2\"", |
| 465 | + F(#{by_deks => [], by_config => All, by_secrets => []})), |
| 466 | + ?assertEqual("this secret still encrypts some data in configuration, " |
| 467 | + "buckets \"b1\", \"b2\"", |
| 468 | + F(#{by_deks => All, by_config => [], by_secrets => []})), |
| 469 | + ?assertEqual("this secret is configured to encrypt secrets s1, s2", |
| 470 | + F(#{by_deks => [], by_config => [], by_secrets => Secrets})), |
| 471 | + ?assertEqual("this secret is configured to encrypt configuration, " |
| 472 | + "buckets \"b1\", \"b2\", secrets s1, s2", |
| 473 | + F(#{by_deks => [], by_config => All, by_secrets => Secrets})), |
| 474 | + ?assertEqual("this secret is configured to encrypt configuration, " |
| 475 | + "buckets \"b1\", \"b2\", secrets s1, s2", |
| 476 | + F(#{by_deks => All, by_config => All, by_secrets => Secrets})), |
| 477 | + ?assertEqual("this secret is configured to encrypt configuration; it also " |
| 478 | + "still encrypts some data in buckets \"b1\", \"b2\"", |
| 479 | + F(#{by_deks => All, by_config => [configDek], |
| 480 | + by_secrets => []})), |
| 481 | + ?assertEqual("this secret is configured to encrypt configuration, " |
| 482 | + "bucket \"b2\", secrets s1, s2; " |
| 483 | + "it also still encrypts some data in bucket \"b1\"", |
| 484 | + F(#{by_deks => [configDek, {bucketDek, "b1"}], |
| 485 | + by_config => [{bucketDek, "b2"}, chronicleDek], |
| 486 | + by_secrets => Secrets})). |
| 487 | + |
| 488 | + |
| 489 | +-endif. |
0 commit comments