-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[#7706] Platform: Edit backup config credentials. #8050
Changes from 22 commits
95b3138
ebc47af
1cd4f9a
e792ba6
e152b0d
4f205b3
e750ef2
d847aac
a5a7011
bd965bc
cf27671
6d16016
f285d55
5758038
88e5728
9c0b652
5665ed5
76df1b8
2804e86
3baf2c9
b9b6e46
cc7fdfe
77ec4bd
ee6a95d
0df5750
fbbf385
0f32b7a
5c2cf0a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,22 +2,26 @@ | |
|
||
package com.yugabyte.yw.controllers; | ||
|
||
import com.fasterxml.jackson.databind.JsonNode; | ||
import com.fasterxml.jackson.databind.node.ObjectNode; | ||
|
||
import com.google.inject.Inject; | ||
|
||
import com.yugabyte.yw.common.ApiResponse; | ||
import com.yugabyte.yw.models.Audit; | ||
import com.yugabyte.yw.models.CustomerConfig; | ||
import com.yugabyte.yw.models.helpers.CommonUtils; | ||
import com.yugabyte.yw.models.helpers.CustomerConfigValidator; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import play.libs.Json; | ||
import play.mvc.Result; | ||
|
||
import java.util.UUID; | ||
|
||
|
||
public class CustomerConfigController extends AuthenticatedController { | ||
public static final Logger LOG = LoggerFactory.getLogger(CustomerConfigController.class); | ||
|
||
|
@@ -57,4 +61,31 @@ public Result delete(UUID customerUUID, UUID configUUID) { | |
public Result list(UUID customerUUID) { | ||
return ApiResponse.success(CustomerConfig.getAll(customerUUID)); | ||
} | ||
|
||
public Result edit(UUID customerUUID, UUID configUUID) { | ||
JsonNode formData = request().body().asJson(); | ||
ObjectNode errorJson = configValidator.validateFormData(formData); | ||
if (errorJson.size() > 0) { | ||
return ApiResponse.error(BAD_REQUEST, errorJson); | ||
} | ||
|
||
errorJson = configValidator.validateDataContent(formData); | ||
if (errorJson.size() > 0) { | ||
return ApiResponse.error(BAD_REQUEST, errorJson); | ||
} | ||
CustomerConfig customerConfig = CustomerConfig.get(customerUUID, configUUID); | ||
if (customerConfig == null) { | ||
return ApiResponse.error(BAD_REQUEST, "Invalid configUUID: " + configUUID); | ||
} | ||
CustomerConfig config = CustomerConfig.get(configUUID); | ||
JsonNode data = Json.toJson(formData.get("data")); | ||
if (data != null && data.get("BACKUP_LOCATION") != null) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please extract "BACKUP_LOCATION" into a constant or use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we are using the string instead of constants lot of places. Including other tests and utils file for masking. I will create another issue to fix these separately. |
||
((ObjectNode)data).put("BACKUP_LOCATION", config.data.get("BACKUP_LOCATION")); | ||
} | ||
JsonNode updatedData = CommonUtils.unmaskConfig(config.data, data); | ||
config.data = Json.toJson(updatedData); | ||
config.update(); | ||
Audit.createAuditEntry(ctx(), request()); | ||
mahendranbhat marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return ApiResponse.success(config); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -64,8 +64,8 @@ public static JsonNode maskConfig(JsonNode config) { | |
} | ||
|
||
private static String getMaskedValue(String key, String value) { | ||
return isStrictlySensitiveField(key) || (value == null) ? MASKED_FIELD_VALUE | ||
: value.replaceAll(maskRegex, "*"); | ||
return isStrictlySensitiveField(key) || value.length() < 5 | ||
|| (value == null) ? MASKED_FIELD_VALUE : value.replaceAll(maskRegex, "*"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No-no-no. If you have this in such variant then you don't have a test case for this. IIRC, boolean operations are executed from left to right order. So if you have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oops!! Yeah, did not check the last condition. Will update and add a test case too. |
||
} | ||
|
||
/** | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -169,4 +169,65 @@ public void testDeleteInUseStorageConfig() { | |
assertEquals(0, CustomerConfig.getAll(defaultCustomer.uuid).size()); | ||
assertAuditEntry(1, defaultCustomer.uuid); | ||
} | ||
|
||
@Test | ||
public void testEditInUseStorageConfig() { | ||
ObjectNode bodyJson = Json.newObject(); | ||
JsonNode data = Json.parse("{\"BACKUP_LOCATION\": \"test\", \"ACCESS_KEY\": \"A-KEY\", " + | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Putting strings here instead of somewhere defined constants may give us some problems later if someone decides to rename one of these fields. I suggest to create/use Java constants. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, we are using the string instead of constants lot of places. Including other tests and utils file for masking. I will create another issue to fix these separately. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, this works for me. |
||
"\"ACCESS_SECRET\": \"A-SECRET\"}"); | ||
bodyJson.put("name", "test1"); | ||
bodyJson.set("data", data); | ||
bodyJson.put("type", "STORAGE"); | ||
UUID configUUID = ModelFactory.createS3StorageConfig(defaultCustomer).configUUID; | ||
Backup backup = ModelFactory.createBackup(defaultCustomer.uuid, UUID.randomUUID(), | ||
configUUID); | ||
String url = "/api/customers/" + defaultCustomer.uuid + "/configs/" + configUUID; | ||
Result result = FakeApiHelper.doRequestWithAuthTokenAndBody("PUT", url, | ||
defaultUser.createAuthToken(), bodyJson); | ||
assertOk(result); | ||
backup.delete(); | ||
result = FakeApiHelper.doRequestWithAuthTokenAndBody("PUT", url, | ||
defaultUser.createAuthToken(), bodyJson); | ||
assertOk(result); | ||
JsonNode json = Json.parse(contentAsString(result)); | ||
assertEquals("s3://foo", json.get("data").get("BACKUP_LOCATION").textValue()); | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Required to add more test cases.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jaydeepkumara for both used and unused configs, editable fields are the same I believe. ( at least the current implementation of UI behaves like that. @nishantSharma459 confirm ) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok. |
||
@Test | ||
public void testEditInvalidCustomerConfig() { | ||
ObjectNode bodyJson = Json.newObject(); | ||
JsonNode data = Json.parse("{\"foo\":\"bar\"}"); | ||
bodyJson.put("name", "test1"); | ||
bodyJson.set("data", data); | ||
bodyJson.put("type", "STORAGE"); | ||
Customer customer = ModelFactory.testCustomer("nc", "New Customer"); | ||
UUID configUUID = ModelFactory.createS3StorageConfig(customer).configUUID; | ||
String url = "/api/customers/" + defaultCustomer.uuid + "/configs/" + configUUID; | ||
Result result = FakeApiHelper.doRequestWithAuthTokenAndBody("PUT", url, | ||
defaultUser.createAuthToken(), bodyJson); | ||
assertBadRequest(result, "Invalid configUUID: " + configUUID); | ||
assertEquals(1, CustomerConfig.getAll(customer.uuid).size()); | ||
assertAuditEntry(0, defaultCustomer.uuid); | ||
} | ||
|
||
@Test | ||
public void testEditWithBackupLocation() { | ||
ObjectNode bodyJson = Json.newObject(); | ||
JsonNode data = Json.parse("{\"BACKUP_LOCATION\": \"test\", \"ACCESS_KEY\": \"A-KEY-NEW\", " + | ||
"\"ACCESS_SECRET\": \"A-SECRET-NEW\"}"); | ||
bodyJson.put("name", "test1"); | ||
bodyJson.set("data", data); | ||
bodyJson.put("type", "STORAGE"); | ||
UUID configUUID = ModelFactory.createS3StorageConfig(defaultCustomer).configUUID; | ||
String url = "/api/customers/" + defaultCustomer.uuid + "/configs/" + configUUID; | ||
Result result = FakeApiHelper.doRequestWithAuthTokenAndBody("PUT", url, | ||
defaultUser.createAuthToken(), bodyJson); | ||
assertOk(result); | ||
JsonNode json = Json.parse(contentAsString(result)); | ||
// Should not update the field BACKUP_LOCATION to "test". | ||
assertEquals("s3://foo", json.get("data").get("BACKUP_LOCATION").textValue()); | ||
// SHould be updated and the API response should give asked data. | ||
assertEquals("A-*****EW", json.get("data").get("ACCESS_KEY").textValue()); | ||
assertEquals("A-********EW", json.get("data").get("ACCESS_SECRET").textValue()); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Invalid Customer configuration UUID.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consistent with the delete API response.