Added volume creation to heatbridge 21/118921/1
authorBOSLET, CORY <cory.boslet@att.com>
Mon, 8 Mar 2021 20:08:06 +0000 (15:08 -0500)
committerAT&T Open Source <g22940@att.com>
Mon, 8 Mar 2021 20:08:06 +0000 (15:08 -0500)
Added volume creation to heatbridge

Issue-ID: SO-3577
Signed-off-by: AT&T Open Source <g22940@att.com>
Change-Id: I0f0844187efe880cccf4b663c8c4fadc346680c3

adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/tasks/inventory/CreateAAIInventory.java
adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeApi.java
adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeImpl.java
adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackClient.java
adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackClientImpl.java
adapters/mso-openstack-adapters/src/test/java/org/onap/so/heatbridge/HeatBridgeImplTest.java
adapters/mso-openstack-adapters/src/test/resources/stack-resources.json

index 0dd7635..15cf4af 100644 (file)
@@ -121,6 +121,8 @@ public class CreateAAIInventory {
                 cloudInformation.getOwner());
         logger.debug("Successfully queried neutron resources and built AAI actions to add l-interfaces to vservers.");
 
+        heatBridgeClient.buildAddVolumes(stackResources);
+
         // Update AAI
         logger.debug("Current Dry Run Value: {}", env.getProperty("heatBridgeDryrun", Boolean.class, false));
         heatBridgeClient.submitToAai(env.getProperty("heatBridgeDryrun", Boolean.class, false));
index 1b2fdfe..1de7273 100644 (file)
@@ -159,6 +159,13 @@ public interface HeatBridgeApi {
     void buildAddVserverLInterfacesToAaiAction(List<Resource> stackResources, List<String> oobMgtNetIds,
             String cloudOwner) throws HeatBridgeException;
 
+    /**
+     * Query and build AAI actions for Openstack volumes
+     *
+     * @throws HeatBridgeException when failing to remove heatbridge data from AAI for a given vf-module
+     */
+    void buildAddVolumes(List<Resource> stackResources) throws HeatBridgeException;
+
     /**
      * Query and build AAI actions for Openstack Compute resources to AAI's pserver and pinterface objects
      *
@@ -180,4 +187,6 @@ public interface HeatBridgeApi {
      * @throws HeatBridgeException when failing to remove heatbridge data from AAI for a given vf-module
      */
     void deleteVfModuleData(String vnfId, String vfModuleId) throws HeatBridgeException;
+
+
 }
index 04c6ea4..1bf4aff 100644 (file)
@@ -64,6 +64,7 @@ import org.onap.aai.domain.yang.SriovPf;
 import org.onap.aai.domain.yang.SriovVf;
 import org.onap.aai.domain.yang.Subnets;
 import org.onap.aai.domain.yang.Vlan;
+import org.onap.aai.domain.yang.Volume;
 import org.onap.aai.domain.yang.Vserver;
 import org.onap.aaiclient.client.aai.AAIDSLQueryClient;
 import org.onap.aaiclient.client.aai.AAIResourcesClient;
@@ -103,6 +104,7 @@ import org.openstack4j.model.network.Network;
 import org.openstack4j.model.network.NetworkType;
 import org.openstack4j.model.network.Port;
 import org.openstack4j.model.network.Subnet;
+import org.openstack4j.model.storage.block.VolumeAttachment;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.core.env.Environment;
@@ -421,6 +423,46 @@ public class HeatBridgeImpl implements HeatBridgeApi {
         }
     }
 
