feat(provider/cf): add tags property to services
MODIFY
clouddriver-cloudfoundry/src/main/java/com/netflix/spinnaker/clouddriver/cloudfoundry/client/Applications.java
clouddriver-cloudfoundry/src/main/java/com/netflix/spinnaker/clouddriver/cloudfoundry/client/Applications.java
@@ -201,6 +201,7 @@ public class Applications {
.serviceName(vcap.getKey())
.name(instance.getName())
.plan(instance.getPlan())
+ .tags(instance.getTags())
.build()))
.collect(toList());

MODIFY
clouddriver-cloudfoundry/src/main/java/com/netflix/spinnaker/clouddriver/cloudfoundry/client/model/v2/ServiceInstance.java
clouddriver-cloudfoundry/src/main/java/com/netflix/spinnaker/clouddriver/cloudfoundry/client/model/v2/ServiceInstance.java
@@ -18,10 +18,13 @@ package com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.v2;
import lombok.Data;
+import java.util.Set;
+
@Data
public class ServiceInstance {
private String name;
private String plan;
private String servicePlanGuid;
private LastOperation lastOperation;
+ private Set<String> tags;
}

MODIFY
clouddriver-cloudfoundry/src/main/java/com/netflix/spinnaker/clouddriver/cloudfoundry/model/CloudFoundryServiceInstance.java
clouddriver-cloudfoundry/src/main/java/com/netflix/spinnaker/clouddriver/cloudfoundry/model/CloudFoundryServiceInstance.java
@@ -21,6 +21,8 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.Builder;
import lombok.Value;
+import java.util.Set;
+
/**
* "Service" in this context refers to an Open Service Broker service.
*/
@@ -36,4 +38,7 @@ public class CloudFoundryServiceInstance {
@JsonView(Views.Cache.class)
String plan;
+
+ @JsonView(Views.Cache.class)
+ Set<String> tags;
}

