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 af2a190df6..03ddf9527c 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 @@ -44,8 +44,6 @@ 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.ApplicationEnvironmentRequest; -import org.cloudfoundry.client.v2.applications.ApplicationEnvironmentResponse; import org.cloudfoundry.client.v2.applications.ApplicationInstanceInfo; import org.cloudfoundry.client.v2.applications.ApplicationInstancesRequest; import org.cloudfoundry.client.v2.applications.ApplicationInstancesResponse; @@ -111,11 +109,17 @@ import org.cloudfoundry.client.v3.Relationship; import org.cloudfoundry.client.v3.Resource; import org.cloudfoundry.client.v3.ToOneRelationship; +import org.cloudfoundry.client.v3.applications.ApplicationFeature; 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.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.ListApplicationsRequest; import org.cloudfoundry.client.v3.applications.SetApplicationCurrentDropletRequest; +import org.cloudfoundry.client.v3.applications.UpdateApplicationFeatureRequest; import org.cloudfoundry.client.v3.builds.BuildState; import org.cloudfoundry.client.v3.builds.CreateBuildRequest; import org.cloudfoundry.client.v3.builds.CreateBuildResponse; @@ -202,6 +206,8 @@ public final class DefaultApplications implements Applications { private static final String STOPPED_STATE = "STOPPED"; + private static final String APP_FEATURE_SSH = "ssh"; + private final Mono cloudFoundryClient; private final Mono dopplerClient; @@ -320,11 +326,21 @@ public Mono disableSsh(DisableApplicationSshRequest request) { (cloudFoundryClient, spaceId) -> Mono.zip( Mono.just(cloudFoundryClient), - getApplicationIdWhere( + getApplicationIdV3( cloudFoundryClient, request.getName(), - spaceId, - sshEnabled(true))))) + 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) -> @@ -343,11 +359,21 @@ public Mono enableSsh(EnableApplicationSshRequest request) { (cloudFoundryClient, spaceId) -> Mono.zip( Mono.just(cloudFoundryClient), - getApplicationIdWhere( + getApplicationIdV3( cloudFoundryClient, request.getName(), - spaceId, - sshEnabled(false))))) + 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) -> @@ -420,7 +446,7 @@ public Mono getEnvironments( (cloudFoundryClient, spaceId) -> Mono.zip( Mono.just(cloudFoundryClient), - getApplicationId( + getApplicationIdV3( cloudFoundryClient, request.getName(), spaceId)))) @@ -906,15 +932,28 @@ public Mono sshEnabled(ApplicationSshEnabledRequest request) { .flatMap( function( (cloudFoundryClient, spaceId) -> - getApplication( - cloudFoundryClient, request.getName(), spaceId))) - .map( - applicationResource -> - ResourceUtils.getEntity(applicationResource).getEnableSsh()) + Mono.zip( + Mono.just(cloudFoundryClient), + getApplicationIdV3( + cloudFoundryClient, + request.getName(), + spaceId)))) + .flatMap(function(DefaultApplications::getSshEnabled)) .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) @@ -2086,12 +2125,12 @@ private static Mono removeServiceBindings( .then(); } - private static Mono requestApplicationEnvironment( + private static Mono requestApplicationEnvironment( CloudFoundryClient cloudFoundryClient, String applicationId) { return cloudFoundryClient - .applicationsV2() - .environment( - ApplicationEnvironmentRequest.builder() + .applicationsV3() + .getEnvironment( + GetApplicationEnvironmentRequest.builder() .applicationId(applicationId) .build()); } @@ -2662,6 +2701,29 @@ private static Mono requestUpdateApplicationName( cloudFoundryClient, applicationId, builder -> builder.name(name)); } + private static Mono requestUpdateApplicationSsh( + CloudFoundryClient cloudFoundryClient, String applicationId, boolean enabled) { + return requestUpdateApplicationFeature( + cloudFoundryClient, + applicationId, + builder -> builder.featureName(APP_FEATURE_SSH).enabled(enabled)); + } + + private static Mono requestUpdateApplicationFeature( + CloudFoundryClient cloudFoundryClient, + String applicationId, + UnaryOperator modifier) { + return cloudFoundryClient + .applicationsV3() + .updateFeature( + modifier.apply( + org.cloudfoundry.client.v3.applications + .UpdateApplicationFeatureRequest.builder() + .applicationId(applicationId)) + .build()) + .cast(ApplicationFeature.class); + } + private static Mono requestUpdateApplicationScale( CloudFoundryClient cloudFoundryClient, String applicationId, @@ -2773,10 +2835,6 @@ private static boolean shouldStartApplication(PushApplicationManifestRequest req return !Optional.ofNullable(request.getNoStart()).orElse(false); } - private static Predicate sshEnabled(Boolean enabled) { - return resource -> enabled.equals(ResourceUtils.getEntity(resource).getEnableSsh()); - } - private static Mono startApplicationAndWait( CloudFoundryClient cloudFoundryClient, String application, @@ -2853,12 +2911,12 @@ private static ApplicationDetail toApplicationDetail( } private static ApplicationEnvironments toApplicationEnvironments( - ApplicationEnvironmentResponse response) { + GetApplicationEnvironmentResponse response) { return ApplicationEnvironments.builder() - .running(response.getRunningEnvironmentJsons()) - .staging(response.getStagingEnvironmentJsons()) - .systemProvided(response.getSystemEnvironmentJsons()) - .userProvided(response.getEnvironmentJsons()) + .running(response.getRunningEnvironmentVariables()) + .staging(response.getStagingEnvironmentVariables()) + .systemProvided(response.getSystemEnvironmentVariables()) + .userProvided(response.getEnvironmentVariables()) .build(); } 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 c5afec5a21..2bd120e0f2 100644 --- a/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/AbstractOperationsTest.java +++ b/cloudfoundry-operations/src/test/java/org/cloudfoundry/operations/AbstractOperationsTest.java @@ -80,6 +80,8 @@ public abstract class AbstractOperationsTest { protected static final String TEST_USERNAME = "test-username"; + protected static final String APP_FEATURE_SSH = "ssh"; + protected final ApplicationsV2 applications = mock(ApplicationsV2.class, RETURNS_SMART_NULLS); protected final ApplicationsV3 applicationsV3 = mock(ApplicationsV3.class, RETURNS_SMART_NULLS); 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 d8494294c1..e8730cead5 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 @@ -41,8 +41,6 @@ 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.ApplicationEnvironmentRequest; -import org.cloudfoundry.client.v2.applications.ApplicationEnvironmentResponse; import org.cloudfoundry.client.v2.applications.ApplicationInstanceInfo; import org.cloudfoundry.client.v2.applications.ApplicationInstancesRequest; import org.cloudfoundry.client.v2.applications.ApplicationInstancesResponse; @@ -127,8 +125,14 @@ import org.cloudfoundry.client.v3.DockerData; import org.cloudfoundry.client.v3.Lifecycle; 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.GetApplicationSshEnabledRequest; +import org.cloudfoundry.client.v3.applications.GetApplicationSshEnabledResponse; import org.cloudfoundry.client.v3.applications.ListApplicationsRequest; import org.cloudfoundry.client.v3.applications.ListApplicationsResponse; +import org.cloudfoundry.client.v3.applications.UpdateApplicationFeatureRequest; +import org.cloudfoundry.client.v3.applications.UpdateApplicationFeatureResponse; import org.cloudfoundry.client.v3.tasks.CancelTaskRequest; import org.cloudfoundry.client.v3.tasks.CancelTaskResponse; import org.cloudfoundry.client.v3.tasks.CreateTaskRequest; @@ -406,9 +410,10 @@ void deleteWithBoundRoutes() { @Test void disableSsh() { - requestApplications( - this.cloudFoundryClient, "test-app-name", TEST_SPACE_ID, "test-metadata-id"); - requestUpdateApplicationSsh(this.cloudFoundryClient, "test-metadata-id", false); + requestApplicationsV3( + this.cloudFoundryClient, "test-app-name", TEST_SPACE_ID, "test-application-id"); + requestGetSshEnabled(this.cloudFoundryClient, "test-application-id", true); + requestUpdateApplicationSshV3(this.cloudFoundryClient, "test-application-id", false); this.applications .disableSsh(DisableApplicationSshRequest.builder().name("test-app-name").build()) @@ -419,7 +424,9 @@ void disableSsh() { @Test void disableSshAlreadyDisabled() { - requestApplicationsWithSsh(this.cloudFoundryClient, "test-app-name", TEST_SPACE_ID, false); + requestApplicationsV3( + this.cloudFoundryClient, "test-app-name", TEST_SPACE_ID, "test-application-id"); + requestGetSshEnabled(this.cloudFoundryClient, "test-application-id", false); this.applications .disableSsh(DisableApplicationSshRequest.builder().name("test-app-name").build()) @@ -430,7 +437,7 @@ void disableSshAlreadyDisabled() { @Test void disableSshNoApp() { - requestApplicationsEmpty(this.cloudFoundryClient, "test-app-name", TEST_SPACE_ID); + requestApplicationsEmptyV3(this.cloudFoundryClient, "test-app-name", TEST_SPACE_ID); this.applications .disableSsh(DisableApplicationSshRequest.builder().name("test-app-name").build()) @@ -445,9 +452,10 @@ void disableSshNoApp() { @Test void enableSsh() { - requestApplications( - this.cloudFoundryClient, "test-app-name", TEST_SPACE_ID, "test-metadata-id"); - requestUpdateApplicationSsh(this.cloudFoundryClient, "test-application-id", true); + requestApplicationsV3( + this.cloudFoundryClient, "test-app-name", TEST_SPACE_ID, "test-application-id"); + requestGetSshEnabled(this.cloudFoundryClient, "test-application-id", false); + requestUpdateApplicationSshV3(this.cloudFoundryClient, "test-application-id", true); this.applications .enableSsh(EnableApplicationSshRequest.builder().name("test-app-name").build()) @@ -458,7 +466,9 @@ void enableSsh() { @Test void enableSshAlreadyEnabled() { - requestApplicationsWithSsh(this.cloudFoundryClient, "test-app-name", TEST_SPACE_ID, true); + requestApplicationsV3( + this.cloudFoundryClient, "test-app-name", TEST_SPACE_ID, "test-application-id"); + requestGetSshEnabled(this.cloudFoundryClient, "test-application-id", true); this.applications .enableSsh(EnableApplicationSshRequest.builder().name("test-app-name").build()) @@ -469,7 +479,7 @@ void enableSshAlreadyEnabled() { @Test void enableSshNoApp() { - requestApplicationsEmpty(this.cloudFoundryClient, "test-app-name", TEST_SPACE_ID); + requestApplicationsEmptyV3(this.cloudFoundryClient, "test-app-name", TEST_SPACE_ID); this.applications .enableSsh(EnableApplicationSshRequest.builder().name("test-app-name").build()) @@ -722,7 +732,8 @@ void getDetectedBuildpack() { @Test void getEnvironments() { - requestApplications(this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-metadata-id"); + requestApplicationsV3( + this.cloudFoundryClient, "test-app", TEST_SPACE_ID, "test-metadata-id"); requestApplicationEnvironment(this.cloudFoundryClient, "test-metadata-id"); this.applications @@ -754,7 +765,7 @@ void getEnvironments() { @Test void getEnvironmentsNoApp() { - requestApplicationsEmpty(this.cloudFoundryClient, "test-app", TEST_SPACE_ID); + requestApplicationsEmptyV3(this.cloudFoundryClient, "test-app", TEST_SPACE_ID); this.applications .getEnvironments( @@ -3734,8 +3745,9 @@ void setHealthCheck() { @Test void sshEnabled() { - requestApplications( - this.cloudFoundryClient, "test-app-name", TEST_SPACE_ID, "test-metadata-id"); + requestApplicationsV3( + this.cloudFoundryClient, "test-app-name", TEST_SPACE_ID, "test-application-id"); + requestGetSshEnabled(this.cloudFoundryClient, "test-application-id", true); this.applications .sshEnabled(ApplicationSshEnabledRequest.builder().name("test-app-name").build()) @@ -3747,7 +3759,7 @@ void sshEnabled() { @Test void sshEnabledNoApp() { - requestApplicationsEmpty(this.cloudFoundryClient, "test-app-name", TEST_SPACE_ID); + requestApplicationsEmptyV3(this.cloudFoundryClient, "test-app-name", TEST_SPACE_ID); this.applications .sshEnabled(ApplicationSshEnabledRequest.builder().name("test-app-name").build()) @@ -4049,22 +4061,22 @@ private static void requestApplicationEmptyStats( private static void requestApplicationEnvironment( CloudFoundryClient cloudFoundryClient, String applicationId) { when(cloudFoundryClient - .applicationsV2() - .environment( - ApplicationEnvironmentRequest.builder() + .applicationsV3() + .getEnvironment( + GetApplicationEnvironmentRequest.builder() .applicationId(applicationId) .build())) .thenReturn( Mono.just( - ApplicationEnvironmentResponse.builder() - .runningEnvironmentJson( + GetApplicationEnvironmentResponse.builder() + .runningEnvironmentVariable( "running-env-name", "running-env-value") - .applicationEnvironmentJson( + .applicationEnvironmentVariable( "application-env-name", "application-env-value") - .stagingEnvironmentJson( + .stagingEnvironmentVariable( "staging-env-name", "staging-env-value") - .environmentJson("env-name", "env-value") - .systemEnvironmentJson( + .environmentVariable("env-name", "env-value") + .systemEnvironmentVariable( "system-env-name", "system-env-value") .build())); } @@ -4661,6 +4673,19 @@ private static void requestApplicationsEmpty( .thenReturn(Mono.just(fill(ListSpaceApplicationsResponse.builder()).build())); } + private static void requestApplicationsEmptyV3( + CloudFoundryClient cloudFoundryClient, String application, String spaceId) { + when(cloudFoundryClient + .applicationsV3() + .list( + ListApplicationsRequest.builder() + .name(application) + .spaceId(spaceId) + .page(1) + .build())) + .thenReturn(Mono.just(fill(ListApplicationsResponse.builder()).build())); + } + private static void requestApplicationsSpecificState( CloudFoundryClient cloudFoundryClient, String application, @@ -5850,6 +5875,42 @@ private static void requestUpdateApplicationSsh( .build())); } + private static void requestUpdateApplicationSshV3( + CloudFoundryClient cloudFoundryClient, String applicationId, Boolean enabled) { + + when(cloudFoundryClient + .applicationsV3() + .updateFeature( + UpdateApplicationFeatureRequest.builder() + .applicationId(applicationId) + .featureName(APP_FEATURE_SSH) + .enabled(enabled) + .build())) + .thenReturn( + Mono.just( + fill(UpdateApplicationFeatureResponse.builder()) + .description("test-description") + .name("test-application-name") + .enabled(enabled) + .build())); + } + + private static void requestGetSshEnabled( + CloudFoundryClient cloudFoundryClient, String applicationId, boolean status) { + when(cloudFoundryClient + .applicationsV3() + .getSshEnabled( + GetApplicationSshEnabledRequest.builder() + .applicationId(applicationId) + .build())) + .thenReturn( + Mono.just( + fill(GetApplicationSshEnabledResponse.builder()) + .reason("test-reason") + .enabled(status) + .build())); + } + private static void requestUpdateApplicationState( CloudFoundryClient cloudFoundryClient, String applicationId, String state) { requestUpdateApplicationState(cloudFoundryClient, applicationId, state, 1);