private static void validateNameAndApplicationAttributes(@RequestBody CanaryConfig canaryConfig) { if (StringUtils.isEmpty(canaryConfig.getName())) { throw new IllegalArgumentException("Canary config must specify a name."); } else if (canaryConfig.getApplications() == null || canaryConfig.getApplications().size() == 0) { throw new IllegalArgumentException("Canary config must specify at least one application."); } String canaryConfigName = canaryConfig.getName(); if (!canaryConfigNamePattern.matcher(canaryConfigName).matches()) { throw new IllegalArgumentException("Canary config cannot be named '" + canaryConfigName + "'. Names must contain only letters, numbers, dashes (-) and underscores (_)."); } }
private void checkForDuplicateCanaryConfig(String accountName, ObjectType objectType, CanaryConfig canaryConfig, String canaryConfigId) { String canaryConfigName = canaryConfig.getName(); List<String> applications = canaryConfig.getApplications(); List<Map<String, Object>> canaryConfigSummaries = listObjectKeys(accountName, objectType, applications, false); Map<String, Object> existingCanaryConfigSummary = canaryConfigSummaries .stream() .filter(it -> it.get("name").equals(canaryConfigName)) .findFirst() .orElse(null); // We want to avoid creating a naming collision due to the renaming of an existing canary config. if (existingCanaryConfigSummary != null && !existingCanaryConfigSummary.get("id").equals(canaryConfigId)) { throw new IllegalArgumentException("Canary config with name '" + canaryConfigName + "' already exists in the scope of applications " + applications + "."); } }
private void checkForDuplicateCanaryConfig(CanaryConfig canaryConfig, String canaryConfigId, AwsNamedAccountCredentials credentials) { String canaryConfigName = canaryConfig.getName(); List<String> applications = canaryConfig.getApplications(); String existingCanaryConfigId = canaryConfigIndex.getIdFromName(credentials, canaryConfigName, applications); // We want to avoid creating a naming collision due to the renaming of an existing canary config. if (!StringUtils.isEmpty(existingCanaryConfigId) && !existingCanaryConfigId.equals(canaryConfigId)) { throw new IllegalArgumentException("Canary config with name '" + canaryConfigName + "' already exists in the scope of applications " + applications + "."); } }
private void checkForDuplicateCanaryConfig(CanaryConfig canaryConfig, String canaryConfigId, ConfigBinNamedAccountCredentials credentials) { String canaryConfigName = canaryConfig.getName(); List<String> applications = canaryConfig.getApplications(); String existingCanaryConfigId = canaryConfigIndex.getIdFromName(credentials, canaryConfigName, applications); // We want to avoid creating a naming collision due to the renaming of an existing canary config. if (!StringUtils.isEmpty(existingCanaryConfigId) && !existingCanaryConfigId.equals(canaryConfigId)) { throw new IllegalArgumentException("Canary config with name '" + canaryConfigName + "' already exists in the scope of applications " + applications + "."); } }
private void checkForDuplicateCanaryConfig(CanaryConfig canaryConfig, String canaryConfigId, GoogleNamedAccountCredentials credentials) { String canaryConfigName = canaryConfig.getName(); List<String> applications = canaryConfig.getApplications(); String existingCanaryConfigId = canaryConfigIndex.getIdFromName(credentials, canaryConfigName, applications); // We want to avoid creating a naming collision due to the renaming of an existing canary config. if (!StringUtils.isEmpty(existingCanaryConfigId) && !existingCanaryConfigId.equals(canaryConfigId)) { throw new IllegalArgumentException("Canary config with name '" + canaryConfigName + "' already exists in the scope of applications " + applications + "."); } }
@Override public <T> void storeObject(String accountName, ObjectType objectType, String objectKey, T obj, String filename, boolean isAnUpdate) { MemoryNamedAccountCredentials credentials = getCredentials(accountName, objectType); long currentTimestamp = System.currentTimeMillis(); Map<String, Object> objectMetadataMap = new HashMap<>(); objectMetadataMap.put("id", objectKey); objectMetadataMap.put("updatedTimestamp", currentTimestamp); objectMetadataMap.put("updatedTimestampIso", Instant.ofEpochMilli(currentTimestamp).toString()); if (objectType == ObjectType.CANARY_CONFIG) { CanaryConfig canaryConfig = (CanaryConfig)obj; checkForDuplicateCanaryConfig(accountName, objectType, canaryConfig, objectKey); objectMetadataMap.put("name", canaryConfig.getName()); objectMetadataMap.put("applications", canaryConfig.getApplications()); } credentials.getObjects().get(objectType).put(objectKey, obj); credentials.getMetadata().get(objectType).put(objectKey, objectMetadataMap); }
private Map<String, Object> metadataFor(ConfigBinNamedAccountCredentials credentials, String id) { // TODO: (mgraff) Should factor out to a common method, or just call .load() ConfigBinRemoteService remoteService = credentials.getRemoteService(); String ownerApp = credentials.getOwnerApp(); String configType = credentials.getConfigType(); String json; try { json = retry.retry(() -> remoteService.get(ownerApp, configType, id), MAX_RETRIES, RETRY_BACKOFF); } catch (RetrofitError e) { throw new IllegalArgumentException("No such object named " + id); } CanaryConfig config; try { config = kayentaObjectMapper.readValue(json, ObjectType.CANARY_CONFIG.getTypeReference()); } catch (Throwable e) { log.error("Read failed on path {}: {}", id, e); throw new IllegalStateException(e); } return new ImmutableMap.Builder<String, Object>() .put("id", id) .put("name", config.getName()) .build(); } }
@ApiOperation(value = "Update a canary config") @RequestMapping(value = "/{canaryConfigId:.+}", consumes = "application/json", method = RequestMethod.PUT) public CanaryConfigUpdateResponse updateCanaryConfig(@RequestParam(required = false) final String configurationAccountName, @PathVariable String canaryConfigId, @RequestBody CanaryConfig canaryConfig) throws IOException { String resolvedConfigurationAccountName = CredentialsHelper.resolveAccountByNameOrType(configurationAccountName, AccountCredentials.Type.CONFIGURATION_STORE, accountCredentialsRepository); StorageService configurationService = storageServiceRepository .getOne(resolvedConfigurationAccountName) .orElseThrow(() -> new IllegalArgumentException("No configuration service was configured; unable to write canary config to bucket.")); canaryConfig.setUpdatedTimestamp(System.currentTimeMillis()); canaryConfig.setUpdatedTimestampIso(Instant.ofEpochMilli(canaryConfig.getUpdatedTimestamp()).toString()); validateNameAndApplicationAttributes(canaryConfig); try { configurationService.loadObject(resolvedConfigurationAccountName, ObjectType.CANARY_CONFIG, canaryConfigId); } catch (Exception e) { throw new IllegalArgumentException("Canary config '" + canaryConfigId + "' does not exist."); } configurationService.storeObject(resolvedConfigurationAccountName, ObjectType.CANARY_CONFIG, canaryConfigId, canaryConfig, canaryConfig.getName() + ".json", true); return CanaryConfigUpdateResponse.builder().canaryConfigId(canaryConfigId).build(); }
@ApiOperation(value = "Write a canary config to object storage") @RequestMapping(consumes = "application/json", method = RequestMethod.POST) public CanaryConfigUpdateResponse storeCanaryConfig(@RequestParam(required = false) final String configurationAccountName, @RequestBody CanaryConfig canaryConfig) throws IOException { String resolvedConfigurationAccountName = CredentialsHelper.resolveAccountByNameOrType(configurationAccountName, AccountCredentials.Type.CONFIGURATION_STORE, accountCredentialsRepository); StorageService configurationService = storageServiceRepository .getOne(resolvedConfigurationAccountName) .orElseThrow(() -> new IllegalArgumentException("No configuration service was configured; unable to write canary config to bucket.")); if (canaryConfig.getCreatedTimestamp() == null) { canaryConfig.setCreatedTimestamp(System.currentTimeMillis()); } if (canaryConfig.getUpdatedTimestamp() == null) { canaryConfig.setUpdatedTimestamp(canaryConfig.getCreatedTimestamp()); } canaryConfig.setCreatedTimestampIso(Instant.ofEpochMilli(canaryConfig.getCreatedTimestamp()).toString()); canaryConfig.setUpdatedTimestampIso(Instant.ofEpochMilli(canaryConfig.getUpdatedTimestamp()).toString()); String canaryConfigId = UUID.randomUUID() + ""; // TODO(duftler): Serialize the canary config within a canary run? validateNameAndApplicationAttributes(canaryConfig); try { configurationService.loadObject(resolvedConfigurationAccountName, ObjectType.CANARY_CONFIG, canaryConfigId); } catch (NotFoundException e) { configurationService.storeObject(resolvedConfigurationAccountName, ObjectType.CANARY_CONFIG, canaryConfigId, canaryConfig, canaryConfig.getName() + ".json", false); return CanaryConfigUpdateResponse.builder().canaryConfigId(canaryConfigId).build(); } throw new IllegalArgumentException("Canary config '" + canaryConfigId + "' already exists."); }
.put("name", canaryConfig.getName()) .put("updatedTimestamp", updatedTimestamp) .put("updatedTimestampIso", Instant.ofEpochMilli(updatedTimestamp).toString())
@NotNull String resolvedStorageAccountName, @NotNull CanaryExecutionRequest canaryExecutionRequest) throws JsonProcessingException { registry.counter(pipelineRunId.withTag("canaryConfigId", canaryConfigId).withTag("canaryConfigName", canaryConfig.getName())).increment();
.put("name", canaryConfig.getName()) .put("updatedTimestamp", updatedTimestamp) .put("updatedTimestampIso", Instant.ofEpochMilli(updatedTimestamp).toString())
.put("name", canaryConfig.getName()) .put("updatedTimestamp", updatedTimestamp) .put("updatedTimestampIso", Instant.ofEpochMilli(updatedTimestamp).toString())
private void checkForDuplicateCanaryConfig(String accountName, ObjectType objectType, CanaryConfig canaryConfig, String canaryConfigId) { String canaryConfigName = canaryConfig.getName(); List<String> applications = canaryConfig.getApplications(); List<Map<String, Object>> canaryConfigSummaries = listObjectKeys(accountName, objectType, applications, false); Map<String, Object> existingCanaryConfigSummary = canaryConfigSummaries .stream() .filter(it -> it.get("name").equals(canaryConfigName)) .findFirst() .orElse(null); // We want to avoid creating a naming collision due to the renaming of an existing canary config. if (existingCanaryConfigSummary != null && !existingCanaryConfigSummary.get("id").equals(canaryConfigId)) { throw new IllegalArgumentException("Canary config with name '" + canaryConfigName + "' already exists in the scope of applications " + applications + "."); } }
private void checkForDuplicateCanaryConfig(CanaryConfig canaryConfig, String canaryConfigId, AwsNamedAccountCredentials credentials) { String canaryConfigName = canaryConfig.getName(); List<String> applications = canaryConfig.getApplications(); String existingCanaryConfigId = canaryConfigIndex.getIdFromName(credentials, canaryConfigName, applications); // We want to avoid creating a naming collision due to the renaming of an existing canary config. if (!StringUtils.isEmpty(existingCanaryConfigId) && !existingCanaryConfigId.equals(canaryConfigId)) { throw new IllegalArgumentException("Canary config with name '" + canaryConfigName + "' already exists in the scope of applications " + applications + "."); } }
@Override public <T> void storeObject(String accountName, ObjectType objectType, String objectKey, T obj, String filename, boolean isAnUpdate) { MemoryNamedAccountCredentials credentials = getCredentials(accountName, objectType); long currentTimestamp = System.currentTimeMillis(); Map<String, Object> objectMetadataMap = new HashMap<>(); objectMetadataMap.put("id", objectKey); objectMetadataMap.put("updatedTimestamp", currentTimestamp); objectMetadataMap.put("updatedTimestampIso", Instant.ofEpochMilli(currentTimestamp).toString()); if (objectType == ObjectType.CANARY_CONFIG) { CanaryConfig canaryConfig = (CanaryConfig)obj; checkForDuplicateCanaryConfig(accountName, objectType, canaryConfig, objectKey); objectMetadataMap.put("name", canaryConfig.getName()); objectMetadataMap.put("applications", canaryConfig.getApplications()); } credentials.getObjects().get(objectType).put(objectKey, obj); credentials.getMetadata().get(objectType).put(objectKey, objectMetadataMap); }
@NotNull String resolvedStorageAccountName, @NotNull CanaryExecutionRequest canaryExecutionRequest) throws JsonProcessingException { registry.counter(pipelineRunId.withTag("canaryConfigId", canaryConfigId).withTag("canaryConfigName", canaryConfig.getName())).increment();
.put("name", canaryConfig.getName()) .put("updatedTimestamp", updatedTimestamp) .put("updatedTimestampIso", Instant.ofEpochMilli(updatedTimestamp).toString())