diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/applications/_UpdateApplicationEnvironmentVariablesRequest.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/applications/_UpdateApplicationEnvironmentVariablesRequest.java index 90da3bfe42..837622ca1f 100644 --- a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/applications/_UpdateApplicationEnvironmentVariablesRequest.java +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/applications/_UpdateApplicationEnvironmentVariablesRequest.java @@ -16,14 +16,15 @@ package org.cloudfoundry.client.v3.applications; +import java.util.Map; + import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import org.cloudfoundry.AllowNulls; import org.immutables.value.Value; -import java.util.Map; - @JsonSerialize @Value.Immutable abstract class _UpdateApplicationEnvironmentVariablesRequest { @@ -39,6 +40,7 @@ abstract class _UpdateApplicationEnvironmentVariablesRequest { */ @AllowNulls @JsonProperty("var") + @JsonInclude(value = JsonInclude.Include.ALWAYS) abstract Map getVars(); } diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/processes/ProcessState.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/processes/ProcessState.java index c9ac2c22c2..bf40f480e8 100644 --- a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/processes/ProcessState.java +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/processes/ProcessState.java @@ -42,7 +42,12 @@ public enum ProcessState { /** * The starting state */ - STARTING("STARTING"); + STARTING("STARTING"), + + /** + * The stopping state + */ + STOPPING("STOPPING"); private final String value; @@ -61,6 +66,8 @@ public static ProcessState from(String s) { return RUNNING; case "starting": return STARTING; + case "stopping": + return STOPPING; default: throw new IllegalArgumentException(String.format("Unknown process state: %s", s)); } diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/_DefaultCloudFoundryOperations.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/_DefaultCloudFoundryOperations.java index 1d21f29b2b..2b0a9996c2 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/_DefaultCloudFoundryOperations.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/_DefaultCloudFoundryOperations.java @@ -79,7 +79,7 @@ public Advanced advanced() { @Override @Value.Derived public Applications applications() { - return new DefaultApplications(getCloudFoundryClientPublisher(), getDopplerClientPublisher(), getSpaceId()); + return new DefaultApplications(getCloudFoundryClient(), getDopplerClient(), getSpaceId().block()); } @Override @@ -318,12 +318,14 @@ private static boolean hasText(CharSequence str) { private static Flux requestOrganizations(Mono cloudFoundryClientPublisher, String organization) { return cloudFoundryClientPublisher - .flatMapMany(cloudFoundryClient -> PaginationUtils - .requestClientV3Resources(page -> cloudFoundryClient.organizationsV3() - .list(ListOrganizationsRequest.builder() - .name(organization) - .page(page) - .build()))); + .flatMapMany(cloudFoundryClient -> PaginationUtils + .requestClientV3Resources(page -> cloudFoundryClient.organizationsV3() + .list(ListOrganizationsRequest.builder() + .name(organization) + .page(page) + .build()) + ) + ); } private static Flux requestSpaces(Mono cloudFoundryClientPublisher, String organizationId, String space) { diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java index 5196fef6c8..8377d53742 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/Applications.java @@ -92,7 +92,7 @@ public interface Applications { Flux getEvents(GetApplicationEventsRequest request); /** - * Retrieve the Health Check Type of an application + * Retrieve the Health Check Type of the web process of an application. * * @param request the get health check request * @return the health check @@ -225,7 +225,7 @@ public interface Applications { Mono setEnvironmentVariable(SetEnvironmentVariableApplicationRequest request); /** - * Set the Health Check Type of an application + * Set the Health Check Type of the web process of an application * * @param request the set health check request * @return a completion indicator diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java index e51ddbb472..626a14f9e3 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/DefaultApplications.java @@ -19,7 +19,6 @@ import static org.cloudfoundry.client.v3.LifecycleType.BUILDPACK; import static org.cloudfoundry.util.DelayUtils.exponentialBackOff; import static org.cloudfoundry.util.tuple.TupleUtils.function; -import static org.cloudfoundry.util.tuple.TupleUtils.predicate; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -41,14 +40,8 @@ import java.util.function.UnaryOperator; import java.util.stream.Collectors; import org.cloudfoundry.client.CloudFoundryClient; -import org.cloudfoundry.client.v2.OrderDirection; import org.cloudfoundry.client.v2.applications.AbstractApplicationResource; import org.cloudfoundry.client.v2.applications.ApplicationEntity; -import org.cloudfoundry.client.v2.applications.ApplicationInstanceInfo; -import org.cloudfoundry.client.v2.applications.ApplicationInstancesRequest; -import org.cloudfoundry.client.v2.applications.ApplicationInstancesResponse; -import org.cloudfoundry.client.v2.applications.ApplicationStatisticsRequest; -import org.cloudfoundry.client.v2.applications.ApplicationStatisticsResponse; import org.cloudfoundry.client.v2.applications.AssociateApplicationRouteRequest; import org.cloudfoundry.client.v2.applications.AssociateApplicationRouteResponse; import org.cloudfoundry.client.v2.applications.CopyApplicationRequest; @@ -57,7 +50,6 @@ import org.cloudfoundry.client.v2.applications.CreateApplicationResponse; import org.cloudfoundry.client.v2.applications.DockerCredentials; import org.cloudfoundry.client.v2.applications.InstanceStatistics; -import org.cloudfoundry.client.v2.applications.ListApplicationRoutesRequest; import org.cloudfoundry.client.v2.applications.ListApplicationServiceBindingsRequest; import org.cloudfoundry.client.v2.applications.RemoveApplicationRouteRequest; import org.cloudfoundry.client.v2.applications.RemoveApplicationServiceBindingRequest; @@ -70,9 +62,6 @@ import org.cloudfoundry.client.v2.applications.UploadApplicationRequest; import org.cloudfoundry.client.v2.applications.UploadApplicationResponse; import org.cloudfoundry.client.v2.applications.Usage; -import org.cloudfoundry.client.v2.events.EventEntity; -import org.cloudfoundry.client.v2.events.EventResource; -import org.cloudfoundry.client.v2.events.ListEventsRequest; import org.cloudfoundry.client.v2.organizations.ListOrganizationPrivateDomainsRequest; import org.cloudfoundry.client.v2.organizations.ListOrganizationSpacesRequest; import org.cloudfoundry.client.v2.organizations.ListOrganizationsRequest; @@ -100,12 +89,10 @@ import org.cloudfoundry.client.v2.spaces.ListSpaceServiceInstancesRequest; import org.cloudfoundry.client.v2.spaces.SpaceApplicationSummary; import org.cloudfoundry.client.v2.spaces.SpaceResource; -import org.cloudfoundry.client.v2.stacks.GetStackRequest; -import org.cloudfoundry.client.v2.stacks.GetStackResponse; -import org.cloudfoundry.client.v2.stacks.ListStacksRequest; -import org.cloudfoundry.client.v2.stacks.StackResource; import org.cloudfoundry.client.v3.BuildpackData; +import org.cloudfoundry.client.v3.CnbData; import org.cloudfoundry.client.v3.Lifecycle; +import org.cloudfoundry.client.v3.LifecycleData; import org.cloudfoundry.client.v3.Relationship; import org.cloudfoundry.client.v3.Resource; import org.cloudfoundry.client.v3.ToOneRelationship; @@ -113,20 +100,26 @@ import org.cloudfoundry.client.v3.applications.ApplicationResource; import org.cloudfoundry.client.v3.applications.GetApplicationEnvironmentRequest; import org.cloudfoundry.client.v3.applications.GetApplicationEnvironmentResponse; +import org.cloudfoundry.client.v3.applications.GetApplicationProcessRequest; +import org.cloudfoundry.client.v3.applications.GetApplicationProcessResponse; +import org.cloudfoundry.client.v3.applications.GetApplicationProcessStatisticsRequest; +import org.cloudfoundry.client.v3.applications.GetApplicationProcessStatisticsResponse; import org.cloudfoundry.client.v3.applications.GetApplicationResponse; import org.cloudfoundry.client.v3.applications.GetApplicationSshEnabledRequest; import org.cloudfoundry.client.v3.applications.GetApplicationSshEnabledResponse; -import org.cloudfoundry.client.v3.applications.ListApplicationProcessesRequest; +import org.cloudfoundry.client.v3.applications.ListApplicationRoutesRequest; import org.cloudfoundry.client.v3.applications.ListApplicationsRequest; import org.cloudfoundry.client.v3.applications.SetApplicationCurrentDropletRequest; +import org.cloudfoundry.client.v3.applications.UpdateApplicationEnvironmentVariablesRequest; +import org.cloudfoundry.client.v3.applications.UpdateApplicationEnvironmentVariablesResponse; import org.cloudfoundry.client.v3.applications.UpdateApplicationFeatureRequest; +import org.cloudfoundry.client.v3.auditevents.AuditEventResource; +import org.cloudfoundry.client.v3.auditevents.ListAuditEventsRequest; import org.cloudfoundry.client.v3.builds.BuildState; import org.cloudfoundry.client.v3.builds.CreateBuildRequest; import org.cloudfoundry.client.v3.builds.CreateBuildResponse; import org.cloudfoundry.client.v3.builds.GetBuildRequest; import org.cloudfoundry.client.v3.builds.GetBuildResponse; -import org.cloudfoundry.client.v3.domains.DomainResource; -import org.cloudfoundry.client.v3.domains.ListDomainsRequest; import org.cloudfoundry.client.v3.packages.BitsData; import org.cloudfoundry.client.v3.packages.CreatePackageRequest; import org.cloudfoundry.client.v3.packages.CreatePackageResponse; @@ -137,12 +130,18 @@ import org.cloudfoundry.client.v3.packages.PackageState; import org.cloudfoundry.client.v3.packages.PackageType; import org.cloudfoundry.client.v3.packages.UploadPackageRequest; -import org.cloudfoundry.client.v3.processes.GetProcessStatisticsRequest; -import org.cloudfoundry.client.v3.processes.GetProcessStatisticsResponse; +import org.cloudfoundry.client.v3.processes.HealthCheck; +import org.cloudfoundry.client.v3.processes.HealthCheckType; import org.cloudfoundry.client.v3.processes.ProcessState; import org.cloudfoundry.client.v3.processes.ProcessStatisticsResource; +import org.cloudfoundry.client.v3.processes.ProcessUsage; +import org.cloudfoundry.client.v3.processes.UpdateProcessRequest; import org.cloudfoundry.client.v3.resourcematch.MatchedResource; import org.cloudfoundry.client.v3.spaces.ApplyManifestRequest; +import org.cloudfoundry.client.v3.stacks.GetStackRequest; +import org.cloudfoundry.client.v3.stacks.GetStackResponse; +import org.cloudfoundry.client.v3.stacks.ListStacksRequest; +import org.cloudfoundry.client.v3.stacks.StackResource; import org.cloudfoundry.client.v3.tasks.CancelTaskRequest; import org.cloudfoundry.client.v3.tasks.CancelTaskResponse; import org.cloudfoundry.client.v3.tasks.CreateTaskRequest; @@ -159,7 +158,6 @@ import org.cloudfoundry.util.DelayTimeoutException; import org.cloudfoundry.util.ExceptionUtils; import org.cloudfoundry.util.FileUtils; -import org.cloudfoundry.util.FluentMap; import org.cloudfoundry.util.JobUtils; import org.cloudfoundry.util.PaginationUtils; import org.cloudfoundry.util.ResourceMatchingUtils; @@ -170,7 +168,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.util.function.Tuple2; -import reactor.util.function.Tuple5; +import reactor.util.function.Tuple4; import reactor.util.function.Tuples; public final class DefaultApplications implements Applications { @@ -210,26 +208,35 @@ public final class DefaultApplications implements Applications { private static final String APP_FEATURE_SSH = "ssh"; - private final Mono cloudFoundryClient; + private final CloudFoundryClient cloudFoundryClient; - private final Mono dopplerClient; + private final DopplerClient dopplerClient; private final RandomWords randomWords; - private final Mono spaceId; + private final String spaceId; + public DefaultApplications( + CloudFoundryClient cloudFoundryClient, DopplerClient dopplerClient, String spaceId) { + this(cloudFoundryClient, dopplerClient, new WordListRandomWords(), spaceId); + } + + /** + * @deprecated Please use {@link DefaultApplications(CloudFoundryClient, DopplerClient, String)} instead. + */ + @Deprecated public DefaultApplications( Mono cloudFoundryClient, Mono dopplerClient, Mono spaceId) { - this(cloudFoundryClient, dopplerClient, new WordListRandomWords(), spaceId); + this(cloudFoundryClient.block(), dopplerClient.block(), spaceId.block()); } DefaultApplications( - Mono cloudFoundryClient, - Mono dopplerClient, + CloudFoundryClient cloudFoundryClient, + DopplerClient dopplerClient, RandomWords randomWords, - Mono spaceId) { + String spaceId) { this.cloudFoundryClient = cloudFoundryClient; this.dopplerClient = dopplerClient; this.randomWords = randomWords; @@ -238,116 +245,56 @@ public DefaultApplications( @Override public Mono copySource(CopySourceApplicationRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplicationId( - cloudFoundryClient, - request.getName(), - spaceId), - getApplicationIdFromOrgSpace( - cloudFoundryClient, - request.getTargetName(), - spaceId, - request.getTargetOrganization(), - request.getTargetSpace())))) + return Mono.zip( + getApplicationId(request.getName()), + getApplicationIdFromOrgSpace( + request.getTargetName(), + this.spaceId, + request.getTargetOrganization(), + request.getTargetSpace())) .flatMap( function( - (cloudFoundryClient, sourceApplicationId, targetApplicationId) -> + (sourceApplicationId, targetApplicationId) -> copyBits( - cloudFoundryClient, request.getStagingTimeout(), sourceApplicationId, targetApplicationId) - .thenReturn( - Tuples.of( - cloudFoundryClient, - targetApplicationId)))) + .thenReturn(targetApplicationId))) .filter( - predicate( - (cloudFoundryClient, targetApplicationId) -> - Optional.ofNullable(request.getRestart()).orElse(false))) + targetApplicationId -> + Optional.ofNullable(request.getRestart()).orElse(false)) .flatMap( - function( - (cloudFoundryClient, targetApplicationId) -> - restartApplication( - cloudFoundryClient, - request.getTargetName(), - targetApplicationId, - request.getStagingTimeout(), - request.getStartupTimeout()))) + targetApplicationId -> + restartApplication( + request.getTargetName(), + targetApplicationId, + request.getStagingTimeout(), + request.getStartupTimeout())) .transform(OperationsLogging.log("Copy Application Source")) .checkpoint(); } @Override public Mono delete(DeleteApplicationRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - getRoutesAndApplicationId( - cloudFoundryClient, - request, - spaceId, - Optional.ofNullable( - request.getDeleteRoutes()) - .orElse(false)) - .map( - function( - (routes, applicationId) -> - Tuples.of( - cloudFoundryClient, - routes, - applicationId))))) + return getRoutesAndApplicationId( + request, Optional.ofNullable(request.getDeleteRoutes()).orElse(false)) .flatMap( function( - (cloudFoundryClient, routes, applicationId) -> - deleteRoutes( - cloudFoundryClient, - request.getCompletionTimeout(), - routes) - .thenReturn( - Tuples.of( - cloudFoundryClient, - applicationId)))) - .delayUntil(function(DefaultApplications::removeServiceBindings)) - .flatMap(function(DefaultApplications::requestDeleteApplication)) + (routes, applicationId) -> + deleteRoutes(request.getCompletionTimeout(), routes) + .thenReturn(applicationId))) + .delayUntil(this::removeServiceBindings) + .flatMap(this::requestDeleteApplication) .transform(OperationsLogging.log("Delete Application")) .checkpoint(); } @Override public Mono disableSsh(DisableApplicationSshRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplicationIdV3( - cloudFoundryClient, - request.getName(), - spaceId)))) - .flatMap( - function( - (cloudFoundryClient, applicationId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - Mono.just(applicationId), - getSshEnabled(cloudFoundryClient, applicationId)))) - .filter( - predicate( - (cloudFoundryClient, applicationId, sshEnabled) -> - sshEnabled.equals(true))) - .flatMap( - function( - (cloudFoundryClient, applicationId) -> - requestUpdateApplicationSsh( - cloudFoundryClient, applicationId, false))) + return getApplicationIdV3(request.getName()) + // TODO dgarnier: is this correct? + .filterWhen(applicationId -> getSshEnabled(applicationId)) + .flatMap(applicationId -> requestUpdateApplicationSsh(applicationId, false)) .then() .transform(OperationsLogging.log("Disable Application SSH")) .checkpoint(); @@ -355,32 +302,9 @@ public Mono disableSsh(DisableApplicationSshRequest request) { @Override public Mono enableSsh(EnableApplicationSshRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplicationIdV3( - cloudFoundryClient, - request.getName(), - spaceId)))) - .flatMap( - function( - (cloudFoundryClient, applicationId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - Mono.just(applicationId), - getSshEnabled(cloudFoundryClient, applicationId)))) - .filter( - predicate( - (cloudFoundryClient, applicationId, sshEnabled) -> - sshEnabled.equals(false))) - .flatMap( - function( - (cloudFoundryClient, applicationId) -> - requestUpdateApplicationSsh( - cloudFoundryClient, applicationId, true))) + return getApplicationIdV3(request.getName()) + .filterWhen(applicationId -> getSshEnabled(applicationId).map(enabled -> !enabled)) + .flatMap(applicationId -> requestUpdateApplicationSsh(applicationId, true)) .then() .transform(OperationsLogging.log("Enable Application SSH")) .checkpoint(); @@ -388,53 +312,30 @@ public Mono enableSsh(EnableApplicationSshRequest request) { @Override public Mono get(GetApplicationRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplication( - cloudFoundryClient, - request.getName(), - spaceId)))) - .flatMap(function(DefaultApplications::getAuxiliaryContent)) + return getApplicationV3(request.getName()) + .flatMap(this::getAuxiliaryContent) .map(function(DefaultApplications::toApplicationDetail)) .transform(OperationsLogging.log("Get Application")) .checkpoint(); } + // TODO dgarnier: manifest v3? @Override public Mono getApplicationManifest(GetApplicationManifestRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) + return getApplicationId(request.getName()) .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplicationId( - cloudFoundryClient, - request.getName(), - spaceId)))) - .flatMap( - function( - (cloudFoundryClient, applicationId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - Mono.just(applicationId), - requestApplicationSummary( - cloudFoundryClient, applicationId)))) + applicationId -> + Mono.zip( + Mono.just(applicationId), + requestApplicationSummary(applicationId))) .flatMap( function( - (cloudFoundryClient, applicationId, response) -> + (applicationId, summary) -> Mono.zip( - getApplicationBuildpacks( - cloudFoundryClient, applicationId), - Mono.just(response), - getStackName( - cloudFoundryClient, - response.getStackId())))) - .flatMap(function(DefaultApplications::toApplicationManifest)) + getApplicationBuildpacks(applicationId), + Mono.just(summary), + getStackName(summary.getStackId())))) + .flatMap(function(this::toApplicationManifest)) .transform(OperationsLogging.log("Get Application Manifest")) .checkpoint(); } @@ -442,17 +343,8 @@ public Mono getApplicationManifest(GetApplicationManifestRe @Override public Mono getEnvironments( GetApplicationEnvironmentsRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplicationIdV3( - cloudFoundryClient, - request.getName(), - spaceId)))) - .flatMap(function(DefaultApplications::requestApplicationEnvironment)) + return getApplicationIdV3(request.getName()) + .flatMap(applicationId -> requestApplicationEnvironment(applicationId)) .map(DefaultApplications::toApplicationEnvironments) .transform(OperationsLogging.log("Get Application Environments")) .checkpoint(); @@ -460,26 +352,13 @@ public Mono getEnvironments( @Override public Flux getEvents(GetApplicationEventsRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplicationId( - cloudFoundryClient, - request.getName(), - spaceId)))) + return getApplicationIdV3(request.getName()) .flatMapMany( - function( - (cloudFoundryClient, applicationId) -> - requestEvents(applicationId, cloudFoundryClient) - .take( - Optional.ofNullable( - request - .getMaxNumberOfEvents()) - .orElse( - MAX_NUMBER_OF_RECENT_EVENTS)))) + applicationId -> + requestEvents(applicationId) + .take( + Optional.ofNullable(request.getMaxNumberOfEvents()) + .orElse(MAX_NUMBER_OF_RECENT_EVENTS))) .map(DefaultApplications::convertToApplicationEvent) .transform(OperationsLogging.log("Get Application Events")) .checkpoint(); @@ -487,12 +366,11 @@ public Flux getEvents(GetApplicationEventsRequest request) { @Override public Mono getHealthCheck(GetApplicationHealthCheckRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - getApplication( - cloudFoundryClient, request.getName(), spaceId))) + return getApplicationV3(request.getName()) + .map(ApplicationResource::getId) + .flatMap(this::requestApplicationWebProcess) + .map(GetApplicationProcessResponse::getHealthCheck) + .map(HealthCheck::getType) .map(DefaultApplications::toHealthCheck) .transform(OperationsLogging.log("Get Application Health Check")) .checkpoint(); @@ -500,8 +378,7 @@ public Mono getHealthCheck(GetApplicationHealthCheckRequ @Override public Flux list() { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap(function(DefaultApplications::requestSpaceSummary)) + return requestSpaceSummary() .flatMapMany(DefaultApplications::extractApplications) .map(DefaultApplications::toApplicationSummary) .transform(OperationsLogging.log("List Applications")) @@ -510,20 +387,8 @@ public Flux list() { @Override public Flux listTasks(ListApplicationTasksRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplicationIdV3( - cloudFoundryClient, - request.getName(), - spaceId)))) - .flatMapMany( - function( - (cloudFoundryClient, applicationId) -> - requestListTasks(cloudFoundryClient, applicationId))) + return getApplicationIdV3(request.getName()) + .flatMapMany(applicationId -> requestListTasks(applicationId)) .map(DefaultApplications::toTask) .transform(OperationsLogging.log("List Application Tasks")) .checkpoint(); @@ -531,15 +396,8 @@ public Flux listTasks(ListApplicationTasksRequest request) { @Override public Flux logs(LogsRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - getApplicationId( - cloudFoundryClient, request.getName(), spaceId))) - .flatMapMany( - applicationId -> - getLogs(this.dopplerClient, applicationId, request.getRecent())) + return getApplicationIdV3(request.getName()) + .flatMapMany(applicationId -> getLogs(applicationId, request.getRecent())) .transform(OperationsLogging.log("Get Application Logs")) .checkpoint(); } @@ -610,55 +468,37 @@ public Mono push(PushApplicationRequest request) { .checkpoint(); } + // TODO dgarnier: pass orgId to constructor? @Override public Mono pushManifest(PushApplicationManifestRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getSpaceOrganizationId(cloudFoundryClient, spaceId), - Mono.just(spaceId)))) - .flatMap( - function( - (cloudFoundryClient, organizationId, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - listAvailableDomains( - cloudFoundryClient, organizationId), - Mono.just(spaceId)))) + return getSpaceOrganizationId(this.spaceId) + .flatMap(organizationId -> listAvailableDomains(organizationId)) .flatMapMany( - function( - (cloudFoundryClient, availableDomains, spaceId) -> - Flux.fromIterable(request.getManifests()) - .flatMap( - manifest -> { - if (manifest.getPath() != null) { - return pushApplication( - cloudFoundryClient, - availableDomains, - manifest, - this.randomWords, - request, - spaceId); - } else if (!manifest.getDocker() - .getImage() - .isEmpty()) { - return pushDocker( - cloudFoundryClient, - availableDomains, - manifest, - this.randomWords, - request, - spaceId); - } else { - throw new IllegalStateException( - "One of application or" - + " dockerImage must be" - + " supplied"); - } - }))) + availableDomains -> + Flux.fromIterable(request.getManifests()) + .flatMap( + manifest -> { + if (manifest.getPath() != null) { + return pushApplication( + availableDomains, + manifest, + this.randomWords, + request); + } else if (!manifest.getDocker() + .getImage() + .isEmpty()) { + return pushDocker( + availableDomains, + manifest, + this.randomWords, + request); + } else { + throw new IllegalStateException( + "One of application or" + + " dockerImage must be" + + " supplied"); + } + })) .then() .transform(OperationsLogging.log("Push Manifest")) .checkpoint(); @@ -674,74 +514,34 @@ public Mono pushManifestV3(PushManifestV3Request request) { throw new RuntimeException("Could not serialize manifest", e); } - return Mono.zip(this.cloudFoundryClient, this.spaceId) + return applyManifestAndWaitForCompletion(manifestSerialized) + .flatMapMany(ignored -> Flux.fromIterable(request.getManifest().getApplications())) .flatMap( - function( - (cloudFoundryClient, spaceId) -> - applyManifestAndWaitForCompletion( - cloudFoundryClient, - spaceId, - manifestSerialized) - .then( - Mono.just( - Tuples.of( - cloudFoundryClient, - spaceId))))) - .flatMapMany( - function( - (cloudFoundryClient, spaceId) -> - Flux.fromIterable(request.getManifest().getApplications()) - .map( - manifestApp -> - Tuples.of( - cloudFoundryClient, - spaceId, - manifestApp)))) - .flatMap( - function( - (cloudFoundryClient, spaceId, manifestApp) -> - getApplicationIdV3( - cloudFoundryClient, - manifestApp.getName(), - spaceId) - .flatMap( - appId -> - Mono.zip( - Mono.just(appId), - createPackage( - cloudFoundryClient, - appId, - manifestApp))) - .flatMap( - function( - (appId, packageId) -> - buildAndStageAndWaitForRunning( - cloudFoundryClient, - manifestApp, - packageId, - appId))))) + manifestApp -> + getApplicationIdV3(manifestApp.getName()) + .flatMap( + appId -> + Mono.zip( + Mono.just(appId), + createPackage(appId, manifestApp))) + .flatMap( + function( + (appId, packageId) -> + buildAndStageAndWaitForRunning( + manifestApp, + packageId, + appId)))) .then(); } @Override public Mono rename(RenameApplicationRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplicationId( - cloudFoundryClient, - request.getName(), - spaceId)))) + return getApplicationIdV3(request.getName()) .flatMap( - function( - (cloudFoundryClient, applicationId) -> - requestUpdateApplicationName( - cloudFoundryClient, - applicationId, - request.getNewName()))) + applicationId -> + requestUpdateApplicationV3( + applicationId, + builder -> builder.name(request.getNewName()))) .then() .transform(OperationsLogging.log("Rename Application")) .checkpoint(); @@ -749,101 +549,48 @@ public Mono rename(RenameApplicationRequest request) { @Override public Mono restage(RestageApplicationRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) + return getApplicationId(request.getName()) .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplicationId( - cloudFoundryClient, - request.getName(), - spaceId)))) - .flatMap( - function( - (cloudFoundryClient, applicationId) -> - restageApplication( - cloudFoundryClient, - request.getName(), - applicationId, - request.getStagingTimeout(), - request.getStartupTimeout()))) + applicationId -> + restageApplication( + request.getName(), + applicationId, + request.getStagingTimeout(), + request.getStartupTimeout())) .transform(OperationsLogging.log("Restage Application")) .checkpoint(); } @Override public Mono restart(RestartApplicationRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplication( - cloudFoundryClient, - request.getName(), - spaceId)))) - .flatMap( - function( - (cloudFoundryClient, resource) -> - Mono.zip( - Mono.just(cloudFoundryClient), - stopApplicationIfNotStopped( - cloudFoundryClient, resource)))) + return getApplication(request.getName()) + .flatMap(resource -> stopApplicationIfNotStopped(resource)) .flatMap( - function( - (cloudFoundryClient, stoppedApplication) -> - startApplicationAndWait( - cloudFoundryClient, - request.getName(), - ResourceUtils.getId(stoppedApplication), - request.getStagingTimeout(), - request.getStartupTimeout()))) + stoppedApplication -> + startApplicationAndWait( + request.getName(), + ResourceUtils.getId(stoppedApplication), + request.getStagingTimeout(), + request.getStartupTimeout())) .transform(OperationsLogging.log("Restart Application")) .checkpoint(); } @Override public Mono restartInstance(RestartApplicationInstanceRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) + return getApplicationId(request.getName()) .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplicationId( - cloudFoundryClient, - request.getName(), - spaceId)))) - .flatMap( - function( - (cloudFoundryClient, applicationId) -> - requestTerminateApplicationInstance( - cloudFoundryClient, - applicationId, - String.valueOf(request.getInstanceIndex())))) + applicationId -> + requestTerminateApplicationInstance( + applicationId, String.valueOf(request.getInstanceIndex()))) .transform(OperationsLogging.log("Restart Application Instance")) .checkpoint(); } @Override public Mono runTask(RunApplicationTaskRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplicationIdV3( - cloudFoundryClient, - request.getApplicationName(), - spaceId)))) - .flatMap( - function( - (cloudFoundryClient, applicationId) -> - requestCreateTask( - cloudFoundryClient, applicationId, request))) + return getApplicationIdV3(request.getApplicationName()) + .flatMap(applicationId -> requestCreateTask(applicationId, request)) .map(DefaultApplications::toTask) .transform(OperationsLogging.log("Run Application Task Instance")) .checkpoint(); @@ -851,164 +598,67 @@ public Mono runTask(RunApplicationTaskRequest request) { @Override public Mono scale(ScaleApplicationRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .filter(predicate((cloudFoundryClient, spaceId) -> areModifiersPresent(request))) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplicationId( - cloudFoundryClient, - request.getName(), - spaceId)))) + if (!areModifiersPresent(request)) { + return Mono.empty(); + } + return getApplicationId(request.getName()) .flatMap( - function( - (cloudFoundryClient, applicationId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - requestUpdateApplicationScale( - cloudFoundryClient, - applicationId, - request.getDiskLimit(), - request.getInstances(), - request.getMemoryLimit())))) - .filter( - predicate( - (cloudFoundryClient, resource) -> - isRestartRequired(request, resource))) + applicationId -> + requestUpdateApplicationScale( + applicationId, + request.getDiskLimit(), + request.getInstances(), + request.getMemoryLimit())) + .filter(resource -> isRestartRequired(request, resource)) .flatMap( - function( - (cloudFoundryClient, resource) -> - restartApplication( - cloudFoundryClient, - request.getName(), - ResourceUtils.getId(resource), - request.getStagingTimeout(), - request.getStartupTimeout()))) + resource -> + restartApplication( + request.getName(), + ResourceUtils.getId(resource), + request.getStagingTimeout(), + request.getStartupTimeout())) .transform(OperationsLogging.log("Scale Application")) .checkpoint(); } - @Override - public Mono setEnvironmentVariable(SetEnvironmentVariableApplicationRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplication( - cloudFoundryClient, - request.getName(), - spaceId)))) - .flatMap( - function( - (cloudFoundryClient, resource) -> - requestUpdateApplicationEnvironment( - cloudFoundryClient, - ResourceUtils.getId(resource), - addToEnvironment( - getEnvironment(resource), - request.getVariableName(), - request.getVariableValue())))) - .then() - .transform(OperationsLogging.log("Set Application Environment Variable")) - .checkpoint(); - } - @Override public Mono setHealthCheck(SetApplicationHealthCheckRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplicationId( - cloudFoundryClient, - request.getName(), - spaceId)))) + return getApplicationIdV3(request.getName()) + .flatMap(this::requestApplicationWebProcess) .flatMap( - function( - (cloudFoundryClient, applicationId) -> - requestUpdateApplicationHealthCheckType( - cloudFoundryClient, - applicationId, - request.getType()))) - .then() + webProcess -> + this.requestUpdateProcessHealthCheckType( + webProcess.getId(), fromHealthCheck(request.getType()))) .transform(OperationsLogging.log("Set Application Health Check")) .checkpoint(); } @Override public Mono sshEnabled(ApplicationSshEnabledRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplicationIdV3( - cloudFoundryClient, - request.getName(), - spaceId)))) - .flatMap(function(DefaultApplications::getSshEnabled)) + return getApplicationIdV3(request.getName()) + .flatMap(applicationId -> getSshEnabled(applicationId)) .transform(OperationsLogging.log("Is Application SSH Enabled")) .checkpoint(); } - private static Mono getSshEnabled( - CloudFoundryClient cloudFoundryClient, String applicationId) { - return cloudFoundryClient - .applicationsV3() - .getSshEnabled( - GetApplicationSshEnabledRequest.builder() - .applicationId(applicationId) - .build()) - .map(GetApplicationSshEnabledResponse::getEnabled); - } - @Override public Mono start(StartApplicationRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) + return getApplicationIdWhere(request.getName(), isNotIn(STARTED_STATE)) .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplicationIdWhere( - cloudFoundryClient, - request.getName(), - spaceId, - isNotIn(STARTED_STATE))))) - .flatMap( - function( - (cloudFoundryClient, applicationId) -> - startApplicationAndWait( - cloudFoundryClient, - request.getName(), - applicationId, - request.getStagingTimeout(), - request.getStartupTimeout()))) + applicationId -> + startApplicationAndWait( + request.getName(), + applicationId, + request.getStagingTimeout(), + request.getStartupTimeout())) .transform(OperationsLogging.log("Start Application")) .checkpoint(); } @Override public Mono stop(StopApplicationRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplicationIdWhere( - cloudFoundryClient, - request.getName(), - spaceId, - isNotIn(STOPPED_STATE))))) - .flatMap(function(DefaultApplications::stopApplication)) + return getApplicationIdWhere(request.getName(), isNotIn(STOPPED_STATE)) + .flatMap(applicationId -> stopApplication(applicationId)) .then() .transform(OperationsLogging.log("Stop Application")) .checkpoint(); @@ -1016,68 +666,48 @@ public Mono stop(StopApplicationRequest request) { @Override public Mono terminateTask(TerminateApplicationTaskRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplicationIdV3( - cloudFoundryClient, - request.getApplicationName(), - spaceId)))) - .flatMap( - function( - (cloudFoundryClient, applicationId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getTaskId( - cloudFoundryClient, - applicationId, - request.getSequenceId())))) - .flatMap(function(DefaultApplications::requestTerminateTask)) + return getApplicationIdV3(request.getApplicationName()) + .flatMap(applicationId -> getTaskId(applicationId, request.getSequenceId())) + .flatMap(taskId -> requestTerminateTask(taskId)) .then() .transform(OperationsLogging.log("Terminate Application Task Instance")) .checkpoint(); } @Override - public Mono unsetEnvironmentVariable(UnsetEnvironmentVariableApplicationRequest request) { - return Mono.zip(this.cloudFoundryClient, this.spaceId) - .flatMap( - function( - (cloudFoundryClient, spaceId) -> - Mono.zip( - Mono.just(cloudFoundryClient), - getApplication( - cloudFoundryClient, - request.getName(), - spaceId)))) + public Mono setEnvironmentVariable(SetEnvironmentVariableApplicationRequest request) { + return getApplicationIdV3(request.getName()) .flatMap( - function( - (cloudFoundryClient, resource) -> - requestUpdateApplicationEnvironment( - cloudFoundryClient, - ResourceUtils.getId(resource), - removeFromEnvironment( - getEnvironment(resource), - request.getVariableName())))) + id -> + requestSetEnvironmentVariable( + id, request.getVariableName(), request.getVariableValue())) + .then() + .transform(OperationsLogging.log("Set Application Environment Variable")) + .checkpoint(); + } + + @Override + public Mono unsetEnvironmentVariable(UnsetEnvironmentVariableApplicationRequest request) { + return getApplicationIdV3(request.getName()) + .flatMap(id -> requestUnsetEnvironmentVariable(id, request.getVariableName())) .then() .transform(OperationsLogging.log("Unset Application Environment Variable")) .checkpoint(); } - private static Map addToEnvironment( - Map environment, String variableName, Object variableValue) { - return FluentMap.builder() - .entries(environment) - .entry(variableName, variableValue) - .build(); + private Mono getSshEnabled(String applicationId) { + return this.cloudFoundryClient + .applicationsV3() + .getSshEnabled( + GetApplicationSshEnabledRequest.builder() + .applicationId(applicationId) + .build()) + .map(GetApplicationSshEnabledResponse::getEnabled); } - private static Mono applyDropletAndWaitForRunning( - CloudFoundryClient cloudFoundryClient, String appname, String appId, String dropletId) { - return cloudFoundryClient + private Mono applyDropletAndWaitForRunning( + String appname, String appId, String dropletId) { + return this.cloudFoundryClient .applicationsV3() .setCurrentDroplet( SetApplicationCurrentDropletRequest.builder() @@ -1085,24 +715,23 @@ private static Mono applyDropletAndWaitForRunning( .data(Relationship.builder().id(dropletId).build()) .build()) .then( - cloudFoundryClient + this.cloudFoundryClient .applicationsV3() .restart( org.cloudfoundry.client.v3.applications .RestartApplicationRequest.builder() .applicationId(appId) .build())) - .then(waitForRunningV3(cloudFoundryClient, appname, appId, null)); + .then(waitForRunningV3(appname, appId, null)); } - private static Mono applyManifestAndWaitForCompletion( - CloudFoundryClient cloudFoundryClient, String spaceId, byte[] manifestSerialized) { - return cloudFoundryClient + private Mono applyManifestAndWaitForCompletion(byte[] manifestSerialized) { + return this.cloudFoundryClient .spacesV3() .applyManifest( ApplyManifestRequest.builder() .manifest(manifestSerialized) - .spaceId(spaceId) + .spaceId(this.spaceId) .build()) .map( response -> @@ -1115,7 +744,7 @@ private static Mono applyManifestAndWaitForCompletion( .flatMap( jobId -> JobUtils.waitForCompletion( - cloudFoundryClient, Duration.ofMinutes(5), jobId)); + this.cloudFoundryClient, Duration.ofMinutes(5), jobId)); } private static boolean areModifiersPresent(ScaleApplicationRequest request) { @@ -1124,84 +753,54 @@ private static boolean areModifiersPresent(ScaleApplicationRequest request) { || request.getInstances() != null; } - private static Flux associateDefaultDomain( - CloudFoundryClient cloudFoundryClient, + private Flux associateDefaultDomain( String applicationId, List availableDomains, ApplicationManifest manifest, - RandomWords randomWords, - String spaceId) { - return getDefaultDomainId(cloudFoundryClient) + RandomWords randomWords) { + return getDefaultDomainId() .flatMapMany( domainId -> getPushRouteIdFromDomain( - cloudFoundryClient, - availableDomains, - domainId, - manifest, - randomWords, - spaceId)) - .flatMap( - routeId -> - requestAssociateRoute(cloudFoundryClient, applicationId, routeId)) + availableDomains, domainId, manifest, randomWords)) + .flatMap(routeId -> requestAssociateRoute(applicationId, routeId)) .map(ResourceUtils::getId); } - private static Mono bindServices( - CloudFoundryClient cloudFoundryClient, - String applicationId, - ApplicationManifest manifest, - String spaceId) { + private Mono bindServices(String applicationId, ApplicationManifest manifest) { if (manifest.getServices() == null || manifest.getServices().size() == 0) { return Mono.empty(); } return Flux.fromIterable(manifest.getServices()) - .flatMap( - serviceInstanceName -> - getServiceId(cloudFoundryClient, serviceInstanceName, spaceId)) + .flatMap(serviceInstanceName -> getServiceId(serviceInstanceName)) .flatMap( serviceInstanceId -> - requestCreateServiceBinding( - cloudFoundryClient, - applicationId, - serviceInstanceId) + requestCreateServiceBinding(applicationId, serviceInstanceId) .onErrorResume( ExceptionUtils.statusCode(CF_SERVICE_ALREADY_BOUND), t -> Mono.empty())) .then(); } - private static Mono buildAndStageAndWaitForRunning( - CloudFoundryClient cloudFoundryClient, - ManifestV3Application manifestApp, - String packageId, - String appId) { - return buildAndStage(cloudFoundryClient, manifestApp, packageId) + private Mono buildAndStageAndWaitForRunning( + ManifestV3Application manifestApp, String packageId, String appId) { + return buildAndStage(manifestApp, packageId) .flatMap( dropletId -> applyDropletAndWaitForRunning( - cloudFoundryClient, - manifestApp.getName(), - appId, - dropletId)); + manifestApp.getName(), appId, dropletId)); } - private static Mono buildAndStage( - CloudFoundryClient cloudFoundryClient, - ManifestV3Application manifestApp, - String packageId) { - return cloudFoundryClient + private Mono buildAndStage(ManifestV3Application manifestApp, String packageId) { + return this.cloudFoundryClient .builds() .create( CreateBuildRequest.builder() .getPackage(Relationship.builder().id(packageId).build()) .build()) .map(CreateBuildResponse::getId) - .flatMap( - buildId -> - waitForBuildStaging( - cloudFoundryClient, buildId, manifestApp.getName(), null)) + .flatMap(buildId -> waitForBuildStaging(buildId, manifestApp.getName(), null)) .map(build -> build.getDroplet().getId()); } @@ -1209,57 +808,51 @@ private static String cleanName(ApplicationManifest manifest) { return manifest.getName().replaceAll("\\.", ""); } - private static BiFunction collectStates() { + public static BiFunction collectStates() { return (totalState, instanceState) -> { - if ("RUNNING".equals(instanceState) || "RUNNING".equals(totalState)) { - return "RUNNING"; + if (ProcessState.RUNNING.equals(instanceState) + || ProcessState.RUNNING.equals(totalState)) { + return ProcessState.RUNNING; } - if ("FLAPPING".equals(instanceState) || "CRASHED".equals(instanceState)) { - return "FAILED"; + if (ProcessState.CRASHED.equals(instanceState)) { + return ProcessState.CRASHED; } return totalState; }; } - private static ApplicationEvent convertToApplicationEvent(EventResource resource) { - EventEntity entity = resource.getEntity(); + private static ApplicationEvent convertToApplicationEvent(AuditEventResource entity) { Date timestamp = null; try { - timestamp = DateUtils.parseFromIso8601(entity.getTimestamp()); + timestamp = DateUtils.parseFromIso8601(entity.getCreatedAt()); } catch (IllegalArgumentException iae) { // do not set time } return ApplicationEvent.builder() - .actor(entity.getActorName()) + .actor(entity.getAuditEventActor().getName()) .description( eventDescription( getMetadataRequest(entity), getEntryNames(entity.getType()))) - .id(ResourceUtils.getId(resource)) + .id(entity.getId()) .event(entity.getType()) .time(timestamp) .build(); } - private static Mono copyBits( - CloudFoundryClient cloudFoundryClient, - Duration completionTimeout, - String sourceApplicationId, - String targetApplicationId) { - return requestCopyBits(cloudFoundryClient, sourceApplicationId, targetApplicationId) + private Mono copyBits( + Duration completionTimeout, String sourceApplicationId, String targetApplicationId) { + return requestCopyBits(sourceApplicationId, targetApplicationId) .flatMap( job -> JobUtils.waitForCompletion( - cloudFoundryClient, completionTimeout, job)); + this.cloudFoundryClient, completionTimeout, job)); } - private static Mono createPackage( - CloudFoundryClient cloudFoundryClient, - String appId, - ManifestV3Application manifestApp) { + private Mono createPackage(String appId, ManifestV3Application manifestApp) { if (manifestApp.getDocker() != null) { - return cloudFoundryClient + return this.cloudFoundryClient .packages() .create( CreatePackageRequest.builder() @@ -1283,7 +876,7 @@ private static Mono createPackage( .build()) .map(CreatePackageResponse::getId); } else { - return cloudFoundryClient + return this.cloudFoundryClient .packages() .create( CreatePackageRequest.builder() @@ -1310,11 +903,10 @@ private static Mono createPackage( .flatMap( packageId -> ResourceMatchingUtilsV3.getMatchedResources( - cloudFoundryClient, manifestApp.getPath()) + this.cloudFoundryClient, manifestApp.getPath()) .flatMap( matchedResources -> uploadPackageBitsAndWait( - cloudFoundryClient, packageId, manifestApp.getPath(), matchedResources, @@ -1323,23 +915,21 @@ private static Mono createPackage( } } - private static Mono deleteRoute( - CloudFoundryClient cloudFoundryClient, String routeId, Duration completionTimeout) { - return requestDeleteRoute(cloudFoundryClient, routeId) + private Mono deleteRoute(String routeId, Duration completionTimeout) { + return requestDeleteRoute(routeId) .flatMap( job -> JobUtils.waitForCompletion( - cloudFoundryClient, completionTimeout, job)); + this.cloudFoundryClient, completionTimeout, job)); } - private static Mono deleteRoutes( - CloudFoundryClient cloudFoundryClient, + private Mono deleteRoutes( Duration completionTimeout, Optional> routes) { return routes.map(Flux::fromIterable) .orElse(Flux.empty()) .map(org.cloudfoundry.client.v2.routes.Route::getId) - .flatMap(routeId -> deleteRoute(cloudFoundryClient, routeId, completionTimeout)) + .flatMap(routeId -> deleteRoute(routeId, completionTimeout)) .then(); } @@ -1384,7 +974,7 @@ private static String eventDescription(Map request, String... en sb.append(", "); } first = false; - sb.append(entryName).append(": ").append(String.valueOf(value)); + sb.append(entryName).append(": ").append(value); } return sb.toString(); } @@ -1394,9 +984,12 @@ private static Flux extractApplications( return Flux.fromIterable(getSpaceSummaryResponse.getApplications()); } - private static Mono getApplication( - CloudFoundryClient cloudFoundryClient, String application, String spaceId) { - return requestApplications(cloudFoundryClient, application, spaceId) + private Mono getApplication(String application) { + return getApplication(application, spaceId); + } + + private Mono getApplication(String application, String spaceId) { + return requestApplications(application, spaceId) .single() .onErrorResume( NoSuchElementException.class, @@ -1405,9 +998,8 @@ private static Mono getApplication( "Application %s does not exist", application)); } - private static Mono> getApplicationBuildpacks( - CloudFoundryClient cloudFoundryClient, String applicationId) { - return cloudFoundryClient + private Mono> getApplicationBuildpacks(String applicationId) { + return this.cloudFoundryClient .applicationsV3() .get( org.cloudfoundry.client.v3.applications.GetApplicationRequest.builder() @@ -1421,17 +1013,16 @@ private static Mono> getApplicationBuildpacks( .defaultIfEmpty(Collections.emptyList()); } - private static Mono getApplicationId( - CloudFoundryClient cloudFoundryClient, String application, String spaceId) { - return getApplication(cloudFoundryClient, application, spaceId).map(ResourceUtils::getId); + private Mono getApplicationId(String application) { + return getApplicationId(application, spaceId); } - private static Mono getApplicationId( - CloudFoundryClient cloudFoundryClient, - ApplicationManifest manifest, - String spaceId, - String stackId) { - return requestApplications(cloudFoundryClient, manifest.getName(), spaceId) + private Mono getApplicationId(String application, String spaceId) { + return getApplication(application, spaceId).map(ResourceUtils::getId); + } + + private Mono getApplicationId(ApplicationManifest manifest, String stackId) { + return requestApplications(manifest.getName()) .singleOrEmpty() .flatMap( application -> { @@ -1444,7 +1035,6 @@ private static Mono getApplicationId( .ifPresent(merge::putAll); return requestUpdateApplication( - cloudFoundryClient, ResourceUtils.getId(application), merge, manifest, @@ -1452,76 +1042,41 @@ private static Mono getApplicationId( .map(ResourceUtils::getId); }) .switchIfEmpty( - requestCreateApplication(cloudFoundryClient, manifest, spaceId, stackId) - .map(ResourceUtils::getId)); + requestCreateApplication(manifest, stackId).map(ResourceUtils::getId)); } - private static Mono getApplicationIdFromOrgSpace( - CloudFoundryClient cloudFoundryClient, - String application, - String spaceId, - String organization, - String space) { - return getSpaceOrganizationId(cloudFoundryClient, spaceId) + private Mono getApplicationIdFromOrgSpace( + String application, String spaceId, String organization, String space) { + return getSpaceOrganizationId(spaceId) .flatMap( organizationId -> organization != null - ? getOrganizationId(cloudFoundryClient, organization) + ? getOrganizationId(organization) : Mono.just(organizationId)) .flatMap( organizationId -> space != null - ? getSpaceId(cloudFoundryClient, organizationId, space) + ? getSpaceId(organizationId, space) : Mono.just(spaceId)) - .flatMap(spaceId1 -> getApplicationId(cloudFoundryClient, application, spaceId1)); - } - - private static Mono getApplicationIdV3( - CloudFoundryClient cloudFoundryClient, String applicationName, String spaceId) { - return getApplicationV3(cloudFoundryClient, applicationName, spaceId) - .map(ApplicationResource::getId); + .flatMap(spaceId1 -> getApplicationId(application, spaceId1)); } - private static Mono getApplicationIdWhere( - CloudFoundryClient cloudFoundryClient, - String application, - String spaceId, - Predicate predicate) { - return getApplication(cloudFoundryClient, application, spaceId) - .filter(predicate) - .map(ResourceUtils::getId); - } - - private static Mono getApplicationInstances( - CloudFoundryClient cloudFoundryClient, String applicationId) { - return requestApplicationInstances(cloudFoundryClient, applicationId) - .onErrorResume( - ExceptionUtils.statusCode( - CF_BUILDPACK_COMPILED_FAILED, - CF_INSTANCES_ERROR, - CF_STAGING_NOT_FINISHED, - CF_STAGING_TIME_EXPIRED, - CF_INSUFFICIENT_RESOURCES, - CF_STAGING_ERROR), - t -> Mono.just(ApplicationInstancesResponse.builder().build())); + private Mono getApplicationIdV3(String applicationName) { + return getApplicationV3(applicationName).map(ApplicationResource::getId); } - private static Mono> getApplicationRoutes( - CloudFoundryClient cloudFoundryClient, String applicationId) { - return requestApplicationRoutes(cloudFoundryClient, applicationId).collectList(); + private Mono getApplicationIdWhere( + String application, Predicate predicate) { + return getApplication(application).filter(predicate).map(ResourceUtils::getId); } - private static Mono getApplicationStatistics( - CloudFoundryClient cloudFoundryClient, String applicationId) { - return requestApplicationStatistics(cloudFoundryClient, applicationId) - .onErrorResume( - ExceptionUtils.statusCode(CF_APP_STOPPED_STATS_ERROR), - t -> Mono.just(ApplicationStatisticsResponse.builder().build())); + private Mono> getApplicationRoutes( + String applicationId) { + return requestApplicationRoutes(applicationId).collectList(); } - private static Mono getApplicationV3( - CloudFoundryClient cloudFoundryClient, String application, String spaceId) { - return requestApplicationsV3(cloudFoundryClient, application, spaceId) + private Mono getApplicationV3(String application) { + return requestApplicationsV3(application) .single() .onErrorResume( NoSuchElementException.class, @@ -1530,41 +1085,29 @@ private static Mono getApplicationV3( "Application %s does not exist", application)); } - private static Mono< - Tuple5< - List, - SummaryApplicationResponse, - GetStackResponse, - List, - List>> - getAuxiliaryContent( - CloudFoundryClient cloudFoundryClient, - AbstractApplicationResource applicationResource) { - String applicationId = ResourceUtils.getId(applicationResource); - String stackId = ResourceUtils.getEntity(applicationResource).getStackId(); + private Mono, SummaryApplicationResponse, String, List>> + getAuxiliaryContent(ApplicationResource applicationResource) { + String applicationId = applicationResource.getId(); + LifecycleData data = applicationResource.getLifecycle().getData(); + String stackName = ""; + if (data instanceof CnbData) { + stackName = ((CnbData) data).getStack(); + } else if (data instanceof BuildpackData) { + stackName = ((BuildpackData) data).getStack(); + } + + Mono> appInstanceDetails = + requestApplicationStatisticsV3(applicationId).map(this::toInstanceDetailList); return Mono.zip( - getApplicationStatistics(cloudFoundryClient, applicationId), - requestApplicationSummary(cloudFoundryClient, applicationId), - getApplicationInstances(cloudFoundryClient, applicationId)) - .flatMap( - function( - (applicationStatisticsResponse, - summaryApplicationResponse, - applicationInstancesResponse) -> - Mono.zip( - getApplicationBuildpacks( - cloudFoundryClient, applicationId), - Mono.just(summaryApplicationResponse), - requestStack(cloudFoundryClient, stackId), - toInstanceDetailList( - applicationInstancesResponse, - applicationStatisticsResponse), - toUrls(summaryApplicationResponse.getRoutes())))); - } - - private static Mono getDefaultDomainId(CloudFoundryClient cloudFoundryClient) { - return requestSharedDomains(cloudFoundryClient) + getApplicationBuildpacks(applicationId), + requestApplicationSummary(applicationId), + Mono.just(stackName), + appInstanceDetails); + } + + private Mono getDefaultDomainId() { + return requestSharedDomains() .filter( resource -> !Optional.ofNullable( @@ -1590,26 +1133,21 @@ private static String[] getEntryNames(String type) { return type.contains("crash") ? ENTRY_FIELDS_CRASH : ENTRY_FIELDS_NORMAL; } - private static Map getEnvironment(AbstractApplicationResource resource) { - return ResourceUtils.getEntity(resource).getEnvironmentJsons(); - } - private static int getInstances(AbstractApplicationResource resource) { return Optional.ofNullable(resource.getEntity()) .map(ApplicationEntity::getInstances) .orElse(0); } - private static Flux getLogs( - Mono dopplerClient, String applicationId, Boolean recent) { + private Flux getLogs(String applicationId, Boolean recent) { if (Optional.ofNullable(recent).orElse(false)) { - return requestLogsRecent(dopplerClient, applicationId) + return requestLogsRecent(applicationId) .filter(e -> EventType.LOG_MESSAGE == e.getEventType()) .map(Envelope::getLogMessage) .collectSortedList(LOG_MESSAGE_COMPARATOR) .flatMapIterable(d -> d); } else { - return requestLogsStream(dopplerClient, applicationId) + return requestLogsStream(applicationId) .filter(e -> EventType.LOG_MESSAGE == e.getEventType()) .map(Envelope::getLogMessage) .transformDeferred( @@ -1618,41 +1156,36 @@ private static Flux getLogs( } @SuppressWarnings("unchecked") - private static Map getMetadataRequest(EventEntity entity) { - Map> metadata = - Optional.ofNullable(entity.getMetadatas()).orElse(Collections.emptyMap()); + private static Map getMetadataRequest(AuditEventResource entity) { + Map metadata = + Optional.ofNullable(entity.getData()).orElse(Collections.emptyMap()); if (metadata.get("request") != null) { - return metadata.get("request") - .map(m -> (Map) m) - .orElse(Collections.emptyMap()); + return (Map) metadata.getOrDefault("request", Collections.emptyMap()); } else if (metadata.get("instance") != null) { - return metadata.entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, v -> v.getValue().orElse(""))); + return Collections.unmodifiableMap(metadata); } else { return Collections.emptyMap(); } } - private static Mono>> getOptionalRoutes( - CloudFoundryClient cloudFoundryClient, boolean deleteRoutes, String applicationId) { + private Mono>> getOptionalRoutes( + boolean deleteRoutes, String applicationId) { if (deleteRoutes) { - return getRoutes(cloudFoundryClient, applicationId).map(Optional::of); + return getRoutes(applicationId).map(Optional::of); } else { return Mono.just(Optional.empty()); } } - private static Mono> getOptionalStackId( - CloudFoundryClient cloudFoundryClient, String stack) { + private Mono> getOptionalStackId(String stack) { return Optional.ofNullable(stack) - .map(stack1 -> getStackId(cloudFoundryClient, stack1).map(Optional::of)) + .map(stack1 -> getStackId(stack1).map(Optional::of)) .orElse(Mono.just(Optional.empty())); } - private static Mono getOrganization( - CloudFoundryClient cloudFoundryClient, String organization) { - return requestOrganizations(cloudFoundryClient, organization) + private Mono getOrganization(String organization) { + return requestOrganizations(organization) .single() .onErrorResume( NoSuchElementException.class, @@ -1661,14 +1194,12 @@ private static Mono getOrganization( "Organization %s not found", organization)); } - private static Mono getOrganizationId( - CloudFoundryClient cloudFoundryClient, String organization) { - return getOrganization(cloudFoundryClient, organization).map(ResourceUtils::getId); + private Mono getOrganizationId(String organization) { + return getOrganization(organization).map(ResourceUtils::getId); } - private static Mono getOrganizationSpaceByName( - CloudFoundryClient cloudFoundryClient, String organizationId, String space) { - return requestOrganizationSpacesByName(cloudFoundryClient, organizationId, space) + private Mono getOrganizationSpaceByName(String organizationId, String space) { + return requestOrganizationSpacesByName(organizationId, space) .single() .onErrorResume( NoSuchElementException.class, @@ -1681,17 +1212,13 @@ private static String getPassword(DockerCredentials dockerCredentials) { .orElse(null); } - private static Flux getPushRouteIdFromDomain( - CloudFoundryClient cloudFoundryClient, + private Flux getPushRouteIdFromDomain( List availableDomains, String domainId, ApplicationManifest manifest, - RandomWords randomWords, - String spaceId) { + RandomWords randomWords) { if (isTcpDomain(availableDomains, domainId)) { - return requestCreateTcpRoute(cloudFoundryClient, domainId, spaceId) - .map(ResourceUtils::getId) - .flux(); + return requestCreateTcpRoute(domainId).map(ResourceUtils::getId).flux(); } List hosts; @@ -1715,27 +1242,19 @@ private static Flux getPushRouteIdFromDomain( return Flux.fromIterable(hosts) .flatMap( host -> - getRouteId( - cloudFoundryClient, - domainId, - host, - manifest.getRoutePath()) + getRouteId(domainId, host, manifest.getRoutePath()) .switchIfEmpty( requestCreateRoute( - cloudFoundryClient, domainId, host, - manifest.getRoutePath(), - spaceId) + manifest.getRoutePath()) .map(ResourceUtils::getId))); } - private static Flux getPushRouteIdFromRoute( - CloudFoundryClient cloudFoundryClient, + private Flux getPushRouteIdFromRoute( List availableDomains, ApplicationManifest manifest, - RandomWords randomWords, - String spaceId) { + RandomWords randomWords) { return Flux.fromIterable(manifest.getRoutes()) .flatMap( route -> @@ -1748,27 +1267,16 @@ private static Flux getPushRouteIdFromRoute( String domainId = getDomainId(availableDomains, decomposedRoute.getDomain()); if (isTcpDomain(availableDomains, domainId)) { - return getRouteIdForTcpRoute( - cloudFoundryClient, - decomposedRoute, - domainId, - manifest, - spaceId); + return getRouteIdForTcpRoute(decomposedRoute, domainId, manifest); } else { return getRouteIdForHttpRoute( - cloudFoundryClient, - decomposedRoute, - domainId, - manifest, - randomWords, - spaceId); + decomposedRoute, domainId, manifest, randomWords); } }); } - private static Mono getRouteId( - CloudFoundryClient cloudFoundryClient, String domainId, String host, String routePath) { - return requestRoutes(cloudFoundryClient, domainId, host, null, routePath) + private Mono getRouteId(String domainId, String host, String routePath) { + return requestRoutes(domainId, host, null, routePath) .filter(resource -> isIdentical(host, ResourceUtils.getEntity(resource).getHost())) .filter( resource -> @@ -1779,68 +1287,45 @@ private static Mono getRouteId( .map(ResourceUtils::getId); } - private static Mono getRouteIdForHttpRoute( - CloudFoundryClient cloudFoundryClient, + private Mono getRouteIdForHttpRoute( DecomposedRoute decomposedRoute, String domainId, ApplicationManifest manifest, - RandomWords randomWords, - String spaceId) { + RandomWords randomWords) { String derivedHost = deriveHostname(decomposedRoute.getHost(), manifest, randomWords); - return getRouteId(cloudFoundryClient, domainId, derivedHost, decomposedRoute.getPath()) + return getRouteId(domainId, derivedHost, decomposedRoute.getPath()) .switchIfEmpty( - requestCreateRoute( - cloudFoundryClient, - domainId, - derivedHost, - decomposedRoute.getPath(), - spaceId) + requestCreateRoute(domainId, derivedHost, decomposedRoute.getPath()) .map(ResourceUtils::getId)); } - private static Mono getRouteIdForTcpRoute( - CloudFoundryClient cloudFoundryClient, - DecomposedRoute decomposedRoute, - String domainId, - ApplicationManifest manifest, - String spaceId) { + private Mono getRouteIdForTcpRoute( + DecomposedRoute decomposedRoute, String domainId, ApplicationManifest manifest) { if (Optional.ofNullable(manifest.getRandomRoute()).orElse(false)) { - return requestCreateTcpRoute(cloudFoundryClient, domainId, spaceId) - .map(ResourceUtils::getId); + return requestCreateTcpRoute(domainId).map(ResourceUtils::getId); } - return getTcpRouteId(cloudFoundryClient, domainId, decomposedRoute.getPort()) + return getTcpRouteId(domainId, decomposedRoute.getPort()) .switchIfEmpty( - requestCreateTcpRoute( - cloudFoundryClient, - domainId, - decomposedRoute.getPort(), - spaceId) + requestCreateTcpRoute(domainId, decomposedRoute.getPort()) .map(ResourceUtils::getId)); } - private static Mono> getRoutes( - CloudFoundryClient cloudFoundryClient, String applicationId) { - return requestApplicationSummary(cloudFoundryClient, applicationId) - .map(SummaryApplicationResponse::getRoutes); + private Mono> getRoutes(String applicationId) { + return requestApplicationSummary(applicationId).map(SummaryApplicationResponse::getRoutes); } - private static Mono>, String>> - getRoutesAndApplicationId( - CloudFoundryClient cloudFoundryClient, - DeleteApplicationRequest request, - String spaceId, - boolean deleteRoutes) { - return getApplicationId(cloudFoundryClient, request.getName(), spaceId) + private Mono>, String>> + getRoutesAndApplicationId(DeleteApplicationRequest request, boolean deleteRoutes) { + return getApplicationId(request.getName()) .flatMap( applicationId -> - getOptionalRoutes(cloudFoundryClient, deleteRoutes, applicationId) + getOptionalRoutes(deleteRoutes, applicationId) .zipWith(Mono.just(applicationId))); } - private static Mono getServiceId( - CloudFoundryClient cloudFoundryClient, String serviceInstanceName, String spaceId) { - return requestListServiceInstances(cloudFoundryClient, serviceInstanceName, spaceId) + private Mono getServiceId(String serviceInstanceName) { + return requestListServiceInstances(serviceInstanceName) .map(ResourceUtils::getId) .single() .onErrorResume( @@ -1851,36 +1336,33 @@ private static Mono getServiceId( serviceInstanceName)); } - private static Mono getSpaceId( - CloudFoundryClient cloudFoundryClient, String organizationId, String space) { - return getOrganizationSpaceByName(cloudFoundryClient, organizationId, space) - .map(ResourceUtils::getId); + private Mono getSpaceId(String organizationId, String space) { + return getOrganizationSpaceByName(organizationId, space).map(ResourceUtils::getId); } - private static Mono getSpaceOrganizationId( - CloudFoundryClient cloudFoundryClient, String spaceId) { - return requestSpace(cloudFoundryClient, spaceId) + private Mono getSpaceOrganizationId(String spaceId) { + return requestSpace(spaceId) .map(response -> ResourceUtils.getEntity(response).getOrganizationId()); } - private static Mono getStackId(CloudFoundryClient cloudFoundryClient, String stack) { - return requestStacks(cloudFoundryClient, stack) - .map(ResourceUtils::getId) + private Mono getStackId(String stackName) { + return requestStacks(stackName) + .map(StackResource::getId) .single() .onErrorResume( NoSuchElementException.class, - t -> ExceptionUtils.illegalArgument("Stack %s does not exist", stack)); + t -> ExceptionUtils.illegalArgument("Stack %s does not exist", stackName)); } - private static Mono getStackName( - CloudFoundryClient cloudFoundryClient, String stackId) { - return requestStack(cloudFoundryClient, stackId) - .map(getStackResponse -> getStackResponse.getEntity().getName()); + private Mono getStackName(String stackId) { + return this.cloudFoundryClient + .stacksV3() + .get(GetStackRequest.builder().stackId(stackId).build()) + .map(GetStackResponse::getName); } - private static Mono getTaskId( - CloudFoundryClient cloudFoundryClient, String applicationId, Integer sequenceId) { - return listTasks(cloudFoundryClient, applicationId, sequenceId) + private Mono getTaskId(String applicationId, Integer sequenceId) { + return listTasks(applicationId, sequenceId) .single() .map(Resource::getId) .onErrorResume( @@ -1890,11 +1372,8 @@ private static Mono getTaskId( "Task with sequence id of %s does not exist", sequenceId)); } - private static Mono getTcpRouteId( - CloudFoundryClient cloudFoundryClient, String domainId, Integer port) { - return requestRoutes(cloudFoundryClient, domainId, null, port, null) - .singleOrEmpty() - .map(ResourceUtils::getId); + private Mono getTcpRouteId(String domainId, Integer port) { + return requestRoutes(domainId, null, port, null).singleOrEmpty().map(ResourceUtils::getId); } private static String getUsername(DockerCredentials dockerCredentials) { @@ -1907,8 +1386,8 @@ private static boolean isIdentical(String s, String t) { return Objects.equals(s, t); } - private static Predicate isInstanceComplete() { - return state -> "RUNNING".equals(state) || "FAILED".equals(state); + private static Predicate isInstanceComplete() { + return state -> ProcessState.RUNNING.equals(state) || ProcessState.CRASHED.equals(state); } private static Predicate isNotIn(String expectedState) { @@ -1925,8 +1404,8 @@ private static boolean isRestartRequired( && STARTED_STATE.equals(ResourceUtils.getEntity(applicationResource).getState()); } - private static Predicate isRunning() { - return "RUNNING"::equals; + private static Predicate isRunning() { + return ProcessState.RUNNING::equals; } private static Predicate isStaged() { @@ -1947,37 +1426,29 @@ private static boolean isTcpDomain(List availableDomains, String return tcpDomainIds.contains(domainId); } - private static Mono> listAvailableDomains( - CloudFoundryClient cloudFoundryClient, String organizationId) { - return requestListPrivateDomains(cloudFoundryClient, organizationId) + private Mono> listAvailableDomains(String organizationId) { + return requestListPrivateDomains(organizationId) .map(DefaultApplications::toDomain) - .mergeWith( - requestListSharedDomains(cloudFoundryClient) - .map(DefaultApplications::toDomain)) + .mergeWith(requestListSharedDomains().map(DefaultApplications::toDomain)) .collectList(); } - private static Flux listTasks( - CloudFoundryClient cloudFoundryClient, String applicationId, Integer sequenceId) { - return requestListTasks(cloudFoundryClient, applicationId, sequenceId) + private Flux listTasks( + String applicationId, Integer sequenceId) { + return requestListTasks(applicationId, sequenceId) .cast(org.cloudfoundry.client.v3.tasks.Task.class); } - private static Mono prepareDomainsAndRoutes( - CloudFoundryClient cloudFoundryClient, + private Mono prepareDomainsAndRoutes( String applicationId, List availableDomains, ApplicationManifest manifest, - List existingRoutes, - RandomWords randomWords, - String spaceId) { + List existingRoutes, + RandomWords randomWords) { if (Optional.ofNullable(manifest.getNoRoute()).orElse(false)) { return Flux.fromIterable(existingRoutes) - .map(ResourceUtils::getId) - .flatMap( - routeId -> - requestRemoveRouteFromApplication( - cloudFoundryClient, applicationId, routeId)) + .map(org.cloudfoundry.client.v3.routes.RouteResource::getId) + .flatMap(routeId -> requestRemoveRouteFromApplication(applicationId, routeId)) .then(); } @@ -1985,12 +1456,7 @@ private static Mono prepareDomainsAndRoutes( if (manifest.getDomains() == null) { if (existingRoutes.isEmpty()) { return associateDefaultDomain( - cloudFoundryClient, - applicationId, - availableDomains, - manifest, - randomWords, - spaceId) + applicationId, availableDomains, manifest, randomWords) .then(); } return Mono.empty(); // A route already exists for the application, do nothing @@ -1999,68 +1465,52 @@ private static Mono prepareDomainsAndRoutes( .flatMap( domain -> getPushRouteIdFromDomain( - cloudFoundryClient, availableDomains, getDomainId(availableDomains, domain), manifest, - randomWords, - spaceId) + randomWords) .flatMap( routeId -> requestAssociateRoute( - cloudFoundryClient, - applicationId, - routeId))) + applicationId, routeId))) .then(); } List existingRouteIds = - existingRoutes.stream().map(ResourceUtils::getId).collect(Collectors.toList()); + existingRoutes.stream() + .map(org.cloudfoundry.client.v3.routes.RouteResource::getId) + .collect(Collectors.toList()); - return getPushRouteIdFromRoute( - cloudFoundryClient, availableDomains, manifest, randomWords, spaceId) + return getPushRouteIdFromRoute(availableDomains, manifest, randomWords) .filter(routeId -> !existingRouteIds.contains(routeId)) - .flatMapSequential( - routeId -> - requestAssociateRoute(cloudFoundryClient, applicationId, routeId), - 1) + .flatMapSequential(routeId -> requestAssociateRoute(applicationId, routeId), 1) .then(); } - private static Flux pushApplication( - CloudFoundryClient cloudFoundryClient, + private Flux pushApplication( List availableDomains, ApplicationManifest manifest, RandomWords randomWords, - PushApplicationManifestRequest request, - String spaceId) { + PushApplicationManifestRequest request) { - return getOptionalStackId(cloudFoundryClient, manifest.getStack()) - .flatMapMany( - stackId -> - getApplicationId( - cloudFoundryClient, - manifest, - spaceId, - stackId.orElse(null))) + return getOptionalStackId(manifest.getStack()) + .flatMapMany(stackId -> getApplicationId(manifest, stackId.orElse(null))) .flatMap( applicationId -> Mono.zip( Mono.just(applicationId), - getApplicationRoutes(cloudFoundryClient, applicationId), + getApplicationRoutes(applicationId), ResourceMatchingUtils.getMatchedResources( - cloudFoundryClient, manifest.getPath()))) + this.cloudFoundryClient, manifest.getPath()))) .flatMap( function( (applicationId, existingRoutes, matchedResources) -> prepareDomainsAndRoutes( - cloudFoundryClient, applicationId, availableDomains, manifest, existingRoutes, - randomWords, - spaceId) + randomWords) .thenReturn( Tuples.of( applicationId, matchedResources)))) @@ -2068,17 +1518,9 @@ private static Flux pushApplication( function( (applicationId, matchedResources) -> Mono.when( - bindServices( - cloudFoundryClient, - applicationId, - manifest, - spaceId), - updateBuildpacks( - cloudFoundryClient, - applicationId, - manifest), + bindServices(applicationId, manifest), + updateBuildpacks(applicationId, manifest), uploadApplicationAndWait( - cloudFoundryClient, applicationId, manifest.getPath(), matchedResources, @@ -2087,78 +1529,51 @@ private static Flux pushApplication( .flatMap( applicationId -> stopAndStartApplication( - cloudFoundryClient, - applicationId, - manifest.getName(), - request)); + applicationId, manifest.getName(), request)); } - private static Flux pushDocker( - CloudFoundryClient cloudFoundryClient, + private Flux pushDocker( List availableDomains, ApplicationManifest manifest, RandomWords randomWords, - PushApplicationManifestRequest request, - String spaceId) { + PushApplicationManifestRequest request) { - return getOptionalStackId(cloudFoundryClient, manifest.getStack()) - .flatMapMany( - stackId -> - getApplicationId( - cloudFoundryClient, - manifest, - spaceId, - stackId.orElse(null))) + return getOptionalStackId(manifest.getStack()) + .flatMapMany(stackId -> getApplicationId(manifest, stackId.orElse(null))) .flatMap( applicationId -> Mono.zip( Mono.just(applicationId), - getApplicationRoutes(cloudFoundryClient, applicationId))) + getApplicationRoutes(applicationId))) .flatMap( function( (applicationId, existingRoutes) -> prepareDomainsAndRoutes( - cloudFoundryClient, applicationId, availableDomains, manifest, existingRoutes, - randomWords, - spaceId) + randomWords) .thenReturn(applicationId))) - .delayUntil( - applicationId -> - bindServices(cloudFoundryClient, applicationId, manifest, spaceId)) + .delayUntil(applicationId -> bindServices(applicationId, manifest)) .flatMap( applicationId -> stopAndStartApplication( - cloudFoundryClient, - applicationId, - manifest.getName(), - request)); + applicationId, manifest.getName(), request)); } - private static Map removeFromEnvironment( - Map environment, String variableName) { - Map modified = new HashMap<>(environment); - modified.remove(variableName); - return modified; - } - - private static Mono removeServiceBindings( - CloudFoundryClient cloudFoundryClient, String applicationId) { - return requestListServiceBindings(cloudFoundryClient, applicationId) + private Mono removeServiceBindings(String applicationId) { + return requestListServiceBindings(applicationId) .map(ResourceUtils::getId) .flatMap( serviceBindingId -> - requestRemoveServiceBinding( - cloudFoundryClient, applicationId, serviceBindingId)) + requestRemoveServiceBinding(applicationId, serviceBindingId)) .then(); } - private static Mono requestApplicationEnvironment( - CloudFoundryClient cloudFoundryClient, String applicationId) { - return cloudFoundryClient + private Mono requestApplicationEnvironment( + String applicationId) { + return this.cloudFoundryClient .applicationsV3() .getEnvironment( GetApplicationEnvironmentRequest.builder() @@ -2166,20 +1581,63 @@ private static Mono requestApplicationEnviron .build()); } - private static Mono requestApplicationInstances( - CloudFoundryClient cloudFoundryClient, String applicationId) { - return cloudFoundryClient - .applicationsV2() - .instances( - ApplicationInstancesRequest.builder().applicationId(applicationId).build()); + private Mono requestApplicationStatisticsV3( + String applicationId) { + return this.cloudFoundryClient + .applicationsV3() + .getProcessStatistics( + GetApplicationProcessStatisticsRequest.builder() + .applicationId(applicationId) + .type("web") + .build()) + .onErrorResume( + ExceptionUtils.statusCodeV3( + CF_BUILDPACK_COMPILED_FAILED, + CF_INSTANCES_ERROR, + CF_STAGING_NOT_FINISHED, + CF_STAGING_TIME_EXPIRED, + CF_INSUFFICIENT_RESOURCES, + CF_STAGING_ERROR, + // NOTE: this used to be an error from the v2 API apps/instances + // endpoint. It probably does not apply to the v3 processes/stats + // endpoint, but it is hard to test. Leaving it in, worst case this + // never gets triggered. + CF_APP_STOPPED_STATS_ERROR), + t -> + Mono.just( + GetApplicationProcessStatisticsResponse.builder() + .resources() + .build())); } - private static Flux requestApplicationRoutes( - CloudFoundryClient cloudFoundryClient, String applicationId) { - return PaginationUtils.requestClientV2Resources( + private Mono requestApplicationWebProcess(String applicationId) { + return this.cloudFoundryClient + .applicationsV3() + .getProcess( + GetApplicationProcessRequest.builder() + .applicationId(applicationId) + .type("web") + .build()); + } + + private Mono requestUpdateProcessHealthCheckType( + String processId, HealthCheckType healthCheckType) { + return this.cloudFoundryClient + .processes() + .update( + UpdateProcessRequest.builder() + .processId(processId) + .healthCheck(HealthCheck.builder().type(healthCheckType).build()) + .build()) + .then(); + } + + private Flux requestApplicationRoutes( + String applicationId) { + return PaginationUtils.requestClientV3Resources( page -> - cloudFoundryClient - .applicationsV2() + this.cloudFoundryClient + .applicationsV3() .listRoutes( ListApplicationRoutesRequest.builder() .applicationId(applicationId) @@ -2187,28 +1645,21 @@ private static Flux requestApplicationRoutes( .build())); } - private static Mono requestApplicationStatistics( - CloudFoundryClient cloudFoundryClient, String applicationId) { - return cloudFoundryClient + private Mono requestApplicationSummary(String applicationId) { + return this.cloudFoundryClient .applicationsV2() - .statistics( - ApplicationStatisticsRequest.builder() - .applicationId(applicationId) - .build()); + .summary(SummaryApplicationRequest.builder().applicationId(applicationId).build()); } - private static Mono requestApplicationSummary( - CloudFoundryClient cloudFoundryClient, String applicationId) { - return cloudFoundryClient - .applicationsV2() - .summary(SummaryApplicationRequest.builder().applicationId(applicationId).build()); + private Flux requestApplications(String application) { + return requestApplications(application, spaceId); } - private static Flux requestApplications( - CloudFoundryClient cloudFoundryClient, String application, String spaceId) { + private Flux requestApplications( + String application, String spaceId) { return PaginationUtils.requestClientV2Resources( page -> - cloudFoundryClient + this.cloudFoundryClient .spaces() .listApplications( ListSpaceApplicationsRequest.builder() @@ -2219,23 +1670,22 @@ private static Flux requestApplications( .cast(AbstractApplicationResource.class); } - private static Flux requestApplicationsV3( - CloudFoundryClient cloudFoundryClient, String application, String spaceId) { + private Flux requestApplicationsV3(String application) { return PaginationUtils.requestClientV3Resources( page -> - cloudFoundryClient + this.cloudFoundryClient .applicationsV3() .list( ListApplicationsRequest.builder() .name(application) - .spaceId(spaceId) + .spaceId(this.spaceId) .page(page) .build())); } - private static Mono requestAssociateRoute( - CloudFoundryClient cloudFoundryClient, String applicationId, String routeId) { - return cloudFoundryClient + private Mono requestAssociateRoute( + String applicationId, String routeId) { + return this.cloudFoundryClient .applicationsV2() .associateRoute( AssociateApplicationRouteRequest.builder() @@ -2244,11 +1694,9 @@ private static Mono requestAssociateRoute( .build()); } - private static Mono requestCopyBits( - CloudFoundryClient cloudFoundryClient, - String sourceApplicationId, - String targetApplicationId) { - return cloudFoundryClient + private Mono requestCopyBits( + String sourceApplicationId, String targetApplicationId) { + return this.cloudFoundryClient .applicationsV2() .copy( CopyApplicationRequest.builder() @@ -2257,11 +1705,8 @@ private static Mono requestCopyBits( .build()); } - private static Mono requestCreateApplication( - CloudFoundryClient cloudFoundryClient, - ApplicationManifest manifest, - String spaceId, - String stackId) { + private Mono requestCreateApplication( + ApplicationManifest manifest, String stackId) { CreateApplicationRequest.Builder builder = CreateApplicationRequest.builder() .command(manifest.getCommand()) @@ -2276,7 +1721,7 @@ private static Mono requestCreateApplication( .instances(manifest.getInstances()) .memory(manifest.getMemory()) .name(manifest.getName()) - .spaceId(spaceId) + .spaceId(this.spaceId) .stackId(stackId); if (manifest.getBuildpacks() != null && manifest.getBuildpacks().size() == 1) { @@ -2299,29 +1744,25 @@ private static Mono requestCreateApplication( }); } - return cloudFoundryClient.applicationsV2().create(builder.build()); + return this.cloudFoundryClient.applicationsV2().create(builder.build()); } - private static Mono requestCreateRoute( - CloudFoundryClient cloudFoundryClient, - String domainId, - String host, - String routePath, - String spaceId) { - return cloudFoundryClient + private Mono requestCreateRoute( + String domainId, String host, String routePath) { + return this.cloudFoundryClient .routes() .create( org.cloudfoundry.client.v2.routes.CreateRouteRequest.builder() .domainId(domainId) .host(host) .path(routePath) - .spaceId(spaceId) + .spaceId(this.spaceId) .build()); } - private static Mono requestCreateServiceBinding( - CloudFoundryClient cloudFoundryClient, String applicationId, String serviceInstanceId) { - return cloudFoundryClient + private Mono requestCreateServiceBinding( + String applicationId, String serviceInstanceId) { + return this.cloudFoundryClient .serviceBindingsV2() .create( CreateServiceBindingRequest.builder() @@ -2330,11 +1771,9 @@ private static Mono requestCreateServiceBinding( .build()); } - private static Mono requestCreateTask( - CloudFoundryClient cloudFoundryClient, - String applicationId, - RunApplicationTaskRequest request) { - return cloudFoundryClient + private Mono requestCreateTask( + String applicationId, RunApplicationTaskRequest request) { + return this.cloudFoundryClient .tasks() .create( CreateTaskRequest.builder() @@ -2346,33 +1785,30 @@ private static Mono requestCreateTask( .build()); } - private static Mono requestCreateTcpRoute( - CloudFoundryClient cloudFoundryClient, String domainId, String spaceId) { - return cloudFoundryClient + private Mono requestCreateTcpRoute(String domainId) { + return this.cloudFoundryClient .routes() .create( org.cloudfoundry.client.v2.routes.CreateRouteRequest.builder() .domainId(domainId) .generatePort(true) - .spaceId(spaceId) + .spaceId(this.spaceId) .build()); } - private static Mono requestCreateTcpRoute( - CloudFoundryClient cloudFoundryClient, String domainId, Integer port, String spaceId) { - return cloudFoundryClient + private Mono requestCreateTcpRoute(String domainId, Integer port) { + return this.cloudFoundryClient .routes() .create( org.cloudfoundry.client.v2.routes.CreateRouteRequest.builder() .domainId(domainId) .port(port) - .spaceId(spaceId) + .spaceId(this.spaceId) .build()); } - private static Mono requestDeleteApplication( - CloudFoundryClient cloudFoundryClient, String applicationId) { - return cloudFoundryClient + private Mono requestDeleteApplication(String applicationId) { + return this.cloudFoundryClient .applicationsV2() .delete( org.cloudfoundry.client.v2.applications.DeleteApplicationRequest.builder() @@ -2380,31 +1816,28 @@ private static Mono requestDeleteApplication( .build()); } - private static Mono requestDeleteRoute( - CloudFoundryClient cloudFoundryClient, String routeId) { - return cloudFoundryClient + private Mono requestDeleteRoute(String routeId) { + return this.cloudFoundryClient .routes() .delete(DeleteRouteRequest.builder().async(true).routeId(routeId).build()); } - private static Flux requestEvents( - String applicationId, CloudFoundryClient cloudFoundryClient) { - return PaginationUtils.requestClientV2Resources( + private Flux requestEvents(String applicationId) { + return PaginationUtils.requestClientV3Resources( page -> - cloudFoundryClient - .events() + this.cloudFoundryClient + .auditEventsV3() .list( - ListEventsRequest.builder() - .actee(applicationId) - .orderDirection(OrderDirection.DESCENDING) - .resultsPerPage(50) + ListAuditEventsRequest.builder() + .targetId(applicationId) + .orderBy("-created_at") + .perPage(50) .page(page) .build())); } - private static Mono requestGetApplication( - CloudFoundryClient cloudFoundryClient, String applicationId) { - return cloudFoundryClient + private Mono requestGetApplication(String applicationId) { + return this.cloudFoundryClient .applicationsV2() .get( org.cloudfoundry.client.v2.applications.GetApplicationRequest.builder() @@ -2413,20 +1846,10 @@ private static Mono requestGetApplication( .cast(AbstractApplicationResource.class); } - private static Flux requestListDomains( - CloudFoundryClient cloudFoundryClient, String organizationId) { - return PaginationUtils.requestClientV3Resources( - page -> - cloudFoundryClient - .domainsV3() - .list(ListDomainsRequest.builder().page(page).build())); - } - - private static Flux requestListPrivateDomains( - CloudFoundryClient cloudFoundryClient, String organizationId) { + private Flux requestListPrivateDomains(String organizationId) { return PaginationUtils.requestClientV2Resources( page -> - cloudFoundryClient + this.cloudFoundryClient .organizations() .listPrivateDomains( ListOrganizationPrivateDomainsRequest.builder() @@ -2435,11 +1858,10 @@ private static Flux requestListPrivateDomains( .build())); } - private static Flux requestListServiceBindings( - CloudFoundryClient cloudFoundryClient, String applicationId) { + private Flux requestListServiceBindings(String applicationId) { return PaginationUtils.requestClientV2Resources( page -> - cloudFoundryClient + this.cloudFoundryClient .applicationsV2() .listServiceBindings( ListApplicationServiceBindingsRequest.builder() @@ -2448,35 +1870,33 @@ private static Flux requestListServiceBindings( .build())); } - private static Flux requestListServiceInstances( - CloudFoundryClient cloudFoundryClient, String serviceInstanceName, String spaceId) { + private Flux requestListServiceInstances( + String serviceInstanceName) { return PaginationUtils.requestClientV2Resources( page -> - cloudFoundryClient + this.cloudFoundryClient .spaces() .listServiceInstances( ListSpaceServiceInstancesRequest.builder() .page(page) .returnUserProvidedServiceInstances(true) .name(serviceInstanceName) - .spaceId(spaceId) + .spaceId(this.spaceId) .build())); } - private static Flux requestListSharedDomains( - CloudFoundryClient cloudFoundryClient) { + private Flux requestListSharedDomains() { return PaginationUtils.requestClientV2Resources( page -> - cloudFoundryClient + this.cloudFoundryClient .sharedDomains() .list(ListSharedDomainsRequest.builder().page(page).build())); } - private static Flux requestListTasks( - CloudFoundryClient cloudFoundryClient, String applicationId) { + private Flux requestListTasks(String applicationId) { return PaginationUtils.requestClientV3Resources( page -> - cloudFoundryClient + this.cloudFoundryClient .applicationsV3() .listTasks( org.cloudfoundry.client.v3.applications @@ -2486,11 +1906,10 @@ private static Flux requestListTasks( .build())); } - private static Flux requestListTasks( - CloudFoundryClient cloudFoundryClient, String applicationId, Integer sequenceId) { + private Flux requestListTasks(String applicationId, Integer sequenceId) { return PaginationUtils.requestClientV3Resources( page -> - cloudFoundryClient + this.cloudFoundryClient .applicationsV3() .listTasks( org.cloudfoundry.client.v3.applications @@ -2501,27 +1920,20 @@ private static Flux requestListTasks( .build())); } - private static Flux requestLogsRecent( - Mono dopplerClient, String applicationId) { - return dopplerClient.flatMapMany( - client -> - client.recentLogs( - RecentLogsRequest.builder().applicationId(applicationId).build())); + private Flux requestLogsRecent(String applicationId) { + return dopplerClient.recentLogs( + RecentLogsRequest.builder().applicationId(applicationId).build()); } - private static Flux requestLogsStream( - Mono dopplerClient, String applicationId) { - return dopplerClient.flatMapMany( - client -> - client.stream( - StreamRequest.builder().applicationId(applicationId).build())); + private Flux requestLogsStream(String applicationId) { + return dopplerClient.stream(StreamRequest.builder().applicationId(applicationId).build()); } - private static Flux requestOrganizationSpacesByName( - CloudFoundryClient cloudFoundryClient, String organizationId, String space) { + private Flux requestOrganizationSpacesByName( + String organizationId, String space) { return PaginationUtils.requestClientV2Resources( page -> - cloudFoundryClient + this.cloudFoundryClient .organizations() .listSpaces( ListOrganizationSpacesRequest.builder() @@ -2531,11 +1943,10 @@ private static Flux requestOrganizationSpacesByName( .build())); } - private static Flux requestOrganizations( - CloudFoundryClient cloudFoundryClient, String organization) { + private Flux requestOrganizations(String organization) { return PaginationUtils.requestClientV2Resources( page -> - cloudFoundryClient + this.cloudFoundryClient .organizations() .list( ListOrganizationsRequest.builder() @@ -2544,9 +1955,8 @@ private static Flux requestOrganizations( .build())); } - private static Mono requestRemoveRouteFromApplication( - CloudFoundryClient cloudFoundryClient, String applicationId, String routeId) { - return cloudFoundryClient + private Mono requestRemoveRouteFromApplication(String applicationId, String routeId) { + return this.cloudFoundryClient .applicationsV2() .removeRoute( RemoveApplicationRouteRequest.builder() @@ -2555,9 +1965,8 @@ private static Mono requestRemoveRouteFromApplication( .build()); } - private static Mono requestRemoveServiceBinding( - CloudFoundryClient cloudFoundryClient, String applicationId, String serviceBindingId) { - return cloudFoundryClient + private Mono requestRemoveServiceBinding(String applicationId, String serviceBindingId) { + return this.cloudFoundryClient .applicationsV2() .removeServiceBinding( RemoveApplicationServiceBindingRequest.builder() @@ -2566,9 +1975,8 @@ private static Mono requestRemoveServiceBinding( .build()); } - private static Mono requestRestageApplication( - CloudFoundryClient cloudFoundryClient, String applicationId) { - return cloudFoundryClient + private Mono requestRestageApplication(String applicationId) { + return this.cloudFoundryClient .applicationsV2() .restage( org.cloudfoundry.client.v2.applications.RestageApplicationRequest.builder() @@ -2576,59 +1984,48 @@ private static Mono requestRestageApplication( .build()); } - private static Flux requestRoutes( - CloudFoundryClient cloudFoundryClient, - String domainId, - String host, - Integer port, - String routePath) { + private Flux requestRoutes( + String domainId, String host, Integer port, String routePath) { ListRoutesRequest.Builder requestBuilder = ListRoutesRequest.builder().domainId(domainId); Optional.ofNullable(host).ifPresent(requestBuilder::host); Optional.ofNullable(routePath).ifPresent(requestBuilder::path); Optional.ofNullable(port).ifPresent(requestBuilder::port); return PaginationUtils.requestClientV2Resources( - page -> cloudFoundryClient.routes().list(requestBuilder.page(page).build())); + page -> this.cloudFoundryClient.routes().list(requestBuilder.page(page).build())); } - private static Flux requestSharedDomains( - CloudFoundryClient cloudFoundryClient) { + private Flux requestSharedDomains() { return PaginationUtils.requestClientV2Resources( page -> - cloudFoundryClient + this.cloudFoundryClient .sharedDomains() .list(ListSharedDomainsRequest.builder().page(page).build())); } - private static Mono requestSpace( - CloudFoundryClient cloudFoundryClient, String spaceId) { - return cloudFoundryClient.spaces().get(GetSpaceRequest.builder().spaceId(spaceId).build()); - } - - private static Mono requestSpaceSummary( - CloudFoundryClient cloudFoundryClient, String spaceId) { - return cloudFoundryClient + private Mono requestSpace(String spaceId) { + return this.cloudFoundryClient .spaces() - .getSummary(GetSpaceSummaryRequest.builder().spaceId(spaceId).build()); + .get(GetSpaceRequest.builder().spaceId(spaceId).build()); } - private static Mono requestStack( - CloudFoundryClient cloudFoundryClient, String stackId) { - return cloudFoundryClient.stacks().get(GetStackRequest.builder().stackId(stackId).build()); + private Mono requestSpaceSummary() { + return this.cloudFoundryClient + .spaces() + .getSummary(GetSpaceSummaryRequest.builder().spaceId(this.spaceId).build()); } - private static Flux requestStacks( - CloudFoundryClient cloudFoundryClient, String stack) { - return PaginationUtils.requestClientV2Resources( + private Flux requestStacks(String stack) { + return PaginationUtils.requestClientV3Resources( page -> - cloudFoundryClient - .stacks() + this.cloudFoundryClient + .stacksV3() .list(ListStacksRequest.builder().page(page).name(stack).build())); } - private static Mono requestTerminateApplicationInstance( - CloudFoundryClient cloudFoundryClient, String applicationId, String instanceIndex) { - return cloudFoundryClient + private Mono requestTerminateApplicationInstance( + String applicationId, String instanceIndex) { + return this.cloudFoundryClient .applicationsV2() .terminateInstance( TerminateApplicationInstanceRequest.builder() @@ -2637,21 +2034,18 @@ private static Mono requestTerminateApplicationInstance( .build()); } - private static Mono requestTerminateTask( - CloudFoundryClient cloudFoundryClient, String taskId) { - return cloudFoundryClient + private Mono requestTerminateTask(String taskId) { + return this.cloudFoundryClient .tasks() .cancel(CancelTaskRequest.builder().taskId(taskId).build()); } - private static Mono requestUpdateApplication( - CloudFoundryClient cloudFoundryClient, + private Mono requestUpdateApplication( String applicationId, Map environmentJsons, ApplicationManifest manifest, String stackId) { return requestUpdateApplication( - cloudFoundryClient, applicationId, builder -> { builder.command(manifest.getCommand()) @@ -2692,11 +2086,9 @@ private static Mono requestUpdateApplication( }); } - private static Mono requestUpdateApplication( - CloudFoundryClient cloudFoundryClient, - String applicationId, - UnaryOperator modifier) { - return cloudFoundryClient + private Mono requestUpdateApplication( + String applicationId, UnaryOperator modifier) { + return this.cloudFoundryClient .applicationsV2() .update( modifier.apply( @@ -2706,45 +2098,52 @@ private static Mono requestUpdateApplication( .cast(AbstractApplicationResource.class); } - private static Mono requestUpdateApplicationEnvironment( - CloudFoundryClient cloudFoundryClient, + private Mono requestUpdateApplicationV3( String applicationId, - Map environment) { - return requestUpdateApplication( - cloudFoundryClient, - applicationId, - builder -> builder.environmentJsons(environment)); + UnaryOperator + modifier) { + return this.cloudFoundryClient + .applicationsV3() + .update( + modifier.apply( + org.cloudfoundry.client.v3.applications + .UpdateApplicationRequest.builder() + .applicationId(applicationId)) + .build()) + .then(); } - private static Mono requestUpdateApplicationHealthCheckType( - CloudFoundryClient cloudFoundryClient, - String applicationId, - ApplicationHealthCheck type) { - return requestUpdateApplication( - cloudFoundryClient, - applicationId, - builder -> builder.healthCheckType(type.getValue())); + private Mono requestSetEnvironmentVariable( + String applicationId, String name, String value) { + return this.cloudFoundryClient + .applicationsV3() + .updateEnvironmentVariables( + UpdateApplicationEnvironmentVariablesRequest.builder() + .applicationId(applicationId) + .var(name, value) + .build()); } - private static Mono requestUpdateApplicationName( - CloudFoundryClient cloudFoundryClient, String applicationId, String name) { - return requestUpdateApplication( - cloudFoundryClient, applicationId, builder -> builder.name(name)); + private Mono requestUnsetEnvironmentVariable( + String applicationId, String name) { + return this.cloudFoundryClient + .applicationsV3() + .updateEnvironmentVariables( + UpdateApplicationEnvironmentVariablesRequest.builder() + .applicationId(applicationId) + .var(name, null) + .build()); } - private static Mono requestUpdateApplicationSsh( - CloudFoundryClient cloudFoundryClient, String applicationId, boolean enabled) { + private Mono requestUpdateApplicationSsh( + String applicationId, boolean enabled) { return requestUpdateApplicationFeature( - cloudFoundryClient, - applicationId, - builder -> builder.featureName(APP_FEATURE_SSH).enabled(enabled)); + applicationId, builder -> builder.featureName(APP_FEATURE_SSH).enabled(enabled)); } - private static Mono requestUpdateApplicationFeature( - CloudFoundryClient cloudFoundryClient, - String applicationId, - UnaryOperator modifier) { - return cloudFoundryClient + private Mono requestUpdateApplicationFeature( + String applicationId, UnaryOperator modifier) { + return this.cloudFoundryClient .applicationsV3() .updateFeature( modifier.apply( @@ -2755,32 +2154,19 @@ private static Mono requestUpdateApplicationFeature( .cast(ApplicationFeature.class); } - private static Mono requestUpdateApplicationScale( - CloudFoundryClient cloudFoundryClient, - String applicationId, - Integer disk, - Integer instances, - Integer memory) { + private Mono requestUpdateApplicationScale( + String applicationId, Integer disk, Integer instances, Integer memory) { return requestUpdateApplication( - cloudFoundryClient, applicationId, builder -> builder.diskQuota(disk).instances(instances).memory(memory)); } - private static Mono requestUpdateApplicationSsh( - CloudFoundryClient cloudFoundryClient, String applicationId, Boolean enabled) { - return requestUpdateApplication( - cloudFoundryClient, applicationId, builder -> builder.enableSsh(enabled)); + private Mono requestUpdateApplicationState( + String applicationId, String state) { + return requestUpdateApplication(applicationId, builder -> builder.state(state)); } - private static Mono requestUpdateApplicationState( - CloudFoundryClient cloudFoundryClient, String applicationId, String state) { - return requestUpdateApplication( - cloudFoundryClient, applicationId, builder -> builder.state(state)); - } - - private static Mono requestUploadApplication( - CloudFoundryClient cloudFoundryClient, + private Mono requestUploadApplication( String applicationId, Path application, List matchedResources) { @@ -2803,15 +2189,12 @@ private static Mono requestUploadApplication( (a, b) -> a) .build(); - return cloudFoundryClient.applicationsV2().upload(request); + return this.cloudFoundryClient.applicationsV2().upload(request); } - private static Mono requestUploadPackage( - CloudFoundryClient cloudFoundryClient, - String packageId, - Path bits, - List matchedResources) { - return cloudFoundryClient + private Mono requestUploadPackage( + String packageId, Path bits, List matchedResources) { + return this.cloudFoundryClient .packages() .upload( UploadPackageRequest.builder() @@ -2822,39 +2205,25 @@ private static Mono requestUploadPackage( .then(); } - private static Mono restageApplication( - CloudFoundryClient cloudFoundryClient, + private Mono restageApplication( String application, String applicationId, Duration stagingTimeout, Duration startupTimeout) { - return requestRestageApplication(cloudFoundryClient, applicationId) - .flatMap( - response -> - waitForStaging( - cloudFoundryClient, - application, - applicationId, - stagingTimeout)) - .then( - waitForRunning( - cloudFoundryClient, application, applicationId, startupTimeout)); + return requestRestageApplication(applicationId) + .flatMap(response -> waitForStaging(application, applicationId, stagingTimeout)) + .then(waitForRunning(application, applicationId, startupTimeout)); } - private static Mono restartApplication( - CloudFoundryClient cloudFoundryClient, + private Mono restartApplication( String application, String applicationId, Duration stagingTimeout, Duration startupTimeout) { - return stopApplication(cloudFoundryClient, applicationId) + return stopApplication(applicationId) .then( startApplicationAndWait( - cloudFoundryClient, - application, - applicationId, - stagingTimeout, - startupTimeout)); + application, applicationId, stagingTimeout, startupTimeout)); } private static boolean shouldStartApplication( @@ -2866,60 +2235,45 @@ private static boolean shouldStartApplication(PushApplicationManifestRequest req return !Optional.ofNullable(request.getNoStart()).orElse(false); } - private static Mono startApplicationAndWait( - CloudFoundryClient cloudFoundryClient, + private Mono startApplicationAndWait( String application, String applicationId, Duration stagingTimeout, Duration startupTimeout) { - return requestUpdateApplicationState(cloudFoundryClient, applicationId, STARTED_STATE) - .flatMap( - response -> - waitForStaging( - cloudFoundryClient, - application, - applicationId, - stagingTimeout)) - .then( - waitForRunning( - cloudFoundryClient, application, applicationId, startupTimeout)); + return requestUpdateApplicationState(applicationId, STARTED_STATE) + .flatMap(response -> waitForStaging(application, applicationId, stagingTimeout)) + .then(waitForRunning(application, applicationId, startupTimeout)); } - private static Mono stopAndStartApplication( - CloudFoundryClient cloudFoundryClient, - String applicationId, - String name, - PushApplicationManifestRequest request) { - return stopApplication(cloudFoundryClient, applicationId) + private Mono stopAndStartApplication( + String applicationId, String name, PushApplicationManifestRequest request) { + return stopApplication(applicationId) .filter(resource -> shouldStartApplication(request, resource)) .flatMap( resource -> startApplicationAndWait( - cloudFoundryClient, name, applicationId, request.getStagingTimeout(), request.getStartupTimeout())); } - private static Mono stopApplication( - CloudFoundryClient cloudFoundryClient, String applicationId) { - return requestUpdateApplicationState(cloudFoundryClient, applicationId, STOPPED_STATE); + private Mono stopApplication(String applicationId) { + return requestUpdateApplicationState(applicationId, STOPPED_STATE); } - private static Mono stopApplicationIfNotStopped( - CloudFoundryClient cloudFoundryClient, AbstractApplicationResource resource) { + private Mono stopApplicationIfNotStopped( + AbstractApplicationResource resource) { return isNotIn(resource, STOPPED_STATE) - ? stopApplication(cloudFoundryClient, ResourceUtils.getId(resource)) + ? stopApplication(ResourceUtils.getId(resource)) : Mono.just(resource); } private static ApplicationDetail toApplicationDetail( List buildpacks, SummaryApplicationResponse summaryApplicationResponse, - GetStackResponse getStackResponse, - List instanceDetails, - List urls) { + String stackName, + List instanceDetails) { if (buildpacks.size() == 0) { buildpacks = Collections.singletonList(summaryApplicationResponse.getDetectedBuildpack()); @@ -2936,8 +2290,8 @@ private static ApplicationDetail toApplicationDetail( .name(summaryApplicationResponse.getName()) .requestedState(summaryApplicationResponse.getState()) .runningInstances(summaryApplicationResponse.getRunningInstances()) - .stack(getStackResponse.getEntity().getName()) - .urls(urls) + .stack(stackName) + .urls(toUrls(summaryApplicationResponse.getRoutes())) .build(); } @@ -2951,7 +2305,7 @@ private static ApplicationEnvironments toApplicationEnvironments( .build(); } - private static Mono toApplicationManifest( + private Mono toApplicationManifest( List buildpacks, SummaryApplicationResponse response, String stackName) { ApplicationManifest.Builder builder = ApplicationManifest.builder() @@ -3040,51 +2394,53 @@ private static DomainSummary toDomain(PrivateDomainResource resource) { .build(); } - private static ApplicationHealthCheck toHealthCheck(AbstractApplicationResource resource) { - String type = resource.getEntity().getHealthCheckType(); - - if (ApplicationHealthCheck.HTTP.getValue().equals(type)) { + private static ApplicationHealthCheck toHealthCheck(HealthCheckType type) { + if (type == HealthCheckType.HTTP) { return ApplicationHealthCheck.HTTP; - } else if (ApplicationHealthCheck.NONE.getValue().equals(type)) { - return ApplicationHealthCheck.NONE; - } else if (ApplicationHealthCheck.PORT.getValue().equals(type)) { + } else if (type == HealthCheckType.PORT) { return ApplicationHealthCheck.PORT; - } else if (ApplicationHealthCheck.PROCESS.getValue().equals(type)) { + } else if (type == HealthCheckType.PROCESS) { return ApplicationHealthCheck.PROCESS; + } else if (type == HealthCheckType.NONE) { + return ApplicationHealthCheck.NONE; } else { return null; } } - private static InstanceDetail toInstanceDetail( - Map.Entry entry, - ApplicationStatisticsResponse statisticsResponse) { - InstanceStatistics instanceStatistics = - Optional.ofNullable(statisticsResponse.getInstances().get(entry.getKey())) - .orElse(emptyInstanceStats()); - Statistics stats = - Optional.ofNullable(instanceStatistics.getStatistics()) - .orElse(emptyApplicationStatistics()); - Usage usage = Optional.ofNullable(stats.getUsage()).orElse(emptyApplicationUsage()); - - return InstanceDetail.builder() - .index(entry.getKey()) - .state(entry.getValue().getState()) - .since(toDate(entry.getValue().getSince())) - .cpu(usage.getCpu()) - .memoryUsage(usage.getMemory()) - .diskUsage(usage.getDisk()) - .diskQuota(stats.getDiskQuota()) - .memoryQuota(stats.getMemoryQuota()) - .build(); + private static HealthCheckType fromHealthCheck(ApplicationHealthCheck type) { + if (type == ApplicationHealthCheck.HTTP) { + return HealthCheckType.HTTP; + } else if (type == ApplicationHealthCheck.PORT) { + return HealthCheckType.PORT; + } else if (type == ApplicationHealthCheck.PROCESS) { + return HealthCheckType.PROCESS; + } else if (type == ApplicationHealthCheck.NONE) { + return HealthCheckType.NONE; + } else { + return null; + } } - private static Mono> toInstanceDetailList( - ApplicationInstancesResponse instancesResponse, - ApplicationStatisticsResponse statisticsResponse) { - return Flux.fromIterable(instancesResponse.getInstances().entrySet()) - .map(entry -> toInstanceDetail(entry, statisticsResponse)) - .collectList(); + private List toInstanceDetailList( + GetApplicationProcessStatisticsResponse statisticsResponse) { + return statisticsResponse.getResources().stream() + .map( + statisticsResource -> { + ProcessUsage usage = + Optional.ofNullable(statisticsResource.getUsage()) + .orElse(ProcessUsage.builder().build()); + return InstanceDetail.builder() + .index(statisticsResource.getIndex().toString()) + .state(statisticsResource.getState().getValue()) + .cpu(usage.getCpu()) + .memoryUsage(usage.getMemory()) + .diskUsage(usage.getDisk()) + .diskQuota(statisticsResource.getDiskQuota()) + .memoryQuota(statisticsResource.getMemoryQuota()) + .build(); + }) + .collect(Collectors.toList()); } private static Task toTask(org.cloudfoundry.client.v3.tasks.Task task) { @@ -3113,19 +2469,16 @@ private static String toUrl(org.cloudfoundry.client.v2.routes.Route route) { return sb.toString(); } - private static Mono> toUrls(List routes) { - return Flux.fromIterable(routes).map(DefaultApplications::toUrl).collectList(); + private static List toUrls(List routes) { + return routes.stream().map(DefaultApplications::toUrl).collect(Collectors.toList()); } - private static Mono updateBuildpacks( - CloudFoundryClient cloudFoundryClient, - String applicationId, - ApplicationManifest manifest) { + private Mono updateBuildpacks(String applicationId, ApplicationManifest manifest) { if (manifest.getBuildpacks() == null || manifest.getBuildpacks().size() < 2) { return Mono.empty(); } - return cloudFoundryClient + return this.cloudFoundryClient .applicationsV3() .update( org.cloudfoundry.client.v3.applications.UpdateApplicationRequest.builder() @@ -3143,8 +2496,7 @@ private static Mono updateBuildpacks( .then(); } - private static Mono uploadApplicationAndWait( - CloudFoundryClient cloudFoundryClient, + private Mono uploadApplicationAndWait( String applicationId, Path application, List matchedResources, @@ -3153,10 +2505,7 @@ private static Mono uploadApplicationAndWait( () -> { if (matchedResources.isEmpty()) { return requestUploadApplication( - cloudFoundryClient, - applicationId, - application, - matchedResources); + applicationId, application, matchedResources); } else { List paths = matchedResources.stream() @@ -3169,7 +2518,6 @@ private static Mono uploadApplicationAndWait( .flatMap( filteredApplication -> requestUploadApplication( - cloudFoundryClient, applicationId, filteredApplication, matchedResources) @@ -3188,11 +2536,12 @@ private static Mono uploadApplicationAndWait( } }) .flatMap( - job -> JobUtils.waitForCompletion(cloudFoundryClient, stagingTimeout, job)); + job -> + JobUtils.waitForCompletion( + this.cloudFoundryClient, stagingTimeout, job)); } - private static Mono uploadPackageBitsAndWait( - CloudFoundryClient cloudFoundryClient, + private Mono uploadPackageBitsAndWait( String packageId, Path application, List matchedResources, @@ -3201,10 +2550,7 @@ private static Mono uploadPackageBitsAndWait( () -> { if (matchedResources.isEmpty()) { return requestUploadPackage( - cloudFoundryClient, - packageId, - application, - matchedResources); + packageId, application, matchedResources); } else { List paths = matchedResources.stream() @@ -3215,7 +2561,6 @@ private static Mono uploadPackageBitsAndWait( .flatMap( filteredApplication -> requestUploadPackage( - cloudFoundryClient, packageId, filteredApplication, matchedResources) @@ -3233,18 +2578,13 @@ private static Mono uploadPackageBitsAndWait( })); } }) - .then( - waitForUploadProcessingCompleted( - cloudFoundryClient, packageId, processingTimeout)); + .then(waitForUploadProcessingCompleted(packageId, processingTimeout)); } - private static Mono waitForBuildStaging( - CloudFoundryClient cloudFoundryClient, - String buildId, - String applicationName, - Duration stagingTimeout) { + private Mono waitForBuildStaging( + String buildId, String applicationName, Duration stagingTimeout) { Duration timeout = Optional.ofNullable(stagingTimeout).orElse(Duration.ofMinutes(15)); - return cloudFoundryClient + return this.cloudFoundryClient .builds() .get(GetBuildRequest.builder().buildId(buildId).build()) .filter( @@ -3266,17 +2606,14 @@ private static Mono waitForBuildStaging( buildId, applicationName)); } - private static Mono waitForRunning( - CloudFoundryClient cloudFoundryClient, - String application, - String applicationId, - Duration startupTimeout) { + private Mono waitForRunning( + String application, String applicationId, Duration startupTimeout) { Duration timeout = Optional.ofNullable(startupTimeout).orElse(Duration.ofMinutes(5)); - return requestApplicationInstances(cloudFoundryClient, applicationId) - .flatMapMany(response -> Flux.fromIterable(response.getInstances().values())) - .map(ApplicationInstanceInfo::getState) - .reduce("UNKNOWN", collectStates()) + return requestApplicationStatisticsV3(applicationId) + .flatMapIterable(GetApplicationProcessStatisticsResponse::getResources) + .map(ProcessStatisticsResource::getState) + .reduce(ProcessState.STARTING, collectStates()) .filter(isInstanceComplete()) .repeatWhenEmpty( exponentialBackOff(Duration.ofSeconds(1), Duration.ofSeconds(15), timeout)) @@ -3292,76 +2629,16 @@ private static Mono waitForRunning( .then(); } - private static Mono waitForRunningV3( - CloudFoundryClient cloudFoundryClient, - String applicationName, - String applicationId, - Duration startupTimeout) { - Duration timeout = Optional.ofNullable(startupTimeout).orElse(Duration.ofMinutes(5)); - - return PaginationUtils.requestClientV3Resources( - page -> - cloudFoundryClient - .applicationsV3() - .listProcesses( - ListApplicationProcessesRequest.builder() - .applicationId(applicationId) - .page(page) - .build())) - .filter(p -> p.getInstances() != 0) - .flatMap( - process -> - cloudFoundryClient - .processes() - .getStatistics( - GetProcessStatisticsRequest.builder() - .processId(process.getId()) - .build()) - .flatMapIterable(GetProcessStatisticsResponse::getResources) - .map(ProcessStatisticsResource::getState) - .filter( - state -> - EnumSet.of( - ProcessState.RUNNING, - ProcessState.CRASHED) - .contains(state)) - .reduce( - (totalState, instanceState) -> - totalState.ordinal() - < instanceState.ordinal() - ? totalState - : instanceState) // CRASHED takes - // precedence over - // RUNNING - .repeatWhenEmpty( - exponentialBackOff( - Duration.ofSeconds(1), - Duration.ofSeconds(15), - timeout)) - .filter(state -> state == ProcessState.RUNNING) - .switchIfEmpty( - ExceptionUtils.illegalState( - "Process %s of Application %s failed during" - + " start", - process.getId(), applicationName)) - .onErrorResume( - DelayTimeoutException.class, - t -> - ExceptionUtils.illegalState( - "Process %s of Application %s timed" - + " out during start", - process.getId(), applicationName))) - .then(); + private Mono waitForRunningV3( + String applicationName, String applicationId, Duration startupTimeout) { + return waitForRunning(applicationName, applicationId, startupTimeout); } - private static Mono waitForStaging( - CloudFoundryClient cloudFoundryClient, - String application, - String applicationId, - Duration stagingTimeout) { + private Mono waitForStaging( + String application, String applicationId, Duration stagingTimeout) { Duration timeout = Optional.ofNullable(stagingTimeout).orElse(Duration.ofMinutes(15)); - return requestGetApplication(cloudFoundryClient, applicationId) + return requestGetApplication(applicationId) .map(response -> ResourceUtils.getEntity(response).getPackageState()) .filter(isStagingComplete()) .repeatWhenEmpty( @@ -3378,9 +2655,9 @@ private static Mono waitForStaging( .then(); } - private static Mono waitForUploadProcessingCompleted( - CloudFoundryClient cloudFoundryClient, String packageId, Duration processingTimeout) { - return cloudFoundryClient + private Mono waitForUploadProcessingCompleted( + String packageId, Duration processingTimeout) { + return this.cloudFoundryClient .packages() .get(GetPackageRequest.builder().packageId(packageId).build()) .filter( diff --git a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/_InstanceDetail.java b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/_InstanceDetail.java index c0a146668a..85b338704a 100644 --- a/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/_InstanceDetail.java +++ b/cloudfoundry-operations/src/main/java/org/cloudfoundry/operations/applications/_InstanceDetail.java @@ -16,11 +16,11 @@ package org.cloudfoundry.operations.applications; +import java.util.Date; + import org.cloudfoundry.Nullable; import org.immutables.value.Value; -import java.util.Date; - /** * Information about an instance of an application */ @@ -64,8 +64,11 @@ abstract class _InstanceDetail { /** * The time this instance was created + * + * @deprecated Always returns null. The "since" field is not returned by the CF v3 API. */ @Nullable + @Deprecated abstract Date getSince(); /** diff --git a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/AbstractOperationsTest.java b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/AbstractOperationsTest.java index ab1250658a..5af35b353b 100644 --- a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/AbstractOperationsTest.java +++ b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/AbstractOperationsTest.java @@ -44,10 +44,12 @@ import org.cloudfoundry.client.v2.userprovidedserviceinstances.UserProvidedServiceInstances; import org.cloudfoundry.client.v2.users.Users; import org.cloudfoundry.client.v3.applications.ApplicationsV3; +import org.cloudfoundry.client.v3.auditevents.AuditEventsV3; import org.cloudfoundry.client.v3.buildpacks.BuildpacksV3; import org.cloudfoundry.client.v3.domains.DomainsV3; import org.cloudfoundry.client.v3.jobs.JobsV3; import org.cloudfoundry.client.v3.organizations.OrganizationsV3; +import org.cloudfoundry.client.v3.processes.Processes; import org.cloudfoundry.client.v3.routes.RoutesV3; import org.cloudfoundry.client.v3.spaces.SpacesV3; import org.cloudfoundry.client.v3.stacks.StacksV3; @@ -105,6 +107,7 @@ public abstract class AbstractOperationsTest { protected final DopplerClient dopplerClient = mock(DopplerClient.class, RETURNS_SMART_NULLS); protected final Events events = mock(Events.class, RETURNS_SMART_NULLS); + protected final AuditEventsV3 auditEventsV3 = mock(AuditEventsV3.class, RETURNS_SMART_NULLS); protected final FeatureFlags featureFlags = mock(FeatureFlags.class, RETURNS_SMART_NULLS); @@ -117,6 +120,7 @@ public abstract class AbstractOperationsTest { protected final Organizations organizations = mock(Organizations.class, RETURNS_SMART_NULLS); protected final OrganizationsV3 organizationsV3 = mock(OrganizationsV3.class, RETURNS_SMART_NULLS); + protected final Processes processes = mock(Processes.class, RETURNS_SMART_NULLS); protected final PrivateDomains privateDomains = mock(PrivateDomains.class, RETURNS_SMART_NULLS); @@ -180,6 +184,7 @@ public final void mockClient() { when(this.cloudFoundryClient.domains()).thenReturn(this.domains); when(this.cloudFoundryClient.domainsV3()).thenReturn(this.domainsV3); when(this.cloudFoundryClient.events()).thenReturn(this.events); + when(this.cloudFoundryClient.auditEventsV3()).thenReturn(this.auditEventsV3); when(this.cloudFoundryClient.featureFlags()).thenReturn(this.featureFlags); when(this.cloudFoundryClient.jobs()).thenReturn(this.jobs); when(this.cloudFoundryClient.jobsV3()).thenReturn(this.jobsV3); @@ -188,6 +193,7 @@ public final void mockClient() { when(this.cloudFoundryClient.organizationQuotaDefinitions()) .thenReturn(this.organizationQuotaDefinitions); when(this.cloudFoundryClient.privateDomains()).thenReturn(this.privateDomains); + when(this.cloudFoundryClient.processes()).thenReturn(this.processes); when(this.cloudFoundryClient.resourceMatch()).thenReturn(this.resourceMatch); when(this.cloudFoundryClient.routes()).thenReturn(this.routes); when(this.cloudFoundryClient.routesV3()).thenReturn(this.routesV3); diff --git a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/DefaultCloudFoundryOperationsTest.java b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/DefaultCloudFoundryOperationsTest.java index 02e671a3e6..2dfa183183 100644 --- a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/DefaultCloudFoundryOperationsTest.java +++ b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/DefaultCloudFoundryOperationsTest.java @@ -17,20 +17,45 @@ package org.cloudfoundry.operations; import static org.assertj.core.api.Assertions.assertThat; - +import static org.cloudfoundry.operations.TestObjects.fill; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import org.cloudfoundry.client.v3.organizations.ListOrganizationsResponse; +import org.cloudfoundry.client.v3.organizations.OrganizationResource; +import org.cloudfoundry.client.v3.spaces.ListSpacesResponse; +import org.cloudfoundry.client.v3.spaces.SpaceResource; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import reactor.core.publisher.Mono; final class DefaultCloudFoundryOperationsTest extends AbstractOperationsTest { - private final DefaultCloudFoundryOperations operations = - DefaultCloudFoundryOperations.builder() - .cloudFoundryClient(this.cloudFoundryClient) - .dopplerClient(this.dopplerClient) - .routingClient(this.routingClient) - .organization(TEST_ORGANIZATION_NAME) - .space(TEST_SPACE_NAME) - .uaaClient(this.uaaClient) - .build(); + private DefaultCloudFoundryOperations operations; + + @BeforeEach + void setUp() { + ListOrganizationsResponse orgsResponse = + fill(ListOrganizationsResponse.builder()) + .resource(fill(OrganizationResource.builder()).build()) + .build(); + when(this.organizationsV3.list(any())).thenReturn(Mono.just(orgsResponse)); + ListSpacesResponse spacesResponse = + fill(ListSpacesResponse.builder()) + .resource(fill(SpaceResource.builder()).build()) + .build(); + when(this.spacesV3.list(any())).thenReturn(Mono.just(spacesResponse)); + + operations = + DefaultCloudFoundryOperations.builder() + .cloudFoundryClient(this.cloudFoundryClient) + .dopplerClient(this.dopplerClient) + .routingClient(this.routingClient) + .organization(TEST_ORGANIZATION_NAME) + .space(TEST_SPACE_NAME) + .uaaClient(this.uaaClient) + .build(); + } @Test void advanced() { diff --git a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/ReflectionUtils.java b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/ReflectionUtils.java new file mode 100644 index 0000000000..2dda61e5ab --- /dev/null +++ b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/ReflectionUtils.java @@ -0,0 +1,136 @@ +package org.cloudfoundry.operations; + +import java.io.File; +import java.lang.reflect.Modifier; +import java.net.JarURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.Objects; +import java.util.jar.JarFile; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class ReflectionUtils { + + private ReflectionUtils() { // do not instantiate this class + } + + /** + * Find implementations for a given interface type. Uses reflection. + */ + public static List> findImplementations(Class interfaceType) { + try { + ClassLoader classLoader = interfaceType.getClassLoader(); + + String path = interfaceType.getPackage().getName().replace('.', '/'); + Enumeration resources = classLoader.getResources(path); + ArrayList lr = Collections.list(resources); + + return lr.stream() + .flatMap( + url -> { + if (url.getProtocol().equals("jar")) { + // Handle JAR URLs + return scanJar( + url, + interfaceType.getPackage().getName(), + interfaceType); + } else { + return scanDirectory( + new File(url.getFile()), + interfaceType.getPackage().getName(), + interfaceType); + } + }) + .collect(Collectors.toList()); + } catch (Exception ignored) { + + } + return Collections.emptyList(); + } + + /** + * Find implementations for the given interface type in a source directory. + */ + private static Stream> scanDirectory( + File directory, String packageName, Class interfaceType) { + File[] files = directory.listFiles(); + if (files == null) { + return Stream.empty(); + } + + Stream> classes = + Arrays.stream(files) + .filter(fileName -> fileName.getName().endsWith(".class")) + .map( + fileName -> + packageName + + '.' + + fileName.getName().replaceAll("\\.class$", "")) + .>map( + className -> + getClassIfImplementsInterface(className, interfaceType)) + .filter(Objects::nonNull); + Stream> directories = + Arrays.stream(files) + .filter(File::isDirectory) + .flatMap( + fileName -> + scanDirectory( + fileName, + packageName + "." + fileName.getName(), + interfaceType)); + return Stream.concat(classes, directories); + } + + /** + * Find implementations for the given interface type in a packaged jar. + * When running {@code mvn package}, class files are packaged in jar files, + * and is not available directly on the filesystem. + */ + private static Stream> scanJar( + URL jarUrl, String packageName, Class interfaceType) { + try { + JarURLConnection jarConnection = (JarURLConnection) jarUrl.openConnection(); + JarFile jarFile = jarConnection.getJarFile(); + String packagePath = packageName.replace('.', '/'); + + return jarFile.stream() + .filter( + entry -> { + String name = entry.getName(); + return name.startsWith(packagePath) + && name.endsWith(".class") + && !name.equals(packagePath + ".class"); + }) + .map(entry -> entry.getName().replace('/', '.').replaceAll("\\.class$", "")) + .>map( + className -> getClassIfImplementsInterface(className, interfaceType)) + .filter(Objects::nonNull); + } catch (Exception e) { + return Stream.empty(); + } + } + + /** + * Return the {@link Class} instance for {@code className}, if it implements {@code interfaceType}. Otherwise, return null. + */ + private static Class getClassIfImplementsInterface( + String className, Class interfaceType) { + try { + Class clazz = Class.forName(className); + if (interfaceType.isAssignableFrom(clazz) + && !clazz.isInterface() + && !Modifier.isAbstract(clazz.getModifiers())) { + Class subclass = clazz.asSubclass(interfaceType); + return subclass; + } + } catch (ClassNotFoundException ignored) { + } + return null; + } +} diff --git a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/TestObjects.java b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/TestObjects.java index 119b62fabb..8dff992136 100644 --- a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/TestObjects.java +++ b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/TestObjects.java @@ -109,9 +109,12 @@ private static T fill(T builder, Optional modifier) { return getConfigurationMethods(builderType, builderMethods, builtGetters).stream() .collect( () -> builder, - (b, method) -> - ReflectionUtils.invokeMethod( - method, b, getConfiguredValue(method, modifier)), + (b, method) -> { + Object configuredValue = getConfiguredValue(method, modifier); + if (configuredValue != null) { + ReflectionUtils.invokeMethod(method, b, configuredValue); + } + }, (a, b) -> {}); } @@ -190,10 +193,19 @@ private static Object getConfiguredValue( return getConfiguredString(configurationMethod, modifier); } else if (parameterType.isArray()) { return Array.newInstance(parameterType.getComponentType(), 0); + } else if (parameterType == Map.Entry.class) { + return null; } else { - throw new IllegalStateException( - String.format("Unable to configure %s", configurationMethod)); + for (Class implementation : + org.cloudfoundry.operations.ReflectionUtils.findImplementations( + parameterType)) { + if (isBuiltType(implementation)) { + return getConfiguredBuilder(implementation, modifier); + } + } } + throw new IllegalStateException( + String.format("Unable to configure %s", configurationMethod)); } private static List getMethods(Class builderType) { diff --git a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java index cdc9619d2d..bc36b0b974 100644 --- a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java +++ b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/applications/DefaultApplicationsTest.java @@ -20,8 +20,11 @@ import static org.cloudfoundry.client.v3.LifecycleType.BUILDPACK; import static org.cloudfoundry.client.v3.LifecycleType.DOCKER; import static org.cloudfoundry.operations.TestObjects.fill; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.RETURNS_SMART_NULLS; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.IOException; @@ -39,7 +42,6 @@ import org.cloudfoundry.client.CloudFoundryClient; import org.cloudfoundry.client.v2.ClientV2Exception; import org.cloudfoundry.client.v2.Metadata; -import org.cloudfoundry.client.v2.OrderDirection; import org.cloudfoundry.client.v2.applications.ApplicationEntity; import org.cloudfoundry.client.v2.applications.ApplicationInstanceInfo; import org.cloudfoundry.client.v2.applications.ApplicationInstancesRequest; @@ -55,8 +57,6 @@ import org.cloudfoundry.client.v2.applications.DockerCredentials; import org.cloudfoundry.client.v2.applications.GetApplicationResponse; import org.cloudfoundry.client.v2.applications.InstanceStatistics; -import org.cloudfoundry.client.v2.applications.ListApplicationRoutesRequest; -import org.cloudfoundry.client.v2.applications.ListApplicationRoutesResponse; import org.cloudfoundry.client.v2.applications.ListApplicationServiceBindingsRequest; import org.cloudfoundry.client.v2.applications.ListApplicationServiceBindingsResponse; import org.cloudfoundry.client.v2.applications.RemoveApplicationRouteRequest; @@ -71,10 +71,6 @@ import org.cloudfoundry.client.v2.applications.UploadApplicationRequest; import org.cloudfoundry.client.v2.applications.UploadApplicationResponse; import org.cloudfoundry.client.v2.applications.Usage; -import org.cloudfoundry.client.v2.events.EventEntity; -import org.cloudfoundry.client.v2.events.EventResource; -import org.cloudfoundry.client.v2.events.ListEventsRequest; -import org.cloudfoundry.client.v2.events.ListEventsResponse; import org.cloudfoundry.client.v2.jobs.ErrorDetails; import org.cloudfoundry.client.v2.jobs.GetJobRequest; import org.cloudfoundry.client.v2.jobs.GetJobResponse; @@ -116,23 +112,41 @@ import org.cloudfoundry.client.v2.spaces.SpaceApplicationSummary; import org.cloudfoundry.client.v2.spaces.SpaceEntity; import org.cloudfoundry.client.v2.spaces.SpaceResource; -import org.cloudfoundry.client.v2.stacks.GetStackRequest; -import org.cloudfoundry.client.v2.stacks.GetStackResponse; -import org.cloudfoundry.client.v2.stacks.ListStacksRequest; -import org.cloudfoundry.client.v2.stacks.ListStacksResponse; -import org.cloudfoundry.client.v2.stacks.StackEntity; import org.cloudfoundry.client.v3.BuildpackData; +import org.cloudfoundry.client.v3.ClientV3Exception; import org.cloudfoundry.client.v3.DockerData; +import org.cloudfoundry.client.v3.Error; import org.cloudfoundry.client.v3.Lifecycle; +import org.cloudfoundry.client.v3.Pagination; import org.cloudfoundry.client.v3.applications.ApplicationState; import org.cloudfoundry.client.v3.applications.GetApplicationEnvironmentRequest; import org.cloudfoundry.client.v3.applications.GetApplicationEnvironmentResponse; +import org.cloudfoundry.client.v3.applications.GetApplicationProcessRequest; +import org.cloudfoundry.client.v3.applications.GetApplicationProcessResponse; +import org.cloudfoundry.client.v3.applications.GetApplicationProcessStatisticsRequest; +import org.cloudfoundry.client.v3.applications.GetApplicationProcessStatisticsResponse; import org.cloudfoundry.client.v3.applications.GetApplicationSshEnabledRequest; import org.cloudfoundry.client.v3.applications.GetApplicationSshEnabledResponse; +import org.cloudfoundry.client.v3.applications.ListApplicationRoutesRequest; +import org.cloudfoundry.client.v3.applications.ListApplicationRoutesResponse; import org.cloudfoundry.client.v3.applications.ListApplicationsRequest; import org.cloudfoundry.client.v3.applications.ListApplicationsResponse; +import org.cloudfoundry.client.v3.applications.UpdateApplicationEnvironmentVariablesRequest; +import org.cloudfoundry.client.v3.applications.UpdateApplicationEnvironmentVariablesResponse; import org.cloudfoundry.client.v3.applications.UpdateApplicationFeatureRequest; import org.cloudfoundry.client.v3.applications.UpdateApplicationFeatureResponse; +import org.cloudfoundry.client.v3.auditevents.AuditEventResource; +import org.cloudfoundry.client.v3.auditevents.ListAuditEventsRequest; +import org.cloudfoundry.client.v3.auditevents.ListAuditEventsResponse; +import org.cloudfoundry.client.v3.processes.HealthCheck; +import org.cloudfoundry.client.v3.processes.HealthCheckType; +import org.cloudfoundry.client.v3.processes.ProcessState; +import org.cloudfoundry.client.v3.processes.ProcessStatisticsResource; +import org.cloudfoundry.client.v3.processes.UpdateProcessRequest; +import org.cloudfoundry.client.v3.processes.UpdateProcessResponse; +import org.cloudfoundry.client.v3.stacks.GetStackRequest; +import org.cloudfoundry.client.v3.stacks.ListStacksRequest; +import org.cloudfoundry.client.v3.stacks.ListStacksResponse; import org.cloudfoundry.client.v3.tasks.CancelTaskRequest; import org.cloudfoundry.client.v3.tasks.CancelTaskResponse; import org.cloudfoundry.client.v3.tasks.CreateTaskRequest; @@ -149,6 +163,8 @@ import org.cloudfoundry.util.FluentMap; import org.cloudfoundry.util.ResourceMatchingUtils; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.springframework.core.io.ClassPathResource; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -161,10 +177,7 @@ final class DefaultApplicationsTest extends AbstractOperationsTest { private final DefaultApplications applications = new DefaultApplications( - Mono.just(this.cloudFoundryClient), - Mono.just(this.dopplerClient), - this.randomWords, - Mono.just(TEST_SPACE_ID)); + this.cloudFoundryClient, this.dopplerClient, this.randomWords, TEST_SPACE_ID); @Test void copySourceNoRestartOrgSpace() { @@ -494,12 +507,11 @@ void enableSshNoApp() { @Test void get() { - requestApplications( + requestApplicationsV3( this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-application-id"); - requestApplicationStatistics(this.cloudFoundryClient, "test-application-id"); + requestApplicationProcessStatistics(this.cloudFoundryClient, "test-application-id"); requestStack(this.cloudFoundryClient, "test-application-stackId"); requestApplicationSummary(this.cloudFoundryClient, "test-application-id"); - requestApplicationInstances(this.cloudFoundryClient, "test-application-id"); requestGetApplicationV3Buildpack(this.cloudFoundryClient, "test-application-id"); this.applications @@ -511,14 +523,14 @@ void get() { .id("test-application-summary-id") .instanceDetail( fill(InstanceDetail.builder()) - .index("instance-0") - .since(new Date(1000)) - .state("test-application-instance-info-state") + .since(null) + .index("1") + .state("RUNNING") .build()) .lastUploaded(new Date(0)) .name("test-application-summary-name") .requestedState("test-application-summary-state") - .stack("test-stack-entity-name") + .stack("test-stack") .url("test-route-host.test-domain-name/test-path") .build()) .expectComplete() @@ -539,7 +551,9 @@ void getApplicationManifest() { .as(StepVerifier::create) .expectNext( ApplicationManifest.builder() - .buildpacks("test-buildpack-1", "test-buildpack-2") + .buildpacks( + "test-application-summary-detectedBuildpack-1", + "test-application-summary-detectedBuildpack-2") .command("test-application-summary-command") .disk(1) .environmentVariables(Collections.emptyMap()) @@ -672,12 +686,11 @@ void getApplicationManifestTcp() { @Test void getBuildpackError() { - requestApplications( + requestApplicationsV3( this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-application-id"); - requestApplicationStatistics(this.cloudFoundryClient, "test-application-id"); requestStack(this.cloudFoundryClient, "test-application-stackId"); requestApplicationSummary(this.cloudFoundryClient, "test-application-id"); - requestApplicationInstancesError(this.cloudFoundryClient, "test-application-id", 170004); + requestProcessStatisticsError(this.cloudFoundryClient, "test-application-id", 170004); requestGetApplicationV3Buildpack(this.cloudFoundryClient, "test-application-id"); this.applications @@ -690,7 +703,7 @@ void getBuildpackError() { .lastUploaded(new Date(0)) .name("test-application-summary-name") .requestedState("test-application-summary-state") - .stack("test-stack-entity-name") + .stack("test-stack") .url("test-route-host.test-domain-name/test-path") .build()) .expectComplete() @@ -699,12 +712,11 @@ void getBuildpackError() { @Test void getDetectedBuildpack() { - requestApplications( + requestApplicationsV3( this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-application-id"); - requestApplicationStatistics(this.cloudFoundryClient, "test-application-id"); + requestApplicationProcessStatistics(this.cloudFoundryClient, "test-application-id"); requestStack(this.cloudFoundryClient, "test-application-stackId"); requestApplicationSummaryDetectedBuildpack(this.cloudFoundryClient, "test-application-id"); - requestApplicationInstances(this.cloudFoundryClient, "test-application-id"); requestGetApplicationV3Docker(this.cloudFoundryClient, "test-application-id"); this.applications @@ -716,15 +728,15 @@ void getDetectedBuildpack() { .id("test-application-summary-id") .instanceDetail( fill(InstanceDetail.builder()) - .index("instance-0") - .since(new Date(1000)) - .state("test-application-instance-info-state") + .since(null) + .index("1") + .state("RUNNING") .build()) .lastUploaded(new Date(0)) .name("test-application-summary-name") .requestedState("test-application-summary-state") - .stack("test-stack-entity-name") - .url("test-route-host.test-domain-name:1") + .stack("test-stack") + .url("test-route-host.test-domain-name/test-path") .build()) .expectComplete() .verify(Duration.ofSeconds(5)); @@ -781,21 +793,21 @@ void getEnvironmentsNoApp() { @Test void getEvents() { - requestApplications(this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-metadata-id"); + requestApplicationsV3( + this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-metadata-id"); requestEvents( this.cloudFoundryClient, "test-metadata-id", - fill(EventEntity.builder(), "event-") - .timestamp("2016-02-08T15:45:59Z") - .metadata( + fill(AuditEventResource.builder(), "event-") + .createdAt("2016-02-08T15:45:59Z") + .data( "request", - Optional.of( - FluentMap.builder() - .entry("instances", 1) - .entry("memory", 2) - .entry("environment_json", "test-data") - .entry("state", "test-state") - .build())) + FluentMap.builder() + .entry("instances", 1) + .entry("memory", 2) + .entry("environment_json", "test-data") + .entry("state", "test-state") + .build()) .build()); this.applications @@ -803,7 +815,7 @@ void getEvents() { .as(StepVerifier::create) .expectNext( ApplicationEvent.builder() - .actor("test-event-actorName") + .actor("test-event-name") .description( "instances: 1, memory: 2, state: test-state," + " environment_json: test-data") @@ -817,20 +829,20 @@ void getEvents() { @Test void getEventsBadTimeSparseMetadata() { - requestApplications(this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-metadata-id"); + requestApplicationsV3( + this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-metadata-id"); requestEvents( this.cloudFoundryClient, "test-metadata-id", - fill(EventEntity.builder(), "event-") - .timestamp("BAD-TIMESTAMP") - .metadata( + fill(AuditEventResource.builder(), "event-") + .createdAt("BAD-TIMESTAMP") + .data( "request", - Optional.of( - FluentMap.builder() - .entry("memory", 2) - .entry("environment_json", "test-data") - .entry("state", "test-state") - .build())) + FluentMap.builder() + .entry("memory", 2) + .entry("environment_json", "test-data") + .entry("state", "test-state") + .build()) .build()); this.applications @@ -838,7 +850,7 @@ void getEventsBadTimeSparseMetadata() { .as(StepVerifier::create) .expectNext( ApplicationEvent.builder() - .actor("test-event-actorName") + .actor("test-event-name") .description( "memory: 2, state: test-state, environment_json: test-data") .event("test-event-type") @@ -850,7 +862,8 @@ void getEventsBadTimeSparseMetadata() { @Test void getEventsFoundZero() { - requestApplications(this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-metadata-id"); + requestApplicationsV3( + this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-metadata-id"); requestEvents(this.cloudFoundryClient, "test-metadata-id"); this.applications @@ -862,21 +875,14 @@ void getEventsFoundZero() { @Test void getEventsLimitZero() { - requestApplications(this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-metadata-id"); + requestApplicationsV3( + this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-metadata-id"); requestEvents( this.cloudFoundryClient, "test-metadata-id", - fill(EventEntity.builder(), "event-") - .timestamp("2016-02-08T15:45:59Z") - .metadata( - "request", - Optional.of( - FluentMap.builder() - .entry("instances", 1) - .entry("memory", 2) - .entry("environment_json", "test-data") - .entry("state", "test-state") - .build())) + fill(AuditEventResource.builder(), "event-") + .createdAt("2016-02-08T15:45:59Z") + .data("index", 1) .build()); this.applications @@ -892,13 +898,14 @@ void getEventsLimitZero() { @Test void getEventsNoRequestMetadata() { - requestApplications(this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-metadata-id"); + requestApplicationsV3( + this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-metadata-id"); requestEvents( this.cloudFoundryClient, "test-metadata-id", - fill(EventEntity.builder(), "event-") - .timestamp("2016-02-08T15:45:59Z") - .metadata("index", Optional.of(1)) + fill(AuditEventResource.builder(), "event-") + .createdAt("2016-02-08T15:45:59Z") + .data("index", 1) .build()); this.applications @@ -906,7 +913,7 @@ void getEventsNoRequestMetadata() { .as(StepVerifier::create) .expectNext( ApplicationEvent.builder() - .actor("test-event-actorName") + .actor("test-event-name") .description("") .event("test-event-type") .time(DateUtils.parseFromIso8601("2016-02-08T15:45:59Z")) @@ -918,30 +925,27 @@ void getEventsNoRequestMetadata() { @Test void getEventsTwo() { - requestApplications(this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-metadata-id"); + requestApplicationsV3( + this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-metadata-id"); requestEvents( this.cloudFoundryClient, "test-metadata-id", - fill(EventEntity.builder(), "event-") - .timestamp("2016-02-08T15:45:59Z") - .metadata( + fill(AuditEventResource.builder(), "event-") + .createdAt("2016-02-08T15:45:59Z") + .data( "request", - Optional.of( - FluentMap.builder() - .entry("instances", 1) - .entry("memory", 2) - .entry("environment_json", "test-data") - .entry("state", "test-state") - .build())) + FluentMap.builder() + .entry("instances", 1) + .entry("memory", 2) + .entry("environment_json", "test-data") + .entry("state", "test-state") + .build()) .build(), - fill(EventEntity.builder(), "event-") - .timestamp("2016-02-08T15:49:07Z") - .metadata( + fill(AuditEventResource.builder(), "event-") + .createdAt("2016-02-08T15:49:07Z") + .data( "request", - Optional.of( - FluentMap.builder() - .entry("state", "test-state-two") - .build())) + FluentMap.builder().entry("state", "test-state-two").build()) .build()); this.applications @@ -949,7 +953,7 @@ void getEventsTwo() { .as(StepVerifier::create) .expectNext( ApplicationEvent.builder() - .actor("test-event-actorName") + .actor("test-event-name") .description( "instances: 1, memory: 2, state: test-state," + " environment_json: test-data") @@ -958,7 +962,7 @@ void getEventsTwo() { .time(DateUtils.parseFromIso8601("2016-02-08T15:45:59Z")) .build(), ApplicationEvent.builder() - .actor("test-event-actorName") + .actor("test-event-name") .description("state: test-state-two") .event("test-event-type") .id("test-event-id") @@ -968,33 +972,38 @@ void getEventsTwo() { .verify(Duration.ofSeconds(5)); } - @Test - void getHealthCheck() { - requestApplications( + @ParameterizedTest + @ValueSource(strings = {"http", "process"}) + void getHealthCheck(String healthCheckType) { + requestApplicationsV3( this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID, - "test-metadata-id"); + "test-application-id"); + requestApplicationProcesses( + this.cloudFoundryClient, + "test-application-id", + HealthCheckType.from(healthCheckType)); this.applications .getHealthCheck( GetApplicationHealthCheckRequest.builder() .name("test-application-name") .build()) + .map(ApplicationHealthCheck::getValue) .as(StepVerifier::create) - .expectNext(ApplicationHealthCheck.PORT) + .expectNext(healthCheckType) .expectComplete() .verify(Duration.ofSeconds(5)); } @Test void getInstancesError() { - requestApplications( + requestApplicationsV3( this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-application-id"); - requestApplicationStatistics(this.cloudFoundryClient, "test-application-id"); requestStack(this.cloudFoundryClient, "test-application-stackId"); requestApplicationSummary(this.cloudFoundryClient, "test-application-id"); - requestApplicationInstancesError(this.cloudFoundryClient, "test-application-id", 220001); + requestProcessStatisticsError(this.cloudFoundryClient, "test-application-id", 220001); requestGetApplicationV3Buildpack(this.cloudFoundryClient, "test-application-id"); this.applications @@ -1007,7 +1016,7 @@ void getInstancesError() { .lastUploaded(new Date(0)) .name("test-application-summary-name") .requestedState("test-application-summary-state") - .stack("test-stack-entity-name") + .stack("test-stack") .url("test-route-host.test-domain-name/test-path") .build()) .expectComplete() @@ -1016,12 +1025,11 @@ void getInstancesError() { @Test void getNoBuildpack() { - requestApplications( + requestApplicationsV3( this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-application-id"); - requestApplicationStatistics(this.cloudFoundryClient, "test-application-id"); + requestApplicationProcessStatistics(this.cloudFoundryClient, "test-application-id"); requestStack(this.cloudFoundryClient, "test-application-stackId"); requestApplicationSummaryNoBuildpack(this.cloudFoundryClient, "test-application-id"); - requestApplicationInstances(this.cloudFoundryClient, "test-application-id"); requestGetApplicationV3Docker(this.cloudFoundryClient, "test-application-id"); this.applications @@ -1033,15 +1041,15 @@ void getNoBuildpack() { .id("test-application-summary-id") .instanceDetail( fill(InstanceDetail.builder()) - .index("instance-0") - .since(new Date(1000)) - .state("test-application-instance-info-state") + .since(null) + .index("1") + .state("RUNNING") .build()) .lastUploaded(new Date(0)) .name("test-application-summary-name") .requestedState("test-application-summary-state") - .stack("test-stack-entity-name") - .url("test-route-host.test-domain-name:1") + .stack("test-stack") + .url("test-route-host.test-domain-name/test-path") .build()) .expectComplete() .verify(Duration.ofSeconds(5)); @@ -1049,12 +1057,11 @@ void getNoBuildpack() { @Test void getStagingError() { - requestApplications( + requestApplicationsV3( this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-application-id"); - requestApplicationStatistics(this.cloudFoundryClient, "test-application-id"); requestStack(this.cloudFoundryClient, "test-application-stackId"); requestApplicationSummary(this.cloudFoundryClient, "test-application-id"); - requestApplicationInstancesError(this.cloudFoundryClient, "test-application-id", 170002); + requestProcessStatisticsError(this.cloudFoundryClient, "test-application-id", 170002); requestGetApplicationV3Buildpack(this.cloudFoundryClient, "test-application-id"); this.applications @@ -1067,7 +1074,7 @@ void getStagingError() { .lastUploaded(new Date(0)) .name("test-application-summary-name") .requestedState("test-application-summary-state") - .stack("test-stack-entity-name") + .stack("test-stack") .url("test-route-host.test-domain-name/test-path") .build()) .expectComplete() @@ -1076,12 +1083,11 @@ void getStagingError() { @Test void getStoppedError() { - requestApplications( + requestApplicationsV3( this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-application-id"); - requestApplicationStatisticsError(this.cloudFoundryClient, "test-application-id", 200003); requestStack(this.cloudFoundryClient, "test-application-stackId"); requestApplicationSummary(this.cloudFoundryClient, "test-application-id"); - requestApplicationInstances(this.cloudFoundryClient, "test-application-id"); + requestProcessStatisticsError(this.cloudFoundryClient, "test-application-id", 200003); requestGetApplicationV3Buildpack(this.cloudFoundryClient, "test-application-id"); this.applications @@ -1091,16 +1097,10 @@ void getStoppedError() { fill(ApplicationDetail.builder()) .buildpack("test-buildpack") .id("test-application-summary-id") - .instanceDetail( - InstanceDetail.builder() - .index("instance-0") - .since(new Date(1000)) - .state("test-application-instance-info-state") - .build()) .lastUploaded(new Date(0)) .name("test-application-summary-name") .requestedState("test-application-summary-state") - .stack("test-stack-entity-name") + .stack("test-stack") .url("test-route-host.test-domain-name/test-path") .build()) .expectComplete() @@ -1109,105 +1109,11 @@ void getStoppedError() { @Test void getWithEmptyInstance() { - requestApplications( - this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-application-id"); - requestApplicationStatistics(this.cloudFoundryClient, "test-application-id"); - requestStack(this.cloudFoundryClient, "test-application-stackId"); - requestApplicationSummary(this.cloudFoundryClient, "test-application-id"); - requestApplicationEmptyInstance(this.cloudFoundryClient, "test-application-id"); - requestGetApplicationV3Buildpack(this.cloudFoundryClient, "test-application-id"); - - this.applications - .get(GetApplicationRequest.builder().name("test-app").build()) - .as(StepVerifier::create) - .expectNext( - fill(ApplicationDetail.builder()) - .buildpack("test-buildpack") - .id("test-application-summary-id") - .instanceDetail( - fill(InstanceDetail.builder()) - .index("instance-0") - .since(null) - .state(null) - .build()) - .lastUploaded(new Date(0)) - .name("test-application-summary-name") - .requestedState("test-application-summary-state") - .stack("test-stack-entity-name") - .url("test-route-host.test-domain-name/test-path") - .build()) - .expectComplete() - .verify(Duration.ofSeconds(5)); - } - - @Test - void getWithEmptyInstanceStats() { - requestApplications( - this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-application-id"); - requestApplicationEmptyStats(this.cloudFoundryClient, "test-application-id"); - requestStack(this.cloudFoundryClient, "test-application-stackId"); - requestApplicationSummary(this.cloudFoundryClient, "test-application-id"); - requestApplicationInstances(this.cloudFoundryClient, "test-application-id"); - requestGetApplicationV3Buildpack(this.cloudFoundryClient, "test-application-id"); - - this.applications - .get(GetApplicationRequest.builder().name("test-app").build()) - .as(StepVerifier::create) - .expectNext( - fill(ApplicationDetail.builder()) - .buildpack("test-buildpack") - .id("test-application-summary-id") - .instanceDetail( - InstanceDetail.builder() - .index("instance-0") - .since(new Date(1000)) - .state("test-application-instance-info-state") - .build()) - .lastUploaded(new Date(0)) - .name("test-application-summary-name") - .requestedState("test-application-summary-state") - .stack("test-stack-entity-name") - .url("test-route-host.test-domain-name/test-path") - .build()) - .expectComplete() - .verify(Duration.ofSeconds(5)); - } - - @Test - void getWithNoInstances() { - requestApplications( - this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-application-id"); - requestApplicationStatistics(this.cloudFoundryClient, "test-application-id"); - requestStack(this.cloudFoundryClient, "test-application-stackId"); - requestApplicationSummary(this.cloudFoundryClient, "test-application-id"); - requestApplicationNoInstances(this.cloudFoundryClient, "test-application-id"); - requestGetApplicationV3Buildpack(this.cloudFoundryClient, "test-application-id"); - - this.applications - .get(GetApplicationRequest.builder().name("test-app").build()) - .as(StepVerifier::create) - .expectNext( - fill(ApplicationDetail.builder()) - .buildpack("test-buildpack") - .id("test-application-summary-id") - .lastUploaded(new Date(0)) - .name("test-application-summary-name") - .requestedState("test-application-summary-state") - .stack("test-stack-entity-name") - .url("test-route-host.test-domain-name/test-path") - .build()) - .expectComplete() - .verify(Duration.ofSeconds(5)); - } - - @Test - void getWithNullStats() { - requestApplications( + requestApplicationsV3( this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-application-id"); - requestApplicationNullStats(this.cloudFoundryClient, "test-application-id"); + requestApplicationProcessStatisticsEmpty(this.cloudFoundryClient, "test-application-id"); requestStack(this.cloudFoundryClient, "test-application-stackId"); requestApplicationSummary(this.cloudFoundryClient, "test-application-id"); - requestApplicationInstances(this.cloudFoundryClient, "test-application-id"); requestGetApplicationV3Buildpack(this.cloudFoundryClient, "test-application-id"); this.applications @@ -1217,16 +1123,10 @@ void getWithNullStats() { fill(ApplicationDetail.builder()) .buildpack("test-buildpack") .id("test-application-summary-id") - .instanceDetail( - InstanceDetail.builder() - .index("instance-0") - .since(new Date(1000)) - .state("test-application-instance-info-state") - .build()) .lastUploaded(new Date(0)) .name("test-application-summary-name") .requestedState("test-application-summary-state") - .stack("test-stack-entity-name") + .stack("test-stack") .url("test-route-host.test-domain-name/test-path") .build()) .expectComplete() @@ -1235,12 +1135,12 @@ void getWithNullStats() { @Test void getWithNullUsage() { - requestApplications( + requestApplicationsV3( this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-application-id"); - requestApplicationNullUsage(this.cloudFoundryClient, "test-application-id"); + requestApplicationProcessStatisticsNullUsage( + this.cloudFoundryClient, "test-application-id"); requestStack(this.cloudFoundryClient, "test-application-stackId"); requestApplicationSummary(this.cloudFoundryClient, "test-application-id"); - requestApplicationInstances(this.cloudFoundryClient, "test-application-id"); requestGetApplicationV3Buildpack(this.cloudFoundryClient, "test-application-id"); this.applications @@ -1252,16 +1152,16 @@ void getWithNullUsage() { .id("test-application-summary-id") .instanceDetail( InstanceDetail.builder() - .index("instance-0") + .index("1") .diskQuota(1L) .memoryQuota(1L) - .since(new Date(1000)) - .state("test-application-instance-info-state") + .since(null) + .state("RUNNING") .build()) .lastUploaded(new Date(0)) .name("test-application-summary-name") .requestedState("test-application-summary-state") - .stack("test-stack-entity-name") + .stack("test-stack") .url("test-route-host.test-domain-name/test-path") .build()) .expectComplete() @@ -1308,7 +1208,7 @@ void listTasks() { @Test void logs() { - requestApplications( + requestApplicationsV3( this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID, @@ -1325,7 +1225,7 @@ void logs() { @Test void logsNoApp() { - requestApplicationsEmpty(this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID); + requestApplicationsEmptyV3(this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID); this.applications .logs(LogsRequest.builder().name("test-application-name").build()) @@ -1341,7 +1241,7 @@ void logsNoApp() { @Test void logsRecent() { - requestApplications( + requestApplicationsV3( this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID, @@ -1358,7 +1258,7 @@ void logsRecent() { @Test void logsRecentNotSet() { - requestApplications( + requestApplicationsV3( this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID, @@ -3206,7 +3106,7 @@ void pushUploadFails() throws IOException { @Test void rename() { - requestApplications( + requestApplicationsV3( this.cloudFoundryClient, "test-app-name", TEST_SPACE_ID, "test-metadata-id"); requestUpdateApplicationRename( this.cloudFoundryClient, "test-metadata-id", "test-new-app-name"); @@ -3224,7 +3124,7 @@ void rename() { @Test void renameNoApp() { - requestApplicationsEmpty(this.cloudFoundryClient, "test-app-name", TEST_SPACE_ID); + requestApplicationsEmptyV3(this.cloudFoundryClient, "test-app-name", TEST_SPACE_ID); this.applications .rename( @@ -3637,21 +3537,12 @@ void scaleNoChange() { @Test void setEnvironmentVariable() { - requestApplications( - this.cloudFoundryClient, - "test-app", - TEST_SPACE_ID, - "test-metadata-id", - FluentMap.builder() - .entry("test-var", "test-value") - .entry("test-var2", "test-value2") - .build()); + requestApplicationsV3( + this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-application-id"); requestUpdateApplicationEnvironment( this.cloudFoundryClient, - "test-metadata-id", - FluentMap.builder() - .entry("test-var", "test-value") - .entry("test-var2", "test-value2") + "test-application-id", + FluentMap.builder() .entry("test-var-name", "test-var-value") .build()); @@ -3669,7 +3560,7 @@ void setEnvironmentVariable() { @Test void setEnvironmentVariableNoApp() { - requestApplicationsEmpty(this.cloudFoundryClient, "test-app", TEST_SPACE_ID); + requestApplicationsEmptyV3(this.cloudFoundryClient, "test-app", TEST_SPACE_ID); this.applications .setEnvironmentVariable( @@ -3689,13 +3580,15 @@ void setEnvironmentVariableNoApp() { @Test void setHealthCheck() { - requestApplications( + requestApplicationsV3( this.cloudFoundryClient, "test-application-name", TEST_SPACE_ID, "test-application-id"); + requestApplicationProcesses( + cloudFoundryClient, "test-application-id", HealthCheckType.HTTP); requestUpdateApplicationHealthCheck( - this.cloudFoundryClient, "test-application-id", ApplicationHealthCheck.PORT); + this.cloudFoundryClient, "test-process-id", ApplicationHealthCheck.PORT); this.applications .setHealthCheck( @@ -3706,6 +3599,14 @@ void setHealthCheck() { .as(StepVerifier::create) .expectComplete() .verify(Duration.ofSeconds(5)); + + verify(this.cloudFoundryClient.processes()) + .update( + argThat( + argument -> + argument.getHealthCheck() + .getType() + .equals(HealthCheckType.PORT))); } @Test @@ -3942,23 +3843,12 @@ void terminateTaskNoTask() { @Test void unsetEnvironmentVariable() { - requestApplications( - this.cloudFoundryClient, - "test-app", - TEST_SPACE_ID, - "test-metadata-id", - FluentMap.builder() - .entry("test-var", "test-value") - .entry("test-var2", "test-value2") - .entry("test-var-name", "test-var-value") - .build()); + requestApplicationsV3( + this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-application-id"); requestUpdateApplicationEnvironment( this.cloudFoundryClient, - "test-metadata-id", - FluentMap.builder() - .entry("test-var2", "test-value2") - .entry("test-var-name", "test-var-value") - .build()); + "test-application-id", + FluentMap.builder().entry("test-var", null).build()); this.applications .unsetEnvironmentVariable( @@ -3973,7 +3863,7 @@ void unsetEnvironmentVariable() { @Test void unsetEnvironmentVariableNoApp() { - requestApplicationsEmpty(this.cloudFoundryClient, "test-app", TEST_SPACE_ID); + requestApplicationsEmptyV3(this.cloudFoundryClient, "test-app", TEST_SPACE_ID); this.applications .unsetEnvironmentVariable( @@ -3995,23 +3885,6 @@ private static void provideRandomWords(RandomWords randomWords) { when(randomWords.getNoun()).thenReturn("test-noun"); } - private static void requestApplicationEmptyInstance( - CloudFoundryClient cloudFoundryClient, String applicationId) { - when(cloudFoundryClient - .applicationsV2() - .instances( - ApplicationInstancesRequest.builder() - .applicationId(applicationId) - .build())) - .thenReturn( - Mono.just( - ApplicationInstancesResponse.builder() - .instance( - "instance-0", - ApplicationInstanceInfo.builder().build()) - .build())); - } - private static void requestApplicationEmptyStats( CloudFoundryClient cloudFoundryClient, String applicationId) { when(cloudFoundryClient @@ -4066,6 +3939,27 @@ private static void requestApplicationInstances( .build())); } + private static void requestProcessStatisticsError( + CloudFoundryClient cloudFoundryClient, String applicationId, Integer code) { + when(cloudFoundryClient + .applicationsV3() + .getProcessStatistics( + GetApplicationProcessStatisticsRequest.builder() + .applicationId(applicationId) + .type("web") + .build())) + .thenReturn( + Mono.error( + new ClientV3Exception( + null, + Collections.singletonList( + Error.builder() + .code(code) + .title("test-error-title") + .detail("test-error-detail") + .build())))); + } + private static void requestApplicationInstancesError( CloudFoundryClient cloudFoundryClient, String applicationId, Integer code) { when(cloudFoundryClient @@ -4111,6 +4005,26 @@ private static void requestApplicationInstancesFailingPartial( .state("FLAPPING") .build()) .build())); + when(cloudFoundryClient.applicationsV3().getProcessStatistics(any())) + .thenReturn( + Mono.just( + GetApplicationProcessStatisticsResponse.builder() + .resources( + fill(ProcessStatisticsResource.builder()) + .state(ProcessState.RUNNING) + .type("web") + .uptime(1L) + .fileDescriptorQuota(1L) + .host("test-host") + .build(), + fill(ProcessStatisticsResource.builder()) + .state(ProcessState.CRASHED) + .type("web") + .uptime(1L) + .fileDescriptorQuota(1L) + .host("test-host") + .build()) + .build())); } private static void requestApplicationInstancesFailingTotal( @@ -4134,6 +4048,19 @@ private static void requestApplicationInstancesFailingTotal( .state("FLAPPING") .build()) .build())); + when(cloudFoundryClient.applicationsV3().getProcessStatistics(any())) + .thenReturn( + Mono.just( + GetApplicationProcessStatisticsResponse.builder() + .resource( + fill(ProcessStatisticsResource.builder()) + .state(ProcessState.CRASHED) + .type("web") + .uptime(1L) + .fileDescriptorQuota(1L) + .host("test-host") + .build()) + .build())); } private static void requestApplicationInstancesRunning( @@ -4157,6 +4084,20 @@ private static void requestApplicationInstancesRunning( .state("RUNNING") .build()) .build())); + + when(cloudFoundryClient.applicationsV3().getProcessStatistics(any())) + .thenReturn( + Mono.just( + GetApplicationProcessStatisticsResponse.builder() + .resource( + fill(ProcessStatisticsResource.builder()) + .state(ProcessState.RUNNING) + .type("web") + .uptime(1L) + .fileDescriptorQuota(1L) + .host("test-host") + .build()) + .build())); } private static void requestApplicationInstancesTimeout( @@ -4180,17 +4121,19 @@ private static void requestApplicationInstancesTimeout( .state("STARTING") .build()) .build())); - } - - private static void requestApplicationNoInstances( - CloudFoundryClient cloudFoundryClient, String applicationId) { - when(cloudFoundryClient - .applicationsV2() - .instances( - ApplicationInstancesRequest.builder() - .applicationId(applicationId) - .build())) - .thenReturn(Mono.just(ApplicationInstancesResponse.builder().build())); + when(cloudFoundryClient.applicationsV3().getProcessStatistics(any())) + .thenReturn( + Mono.just( + GetApplicationProcessStatisticsResponse.builder() + .resource( + fill(ProcessStatisticsResource.builder()) + .state(ProcessState.STARTING) + .type("web") + .uptime(1L) + .fileDescriptorQuota(1L) + .host("test-host") + .build()) + .build())); } private static void requestApplicationNullStats( @@ -4244,30 +4187,30 @@ private static void requestApplicationNullUsage( private static void requestApplicationRoutes( CloudFoundryClient cloudFoundryClient, String applicationId, String routeId) { when(cloudFoundryClient - .applicationsV2() + .applicationsV3() .listRoutes( - ListApplicationRoutesRequest.builder() + org.cloudfoundry.client.v3.applications.ListApplicationRoutesRequest + .builder() .applicationId(applicationId) .page(1) .build())) .thenReturn( Mono.just( - fill(ListApplicationRoutesResponse.builder()) + fill(org.cloudfoundry.client.v3.applications + .ListApplicationRoutesResponse.builder()) .resource( - fill(RouteResource.builder()) - .metadata( - fill(Metadata.builder()) - .id(routeId) - .build()) + fill(org.cloudfoundry.client.v3.routes.RouteResource + .builder()) + .id(routeId) .build()) - .totalPages(1) + .pagination(Pagination.builder().totalPages(1).build()) .build())); } private static void requestApplicationRoutesEmpty( CloudFoundryClient cloudFoundryClient, String applicationId) { when(cloudFoundryClient - .applicationsV2() + .applicationsV3() .listRoutes( ListApplicationRoutesRequest.builder() .applicationId(applicationId) @@ -4276,7 +4219,7 @@ private static void requestApplicationRoutesEmpty( .thenReturn( Mono.just( fill(ListApplicationRoutesResponse.builder()) - .totalPages(1) + .pagination(Pagination.builder().totalPages(1).build()) .build())); } @@ -4432,6 +4375,8 @@ private static void requestApplicationSummaryDetectedBuildpack( .builder(), "domain-") .build()) + .port(null) + .path("/test-path") .build()) .buildpack(null) .packageUpdatedAt(DateUtils.formatToIso8601(new Date(0))) @@ -4507,6 +4452,8 @@ private static void requestApplicationSummaryNoBuildpack( .builder(), "domain-") .build()) + .path("/test-path") + .port(null) .build()) .buildpack(null) .detectedBuildpack(null) @@ -4572,6 +4519,69 @@ private static void requestApplicationSummaryTcp( .build())); } + private static void requestApplicationProcessStatistics( + CloudFoundryClient cloudFoundryClient, String applicationId) { + when(cloudFoundryClient + .applicationsV3() + .getProcessStatistics( + GetApplicationProcessStatisticsRequest.builder() + .applicationId(applicationId) + .type("web") + .build())) + .thenReturn( + Mono.just( + GetApplicationProcessStatisticsResponse.builder() + .resources( + fill(ProcessStatisticsResource.builder()) + .state(ProcessState.RUNNING) + .type("web") + .uptime(1L) + .fileDescriptorQuota(1L) + .host("test-host") + .build()) + .build())); + } + + private static void requestApplicationProcessStatisticsEmpty( + CloudFoundryClient cloudFoundryClient, String applicationId) { + when(cloudFoundryClient + .applicationsV3() + .getProcessStatistics( + GetApplicationProcessStatisticsRequest.builder() + .applicationId(applicationId) + .type("web") + .build())) + .thenReturn( + Mono.just( + GetApplicationProcessStatisticsResponse.builder() + .resources() + .build())); + } + + private static void requestApplicationProcessStatisticsNullUsage( + CloudFoundryClient cloudFoundryClient, String applicationId) { + when(cloudFoundryClient + .applicationsV3() + .getProcessStatistics( + GetApplicationProcessStatisticsRequest.builder() + .applicationId(applicationId) + .type("web") + .build())) + .thenReturn( + Mono.just( + GetApplicationProcessStatisticsResponse.builder() + .resources( + fill(ProcessStatisticsResource.builder()) + .state(ProcessState.RUNNING) + .type("web") + .uptime(1L) + .fileDescriptorQuota(1L) + .host("test-host") + .usage(null) + .build()) + .build())); + } + private static void requestApplications( CloudFoundryClient cloudFoundryClient, String application, @@ -4697,61 +4707,37 @@ private static void requestApplicationsV3( Mono.just( fill(ListApplicationsResponse.builder()) .resource( - org.cloudfoundry.client.v3.applications - .ApplicationResource.builder() - .createdAt("test-created-at") - .id(applicationId) + fill(org.cloudfoundry.client.v3.applications + .ApplicationResource.builder()) .lifecycle( - Lifecycle.builder() + fill(Lifecycle.builder()) + .type(BUILDPACK) .data( BuildpackData .builder() - .buildpack( - "test-buildpack") + .stack( + "test-stack") .build()) - .type(BUILDPACK) .build()) - .name("test-name") + .id(applicationId) .state(ApplicationState.STOPPED) - .updatedAt("test-updated-at") .build()) .build())); } - private static void requestApplicationsWithSsh( - CloudFoundryClient cloudFoundryClient, - String application, - String spaceId, - Boolean sshEnabled) { + private static void requestApplicationProcesses( + CloudFoundryClient cloudFoundryClient, String applicationId, HealthCheckType type) { when(cloudFoundryClient - .spaces() - .listApplications( - ListSpaceApplicationsRequest.builder() - .name(application) - .spaceId(spaceId) - .page(1) + .applicationsV3() + .getProcess( + GetApplicationProcessRequest.builder() + .applicationId(applicationId) + .type("web") .build())) .thenReturn( Mono.just( - fill(ListSpaceApplicationsResponse.builder()) - .resource( - ApplicationResource.builder() - .metadata( - fill(Metadata.builder()) - .id("test-application-id") - .build()) - .entity( - fill( - ApplicationEntity - .builder(), - "application-") - .environmentJson( - "test-var", - "test-value") - .enableSsh(sshEnabled) - .build()) - .build()) - .totalPages(1) + fill(GetApplicationProcessResponse.builder(), "process-") + .healthCheck(fill(HealthCheck.builder()).type(type).build()) .build())); } @@ -4941,27 +4927,31 @@ private static void requestDeleteRoute(CloudFoundryClient cloudFoundryClient, St } private static void requestEvents( - CloudFoundryClient cloudFoundryClient, String applicationId, EventEntity... entities) { - ListEventsResponse.Builder responseBuilder = fill(ListEventsResponse.builder()); - - for (EventEntity entity : entities) { - responseBuilder.resource( - EventResource.builder() - .metadata(fill(Metadata.builder()).id("test-event-id").build()) - .entity(entity) - .build()); - } + CloudFoundryClient cloudFoundryClient, + String applicationId, + AuditEventResource... entities) { + ListAuditEventsResponse.Builder responseBuilder = fill(ListAuditEventsResponse.builder()); + responseBuilder.resources(entities); + + // for (AuditEventResource entity : entities) { + // HashMap data = new HashMap<>(); + // data.put("id", "test-event-id"); + // } when(cloudFoundryClient - .events() + .auditEventsV3() .list( - ListEventsRequest.builder() - .actee(applicationId) - .orderDirection(OrderDirection.DESCENDING) - .resultsPerPage(50) + ListAuditEventsRequest.builder() + .targetId(applicationId) + .orderBy("-created_at") + .perPage(50) .page(1) .build())) - .thenReturn(Mono.just(responseBuilder.totalPages(1).build())); + .thenReturn( + Mono.just( + responseBuilder + .pagination(Pagination.builder().totalPages(1).build()) + .build())); } private static void requestGetApplication( @@ -5050,6 +5040,20 @@ private static void requestInstancesApplicationFailing( .state("FAILED") .build()) .build())); + + when(cloudFoundryClient.applicationsV3().getProcessStatistics(any())) + .thenReturn( + Mono.just( + GetApplicationProcessStatisticsResponse.builder() + .resources( + fill(ProcessStatisticsResource.builder()) + .state(ProcessState.CRASHED) + .type("web") + .uptime(1L) + .fileDescriptorQuota(1L) + .host("test-host") + .build()) + .build())); } private static void requestGetApplicationTimeout( @@ -5082,21 +5086,18 @@ private static void requestGetApplicationV3Buildpack( .build())) .thenReturn( Mono.just( - org.cloudfoundry.client.v3.applications.GetApplicationResponse - .builder() - .createdAt("test-created-at") + fill(org.cloudfoundry.client.v3.applications.GetApplicationResponse + .builder()) .id(applicationId) .lifecycle( - Lifecycle.builder() + fill(Lifecycle.builder()) .data( BuildpackData.builder() .buildpack("test-buildpack") .build()) .type(BUILDPACK) .build()) - .name("test-name") .state(ApplicationState.STOPPED) - .updatedAt("test-updated-at") .build())); } @@ -5111,23 +5112,19 @@ private static void requestGetApplicationV3BuildpackMultiple( .build())) .thenReturn( Mono.just( - org.cloudfoundry.client.v3.applications.GetApplicationResponse - .builder() - .createdAt("test-created-at") - .id(applicationId) + fill(org.cloudfoundry.client.v3.applications.GetApplicationResponse + .builder()) .lifecycle( Lifecycle.builder() .data( BuildpackData.builder() .buildpacks( - "test-buildpack-1", - "test-buildpack-2") + "test-application-summary-detectedBuildpack-1", + "test-application-summary-detectedBuildpack-2") .build()) .type(BUILDPACK) .build()) - .name("test-name") .state(ApplicationState.STOPPED) - .updatedAt("test-updated-at") .build())); } @@ -5142,18 +5139,15 @@ private static void requestGetApplicationV3Docker( .build())) .thenReturn( Mono.just( - org.cloudfoundry.client.v3.applications.GetApplicationResponse - .builder() - .createdAt("test-created-at") + fill(org.cloudfoundry.client.v3.applications.GetApplicationResponse + .builder()) .id(applicationId) .lifecycle( Lifecycle.builder() .data(DockerData.builder().build()) .type(DOCKER) .build()) - .name("test-name") .state(ApplicationState.STOPPED) - .updatedAt("test-updated-at") .build())); } @@ -5663,19 +5657,19 @@ private static void requestSpaceSummary(CloudFoundryClient cloudFoundryClient, S } private static void requestStack(CloudFoundryClient cloudFoundryClient, String stackId) { - when(cloudFoundryClient.stacks().get(GetStackRequest.builder().stackId(stackId).build())) + when(cloudFoundryClient.stacksV3().get(GetStackRequest.builder().stackId(stackId).build())) .thenReturn( Mono.just( - fill(GetStackResponse.builder()) - .entity( - fill(StackEntity.builder(), "stack-entity-") - .build()) + fill( + org.cloudfoundry.client.v3.stacks.GetStackResponse + .builder(), + "stack-entity-") .build())); } private static void requestStackIdEmpty(CloudFoundryClient cloudFoundryClient, String stack) { when(cloudFoundryClient - .stacks() + .stacksV3() .list(ListStacksRequest.builder().name(stack).page(1).build())) .thenReturn(Mono.just(fill(ListStacksResponse.builder()).build())); } @@ -5764,63 +5758,49 @@ private static void requestUpdateApplication( private static void requestUpdateApplicationEnvironment( CloudFoundryClient cloudFoundryClient, String applicationId, - Map environment) { + Map environment) { when(cloudFoundryClient - .applicationsV2() - .update( - UpdateApplicationRequest.builder() + .applicationsV3() + .updateEnvironmentVariables( + UpdateApplicationEnvironmentVariablesRequest.builder() .applicationId(applicationId) - .environmentJsons(environment) + .putAllVars(environment) .build())) .thenReturn( Mono.just( - fill(UpdateApplicationResponse.builder()) - .entity( - fill(ApplicationEntity.builder()) - .environmentJsons(environment) - .build()) + fill(UpdateApplicationEnvironmentVariablesResponse.builder()) .build())); } private static void requestUpdateApplicationHealthCheck( - CloudFoundryClient cloudFoundryClient, - String applicationId, - ApplicationHealthCheck type) { + CloudFoundryClient cloudFoundryClient, String processId, ApplicationHealthCheck type) { when(cloudFoundryClient - .applicationsV2() + .processes() .update( - UpdateApplicationRequest.builder() - .applicationId(applicationId) - .healthCheckType(type.getValue()) - .build())) - .thenReturn( - Mono.just( - fill(UpdateApplicationResponse.builder()) - .entity( - fill( - ApplicationEntity.builder(), - "application-entity-") + UpdateProcessRequest.builder() + .processId(processId) + .healthCheck( + HealthCheck.builder() + .type(HealthCheckType.from(type.getValue())) .build()) - .build())); + .build())) + .thenReturn(Mono.just(fill(UpdateProcessResponse.builder()).build())); } private static void requestUpdateApplicationRename( CloudFoundryClient cloudFoundryClient, String applicationId, String name) { when(cloudFoundryClient - .applicationsV2() + .applicationsV3() .update( - UpdateApplicationRequest.builder() + org.cloudfoundry.client.v3.applications.UpdateApplicationRequest + .builder() .applicationId(applicationId) .name(name) .build())) .thenReturn( Mono.just( - fill(UpdateApplicationResponse.builder()) - .entity( - fill( - ApplicationEntity.builder(), - "application-entity-") - .build()) + fill(org.cloudfoundry.client.v3.applications + .UpdateApplicationResponse.builder()) .build())); } diff --git a/cloudfoundry-util/src/main/java/org/cloudfoundry/util/ExceptionUtils.java b/cloudfoundry-util/src/main/java/org/cloudfoundry/util/ExceptionUtils.java index 0d128ea5c6..5ede066f3c 100644 --- a/cloudfoundry-util/src/main/java/org/cloudfoundry/util/ExceptionUtils.java +++ b/cloudfoundry-util/src/main/java/org/cloudfoundry/util/ExceptionUtils.java @@ -17,8 +17,12 @@ package org.cloudfoundry.util; import java.util.Arrays; +import java.util.Set; import java.util.function.Predicate; +import java.util.stream.Collectors; import org.cloudfoundry.client.v2.ClientV2Exception; +import org.cloudfoundry.client.v3.ClientV3Exception; +import org.cloudfoundry.client.v3.Error; import reactor.core.publisher.Mono; /** @@ -74,4 +78,22 @@ public static Predicate statusCode(int... codes) { .getCode() .equals(candidate)); } + + /** + * A predicate that returns {@code true} if the exception is a {@link ClientV2Exception} and its code matches expectation + * + * @param codes the codes to match + * @return {@code true} if the exception is a {@link ClientV2Exception} and its code matches + */ + public static Predicate statusCodeV3(int... codes) { + return t -> { + if (!(t instanceof ClientV3Exception)) { + return false; + } + ClientV3Exception exception = (ClientV3Exception) t; + Set errorCodes = + exception.getErrors().stream().map(Error::getCode).collect(Collectors.toSet()); + return Arrays.stream(codes).anyMatch(errorCodes::contains); + }; + } } diff --git a/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java b/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java index 36c30c3578..bc98757ffb 100644 --- a/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java +++ b/integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java @@ -270,6 +270,7 @@ ReactorCloudFoundryClient cloudFoundryClient( } @Bean + @DependsOn({"organizationId", "spaceId"}) DefaultCloudFoundryOperations cloudFoundryOperations( CloudFoundryClient cloudFoundryClient, DopplerClient dopplerClient,