Repository navigation
Conversation
2b06745 to
698462b
Compare
theghost5800
left a comment
There was a problem hiding this comment.
Some of comments are repeatable or not but overall do the checks through all the code again if possible
theghost5800
left a comment
There was a problem hiding this comment.
Some of comments are repeatable or not but overall do the checks through all the code again if possible
LMCROSSITXSADEPLOY-3563
… from poms LMCROSSITXSADEPLOY-3054
LMCROSSITXSADEPLOY-3563
LMCROSSITXSADEPLOY-3563
LMCROSSITXSADEPLOY-3563
LMCROSSITXSADEPLOY-3563
LMCROSSITXSADEPLOY-3563
LMCROSSITXSADEPLOY-3563
LMCROSSITXSADEPLOY-3563
LMCROSSITXSADEPLOY-3563
LMCROSSITXSADEPLOY-3563
19c69f8 to
e7fa4e6
Compare
…operations limiting LMCROSSITXSADEPLOY-3563
LMCROSSITXSADEPLOY-3563
LMCROSSITXSADEPLOY-3563
LMCROSSITXSADEPLOY-3563
LMCROSSITXSADEPLOY-3563
LMCROSSITXSADEPLOY-3563
LMCROSSITXSADEPLOY-3563
LMCROSSITXSADEPLOY-3563
|
| <dependency> | ||
| <groupId>org.hamcrest</groupId> | ||
| <artifactId>hamcrest</artifactId> | ||
| <version>${hamcrest.version}}</version> |
There was a problem hiding this comment.
remove the second '}' here
| private ExecutorService createUploadMonitorExecutor() { | ||
| ThreadFactory threadFactory = Thread.ofVirtual() | ||
| .name(Constants.UPLOAD_MONITOR_THREAD_NAME_PREFIX, 0) | ||
| .factory(); | ||
|
|
||
| return Executors.newThreadPerTaskExecutor(threadFactory); | ||
| } |
There was a problem hiding this comment.
ExecutorService should be shut down as part of its owner's lifecycle. Here its created but it does not appear to be closed.
| public static final int MAX_CONCURRENT_PAGES = 4; //leaving it like that for testing purposes | ||
| public static final int SECOND_PAGE = 2; | ||
| public static final int DEFAULT_CONCURRENT_TASKS = 8; //this one can be a bit more, but first tests will be like that |
There was a problem hiding this comment.
Should these values be left for prod? If so remove the comments.
| if (e.getStatusCode() == HttpStatus.NOT_FOUND) { | ||
| // package was most probably already consumed by CF between the polls, meaning that since the build was already created from the package object, the package is not needed anymore | ||
| // and the cf blobstore garbage collector has deleted it | ||
| keepPolling = false; | ||
| continue; | ||
| } | ||
| throw e; |
There was a problem hiding this comment.
The non-404 throw runs on the background monitor thread, and it seems like the error gets swallowed. Should this call callback.onError(e) like the FAILED-status branch below?
| public record V3Application(@JsonProperty(V3Fields.GUID) String guid, @JsonProperty(V3Fields.NAME) String name, | ||
| @JsonProperty(V3Fields.STATE) String state, | ||
| @JsonProperty(V3Fields.CREATED_AT) String createdAt, @JsonProperty(V3Fields.UPDATED_AT) String updatedAt, | ||
| @JsonProperty("lifecycle") V3Lifecycle lifecycle, @JsonProperty(V3Fields.METADATA) V3Metadata metadata, |
There was a problem hiding this comment.
Only lifecycle is still string
| } | ||
|
|
||
| @JsonIgnoreProperties(ignoreUnknown = true) | ||
| public record V3EnvironmentVariables(@JsonProperty("var") Map<String, String> environmentVariables) { |
| private static BitsData.Checksum | ||
| parseBitsChecksum(V3Package.V3Checksum checksum) { |
| @JsonProperty("shareable") Boolean shareable, | ||
| @JsonProperty("documentation_url") String documentationUrl, |
| public record V3Features(@JsonProperty("bindable") Boolean bindable, | ||
| @JsonProperty("allow_context_updates") Boolean allowContextUpdates, | ||
| @JsonProperty("bindings_retrievable") Boolean bindingsRetrievable, | ||
| @JsonProperty("instances_retrievable") Boolean instancesRetrievable, | ||
| @JsonProperty("plan_updatable") Boolean planUpdatable) { | ||
| } | ||
|
|
||
| @JsonIgnoreProperties(ignoreUnknown = true) | ||
| public record V3Relationships(@JsonProperty("service_broker") V3ToOneRelationship serviceBroker) { |
| @JsonProperty(V3Fields.STATE) String state, @JsonProperty("memory_in_mb") Integer memoryInMb, | ||
| @JsonProperty("disk_in_mb") Integer diskInMb, @JsonProperty("result") V3Result result, |
| @JsonProperty(V3Fields.METADATA) V3Metadata metadata) { | ||
|
|
||
| @JsonIgnoreProperties(ignoreUnknown = true) | ||
| public record V3Result(@JsonProperty("failure_reason") String failureReason) { |
| while (keepPolling) { | ||
| Upload upload; | ||
|
|
||
| try { | ||
| upload = getUploadStatus(cloudPackage.getGuid()); | ||
| } catch (CloudOperationException e) { | ||
| if (e.getStatusCode() == HttpStatus.NOT_FOUND) { | ||
| // package was most probably already consumed by CF between the polls, meaning that since the build was already created from the package object, the package is not needed anymore | ||
| // and the cf blobstore garbage collector has deleted it | ||
| keepPolling = false; | ||
| continue; | ||
| } | ||
| throw e; | ||
| } | ||
|
|
||
| Status uploadStatus = upload.getStatus(); | ||
| boolean unsubscribe = callback.onProgress(uploadStatus.toString()); | ||
|
|
||
| if (unsubscribe || OperationsUtil.isUploadReady(uploadStatus)) { | ||
| keepPolling = false; | ||
| } else if (OperationsUtil.hasUploadFailed(uploadStatus)) { | ||
| callback.onError(upload.getErrorDetails() | ||
| .getDescription()); | ||
| keepPolling = false; | ||
| } else { | ||
| try { | ||
| MiscUtil.sleep(Constants.PACKAGE_UPLOAD_JOB_POLLING_PERIOD); | ||
| } catch (IllegalStateException e) { | ||
| keepPolling = false; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Thats a very big while loop. Can you extract some of the things in it to methods
|
|
||
| private static ObjectMapper configureObjectMapper() { | ||
| return new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) | ||
| .enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY); |
There was a problem hiding this comment.
Missing configs to fully match cf-java-client objectmapper behaviour
.registerModule(new Jdk8Module())
.setSerializationInclusion(NON_NULL);
| Duration interval = Constants.JOB_POLL_MIN_INTERVAL; | ||
|
|
||
| while (true) { | ||
| V3Job asyncJob = get(CloudControllerV3Endpoints.JOBS + jobGuid, V3Job.class); |
There was a problem hiding this comment.
I don't see this changed, I expect to use similar structures as this method postForObject(String uri, Object body, Class<T> responseType, Object... uriVars). jobGuid to be passed as uriVar, not as concatenated String.
| long timeoutNanos = timeout.toNanos(); | ||
| Duration interval = Constants.JOB_POLL_MIN_INTERVAL; | ||
|
|
||
| while (true) { |
There was a problem hiding this comment.
while (asyncJob == null || !asyncJob.isTerminal()) {
long elapsedNanos = determineElapsedTime(startTimeNanos, timeout, jobGuid);
long remainingNanos = timeoutNanos - elapsedNanos;
Duration sleepDuration = interval.toNanos() > remainingNanos ? Duration.ofNanos(remainingNanos) : interval;
sleep(sleepDuration);
interval = nextInterval(interval);
asyncJob = get(CloudControllerV3Endpoints.JOBS + jobGuid, V3Job.class);
}
if (asyncJob.isFailed()) {
throw jobFailed(asyncJob);
}
return asyncJob;
Here is one solution which can avoid this.
Also I have notice in the current behaviour that there is no exit from the loop due to exceeded timeout which means if job doesn't return any success or failed state in expected timeout frame, then it will stuck indefinitely.
| private CloudOperationException convertV3ClientException(AbstractCloudFoundryException e) { | ||
| HttpStatus httpStatus = HttpStatus.valueOf(e.getStatusCode()); | ||
| return new CloudOperationException(httpStatus, httpStatus.getReasonPhrase(), e.getMessage(), e); | ||
| // The underlying CloudControllerRestClient already surfaces failures as CloudOperationException |
There was a problem hiding this comment.
My question again is why we need this method if we do not make anymore any translations or changes? Can we just remove these two methods and stop invoking delegated method through lambda expressions?
| public record V3Features(@JsonProperty("bindable") Boolean bindable, | ||
| @JsonProperty("allow_context_updates") Boolean allowContextUpdates, | ||
| @JsonProperty("bindings_retrievable") Boolean bindingsRetrievable, | ||
| @JsonProperty("instances_retrievable") Boolean instancesRetrievable, | ||
| @JsonProperty("plan_updatable") Boolean planUpdatable) { | ||
| } | ||
|
|
||
| @JsonIgnoreProperties(ignoreUnknown = true) | ||
| public record V3Relationships(@JsonProperty("service_broker") V3ToOneRelationship serviceBroker) { |
| assertEquals(serviceName, service.getName()); | ||
| assertEquals(IntegrationTestConstants.SERVICE_OFFERING, service.getLabel()); | ||
| assertEquals(IntegrationTestConstants.SERVICE_PLAN, service.getPlan()); | ||
| } catch (Exception e) { |
There was a problem hiding this comment.
remove this try-catch block. If some of method invocations throw exception, it will lead to failed test
| assertTrue(finchServiceOffering.getServicePlans() | ||
| .stream() | ||
| .anyMatch(plan -> IntegrationTestConstants.SERVICE_PLAN.equals(plan.getName())), | ||
| MessageFormat.format("Expected plan \"{0}\" in the offering's plans", IntegrationTestConstants.SERVICE_PLAN)); |
| MessageFormat.format("Expected service \"{0}\" to no longer match the selector after the label was unset", | ||
| serviceName)); | ||
| } catch (Exception e) { | ||
| fail(e); |
| assertTrue(tasks.stream() | ||
| .anyMatch(currentTask -> currentTask.getGuid() | ||
| .equals(task.getGuid())), | ||
| MessageFormat.format("Expected the created task \"{0}\" to be in the application's task list", task.getName())); |
| <dependency> | ||
| <groupId>org.hamcrest</groupId> | ||
| <artifactId>hamcrest</artifactId> | ||
| <version>${hamcrest.version}}</version> |
| String domain = route.url(); | ||
|
|
||
| if (StringUtils.hasText(route.host())) { | ||
| domain = domain.substring(route.host() | ||
| .length() + 1); | ||
| } |
There was a problem hiding this comment.
Why are we slicing the url here?
| @Override | ||
| public void createApplication(ApplicationToCreateDto dto) { | ||
| applicationsOperations.createApplication(dto); | ||
|
|
||
| if (dto.getStaging() != null) { | ||
| updateApplicationStaging(dto.getName(), dto.getStaging()); | ||
| } | ||
|
|
||
| if (dto.getRoutes() != null && !dto.getRoutes() | ||
| .isEmpty()) { | ||
| updateApplicationRoutes(dto.getName(), dto.getRoutes()); | ||
| } | ||
| } |
There was a problem hiding this comment.
The lifecycle gets written twice on every app create: once in createApplication, then again in the updateApplicationStaging. Can you build it once in the create body and drop it from the staging update? Also the two builders aren't equivalent: only updateApplicationStaging validates CNB buildpacks.
| private UUID getRequiredApplicationGuid(String applicationName) { | ||
| String applicationsQuery = OperationsQueryUtil.buildApplicationsQuery(applicationName, targetSpace); | ||
| List<V3GuidReference> apps = client.list(applicationsQuery, APP_PAGE); | ||
|
|
||
| if (apps.isEmpty() || apps.getFirst() | ||
| .guid() == null) { | ||
| throw new CloudOperationException(HttpStatus.NOT_FOUND, HttpStatus.NOT_FOUND.getReasonPhrase(), | ||
| MessageFormat.format(Messages.APPLICATION_0_NOT_FOUND, applicationName)); | ||
| } | ||
|
|
||
| return UUID.fromString(apps.getFirst() | ||
| .guid()); | ||
| } |
There was a problem hiding this comment.
getRequiredApplicationGuid is duplicated across 6 classes: here PackagesV3Operations, EventsV3Operations, ProcessesV3Operations, RoutesV3Operations, TasksV3Operations, ServiceBindingsV3Operations. Can you extract it into one shared helper?



Migration of the cf-java-client dependency