ADD
clouddriver-cloudfoundry/src/test/java/com/netflix/spinnaker/clouddriver/cloudfoundry/client/ApplicationsTest.java
+/*
+ * Copyright 2018 Pivotal, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.netflix.spinnaker.clouddriver.cloudfoundry.client;
+
+import com.netflix.spinnaker.clouddriver.cloudfoundry.client.api.ApplicationService;
+import com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.v2.ApplicationEnv;
+import com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.v2.InstanceStatus;
+import com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.v2.ServiceInstance;
+import com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.v3.*;
+import com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.v3.Package;
+import com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.v3.Process;
+import com.netflix.spinnaker.clouddriver.cloudfoundry.model.CloudFoundryOrganization;
+import com.netflix.spinnaker.clouddriver.cloudfoundry.model.CloudFoundryServerGroup;
+import com.netflix.spinnaker.clouddriver.cloudfoundry.model.CloudFoundrySpace;
+import io.vavr.collection.HashMap;
+import org.junit.jupiter.api.Test;
+
+import java.time.ZonedDateTime;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.*;
+
+class ApplicationsTest {
+ private ApplicationService applicationService = mock(ApplicationService.class);
+ private Spaces spaces = mock(Spaces.class);
+ private Applications apps = new Applications("pws", applicationService, spaces);
+
+ @Test
+ void errorHandling() {
+ CloudFoundryClient client = new HttpCloudFoundryClient("pws", "api.run.pivotal.io",
+ "baduser", "badpassword");
+
+ assertThatThrownBy(() -> client.getApplications().all())
+ .isInstanceOf(CloudFoundryApiException.class);
+ }
+
+ @Test
+ void dontScaleApplicationIfInputsAreNullOrZero() {
+ apps.scaleApplication("id", null, null, null);
+ apps.scaleApplication("id", 0, 0, 0);
+
+ verify(applicationService, never()).scaleApplication(any(), any());
+ }
+
+ @Test
+ void findByIdIfInputsAreValid() {
+ Application application = new Application()
+ .setCreatedAt(ZonedDateTime.now())
+ .setGuid("some-app-guid")
+ .setName("some-app-name")
+ .setState("STARTED")
+ .setLinks(HashMap.of("space", new Link().setHref("http://capi.io/space/space-guid")).toJavaMap());
+
+ ApplicationEnv.SystemEnv systemEnv = new ApplicationEnv.SystemEnv()
+ .setVcapServices(HashMap.of("service-name-1", Collections.singletonList(new ServiceInstance()
+ .setName("service-instance")
+ .setPlan("service-plan")
+ .setServicePlanGuid("service-plan-guid")
+ .setTags(new HashSet<>(Arrays.asList("tag1", "tag2")))
+ )).toJavaMap());
+ ApplicationEnv applicationEnv = new ApplicationEnv()
+ .setSystemEnvJson(systemEnv);
+
+ Process process = new Process()
+ .setDiskInMb(1024)
+ .setGuid("process-guid")
+ .setInstances(1)
+ .setMemoryInMb(1024);
+
+ Package applicationPacakage = new Package()
+ .setData(new PackageData()
+ .setChecksum(new PackageChecksum().setType("package-checksum-type").setValue("package-check-sum-value"))
+ )
+ .setLinks(HashMap.of("download", new Link().setHref("http://capi.io/download/space-guid")).toJavaMap());
+ Pagination<Package> packagePagination = new Pagination<Package>()
+ .setPagination(new Pagination.Details().setTotalPages(1))
+ .setResources(Collections.singletonList(applicationPacakage));
+
+ Droplet droplet = new Droplet()
+ .setGuid("droplet-guid")
+ .setStack("droplet-stack")
+ .setBuildpacks(Collections.singletonList(new Buildpack().setBuildpackName("build-pack-name")));
+
+ CloudFoundryOrganization cloudFoundryOrganization = CloudFoundryOrganization.builder()
+ .id("org-id")
+ .name("org-name")
+ .build();
+ CloudFoundrySpace cloudFoundrySpace = CloudFoundrySpace.builder()
+ .id("space-id")
+ .name("space-name")
+ .organization(cloudFoundryOrganization)
+ .build();
+
+ when(applicationService.findById("some-app-guid")).thenReturn(application);
+ when(applicationService.findApplicationEnvById("some-app-guid")).thenReturn(applicationEnv);
+ when(spaces.findById(any())).thenReturn(cloudFoundrySpace);
+ when(applicationService.findProcessById(any())).thenReturn(process);
+ when(applicationService.instances("some-app-guid")).thenReturn(
+ HashMap.of("0", new InstanceStatus().setState(InstanceStatus.State.RUNNING).setUptime(2405L)).toJavaMap());
+ when(applicationService.findPackagesByAppId("some-app-guid")).thenReturn(packagePagination);
+ when(applicationService.findDropletByApplicationGuid("some-app-guid")).thenReturn(droplet);
+
+ CloudFoundryServerGroup cloudFoundryServerGroup = apps.findById("some-app-guid");
+ assertThat(cloudFoundryServerGroup).isNotNull();
+ assertThat(cloudFoundryServerGroup.getId()).isEqualTo("some-app-guid");
+ assertThat(cloudFoundryServerGroup.getName()).isEqualTo("some-app-name");
+ assertThat(cloudFoundryServerGroup.getServiceInstances().size()).isEqualTo(1);
+ assertThat(cloudFoundryServerGroup.getServiceInstances().get(0).getTags()).containsExactly("tag1", "tag2");
+ }
+}

MODIFY
clouddriver-cloudfoundry/src/test/java/com/netflix/spinnaker/clouddriver/cloudfoundry/client/ServiceInstancesTest.java
clouddriver-cloudfoundry/src/test/java/com/netflix/spinnaker/clouddriver/cloudfoundry/client/ServiceInstancesTest.java
@@ -32,12 +32,8 @@ import java.util.Arrays;
import java.util.Collections;
import static com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.ErrorDescription.Code.SERVICE_ALREADY_EXISTS;
-import static com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.v2.LastOperation.State.FAILED;
-import static com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.v2.LastOperation.State.IN_PROGRESS;
-import static com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.v2.LastOperation.State.SUCCEEDED;
-import static com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.v2.LastOperation.Type.CREATE;
-import static com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.v2.LastOperation.Type.DELETE;
-import static com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.v2.LastOperation.Type.UPDATE;
+import static com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.v2.LastOperation.State.*;
+import static com.netflix.spinnaker.clouddriver.cloudfoundry.client.model.v2.LastOperation.Type.*;
import static junit.framework.TestCase.fail;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*;
@@ -318,6 +314,7 @@ public class ServiceInstancesTest {
serviceInstances.destroyServiceInstance(cloudFoundrySpace, "newServiceInstanceName");
+ verify(serviceInstanceService, times(1)).findAllServiceInstancesBySpaceId(any(), any(), anyListOf(String.class));
verify(serviceInstanceService, times(1)).destroyServiceInstance(any());
verify(serviceInstanceService, times(2)).getServiceInstanceById("service-instance-guid");
}

DELETE
clouddriver-cloudfoundry/src/test/java/com/netflix/spinnaker/clouddriver/cloudfoundry/client/model/ApplicationsTest.java
-/*
- * Copyright 2018 Pivotal, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.netflix.spinnaker.clouddriver.cloudfoundry.client.model;
-
-import com.netflix.spinnaker.clouddriver.cloudfoundry.client.Applications;
-import com.netflix.spinnaker.clouddriver.cloudfoundry.client.CloudFoundryApiException;
-import com.netflix.spinnaker.clouddriver.cloudfoundry.client.CloudFoundryClient;
-import com.netflix.spinnaker.clouddriver.cloudfoundry.client.HttpCloudFoundryClient;
-import com.netflix.spinnaker.clouddriver.cloudfoundry.client.api.ApplicationService;
-import org.junit.jupiter.api.Test;
-
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.*;
-
-class ApplicationsTest {
- @Test
- void errorHandling() {
- CloudFoundryClient client = new HttpCloudFoundryClient("pws", "api.run.pivotal.io",
- "baduser", "badpassword");
-
- assertThatThrownBy(() -> client.getApplications().all())
- .isInstanceOf(CloudFoundryApiException.class);
- }
-
- @Test
- void dontScaleApplicationIfInputsAreNullOrZero() {
- ApplicationService applicationService = mock(ApplicationService.class);
-
- Applications apps = new Applications("pws", applicationService, null);
-
- apps.scaleApplication("id", null, null, null);
- apps.scaleApplication("id", 0, 0, 0);
-
- verify(applicationService, never()).scaleApplication(any(), any());
- }
-}

feat(provider/cf): add tags property to services

Co-Authored-By: Stu Pollock <spollock@pivotal.io>