+    @Override
+    public void buildAddVolumes(List<Resource> stackResources) throws HeatBridgeException {
+        try {
+            if (stackResources.stream().anyMatch(r -> r.getType().equals("OS::Cinder::Volume"))) {
+                stackResources.stream().filter(r -> r.getType().equalsIgnoreCase("OS::Cinder::Volume"))
+                        .forEach(r -> createVolume(r));
+            } else {
+                logger.debug("Heat stack contains no volumes");
+            }
+        } catch (Exception e) {
+            logger.error("Failed to add volumes to AAI", e);
+            throw new HeatBridgeException("Failed to add volumes to AAI", e);
+        }
+
+    }
+
+    protected void createVolume(Resource r) {
+        org.openstack4j.model.storage.block.Volume osVolume = osClient.getVolumeById(r.getPhysicalResourceId());
+        List<? extends VolumeAttachment> attachments = osVolume.getAttachments();
+        if (attachments != null) {
+            Optional<? extends VolumeAttachment> vserver = attachments.stream().findFirst();
+            if (vserver.isPresent()) {
+                Volume volume = new Volume();
+                volume.setVolumeId(r.getPhysicalResourceId());
+                AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.cloudInfrastructure()
+                        .cloudRegion(cloudOwner, cloudRegionId).tenant(tenantId).vserver(vserver.get().getServerId())
+                        .volume(r.getPhysicalResourceId()));
+                transaction.createIfNotExists(uri, Optional.of(volume));
+            } else {
+                logger.warn(
+                        "Volume {} contains no attachments in openstack. Unable to determine which vserver volume belongs too.",
+                        r.getPhysicalResourceId());
+            }
+        } else {
+            logger.warn(
+                    "Volume {} contains no attachments in openstack. Unable to determine which vserver volume belongs too.",
+                    r.getPhysicalResourceId());
+        }
+    }
+
     protected String getInterfaceType(NodeType nodeType, String nicType) {
         logger.debug("nicType: " + nicType + "nodeType: " + nodeType);
         if (DIRECT.equalsIgnoreCase(nicType)) {
index 8d47ff4..a4aacfe 100644 (file)
@@ -43,6 +43,7 @@ import org.openstack4j.model.heat.Resource;
 import org.openstack4j.model.network.Network;
 import org.openstack4j.model.network.Port;
 import org.openstack4j.model.network.Subnet;
+import org.openstack4j.model.storage.block.Volume;
 
 public interface OpenstackClient {
 
@@ -101,4 +102,11 @@ public interface OpenstackClient {
      * @return Subnet object.
      */
     Subnet getSubnetById(String subnetId);
+
+    /**
+     * Get a volume object by volume ID
+     * 
+     * @return Volume object.
+     */
+    Volume getVolumeById(String volumeId);
 }
index 1505203..81f09b8 100644 (file)
@@ -46,6 +46,8 @@ import org.openstack4j.model.heat.Resource;
 import org.openstack4j.model.network.Network;
 import org.openstack4j.model.network.Port;
 import org.openstack4j.model.network.Subnet;
+import org.openstack4j.model.storage.block.Volume;
+import org.openstack4j.model.storage.block.VolumeBackup;
 
 abstract class OpenstackClientImpl implements OpenstackClient {
     @Override
@@ -84,6 +86,11 @@ abstract class OpenstackClientImpl implements OpenstackClient {
         return getClient().networking().subnet().get(subnetId);
     }
 
+    @Override
+    public Volume getVolumeById(String id) {
+        return getClient().blockStorage().volumes().get(id);
+    }
+
     /**
      * Retrieves the specific client to utilize.
      * 
index fab7df5..cf3e1c5 100644 (file)
@@ -106,6 +106,8 @@ import org.openstack4j.model.network.Network;
 import org.openstack4j.model.network.NetworkType;
 import org.openstack4j.model.network.Port;
 import org.openstack4j.model.network.Subnet;
+import org.openstack4j.model.storage.block.Volume;
+import org.openstack4j.model.storage.block.VolumeAttachment;
 import org.openstack4j.openstack.heat.domain.HeatResource;
 import org.openstack4j.openstack.heat.domain.HeatResource.Resources;
 import org.slf4j.Logger;
@@ -118,7 +120,6 @@ import com.fasterxml.jackson.databind.JsonMappingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.google.common.collect.ImmutableMap;
 
-
 @RunWith(MockitoJUnitRunner.Silent.class)
 public class HeatBridgeImplTest {
 
@@ -808,6 +809,28 @@ public class HeatBridgeImplTest {
         assertEquals(1, images.size());
     }
 
+    @Test
+    public void testBuildAddVolumes() throws HeatBridgeException {
+        List<Resource> stackResources = (List<Resource>) extractTestStackResources();
+        Volume volume = mock(Volume.class);
+        List<VolumeAttachment> attachments = new ArrayList<>();
+        VolumeAttachment server = mock(VolumeAttachment.class);
+        attachments.add(server);
+        when(volume.getAttachments()).thenAnswer(x -> attachments);
+        when(server.getServerId()).thenReturn("vserverIdTest");
+
+        when(osClient.getVolumeById("5ad95036-8daf-4379-a59c-865f35976ca3")).thenReturn(volume);
+
+        heatbridge.buildAddVolumes(stackResources);
+
+        verify(transaction, times(1)).createIfNotExists(
+                eq(AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.cloudInfrastructure()
+                        .cloudRegion("CloudOwner", "RegionOne").tenant("7320ec4a5b9d4589ba7c4412ccfd290f")
+                        .vserver("vserverIdTest").volume("5ad95036-8daf-4379-a59c-865f35976ca3"))),
+                any(Optional.class));
+        verify(osClient, times(1)).getVolumeById(eq("5ad95036-8daf-4379-a59c-865f35976ca3"));
+    }
+
     private List<? extends Resource> extractTestStackResources() {
         List<HeatResource> stackResources = null;
         try {
@@ -838,4 +861,5 @@ public class HeatBridgeImplTest {
     }
 
 
+
 }
index 6b63895..159c666 100644 (file)
       "resource_status_reason": "state changed",
       "physical_resource_id": "5ad95036-8daf-4379-a59c-865f35976cd4",
       "resource_type": "OS::Neutron::Net"
+    },
+    {
+      "resource_name": "volume",
+      "links": [
+        {
+          "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-re_pfe_network-2wmjvgzrhtvs/290fc2fd-cd1d-47d0-90eb-2ece7c009b29/resources/bridge_network",
+          "rel": "self"
+        },
+        {
+          "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-re_pfe_network-2wmjvgzrhtvs/290fc2fd-cd1d-47d0-90eb-2ece7c009b29",
+          "rel": "stack"
+        }
+      ],
+      "logical_resource_id": "some_id",
+      "resource_status": "CREATE_COMPLETE",
+      "updated_time": "2018-04-09T21:09:55Z",
+      "required_by": [
+        "bridge_network_subnet"
+      ],
+      "resource_status_reason": "state changed",
+      "physical_resource_id": "5ad95036-8daf-4379-a59c-865f35976ca3",
+      "resource_type": "OS::Cinder::Volume"
     }
   ]
 }