示例#1
0
    def test_02_attach_volume(self):
        """Attach a created Volume to a Running VM
        """
        # Validate the following
        # 1. shows list of volumes
        # 2. "Attach Disk" pop-up box will display with list of  instances
        # 3. disk should be  attached to instance successfully

        self.debug("Attaching volume (ID: %s) to VM (ID: %s)" %
                   (self.volume.id, self.virtual_machine.id))
        self.virtual_machine.attach_volume(self.apiClient, self.volume)
        self.attached = True
        list_volume_response = Volume.list(self.apiClient, id=self.volume.id)
        self.assertEqual(isinstance(list_volume_response, list), True,
                         "Check list response returns a valid list")
        self.assertNotEqual(list_volume_response, None,
                            "Check if volume exists in ListVolumes")
        volume = list_volume_response[0]
        self.assertNotEqual(volume.virtualmachineid, None,
                            "Check if volume state (attached) is reflected")
        try:
            # Format the attached volume to a known fs
            format_volume_to_ext3(self.virtual_machine.get_ssh_client())

        except Exception as e:

            self.fail("SSH failed for VM: %s - %s" %
                      (self.virtual_machine.ipaddress, e))
        return
示例#2
0
    def test_02_attach_volume(self):
        """Attach a created Volume to a Running VM
        """
        # Validate the following
        # 1. shows list of volumes
        # 2. "Attach Disk" pop-up box will display with list of  instances
        # 3. disk should be  attached to instance successfully

        self.debug(
                "Attaching volume (ID: %s) to VM (ID: %s)" % (
                                                    self.volume.id,
                                                    self.virtual_machine.id
                                                    ))
        self.virtual_machine.attach_volume(self.apiClient, self.volume)
        self.attached = True
        list_volume_response = Volume.list(
                                                self.apiClient,
                                                id=self.volume.id
                                                )
        self.assertEqual(
                            isinstance(list_volume_response, list),
                            True,
                            "Check list response returns a valid list"
                        )
        self.assertNotEqual(
                            list_volume_response,
                            None,
                            "Check if volume exists in ListVolumes"
                            )
        volume = list_volume_response[0]
        self.assertNotEqual(
                            volume.virtualmachineid,
                            None,
                            "Check if volume state (attached) is reflected"
                            )
        try:
            #Format the attached volume to a known fs
            format_volume_to_ext3(self.virtual_machine.get_ssh_client())

        except Exception as e:

            self.fail("SSH failed for VM: %s - %s" %
                                    (self.virtual_machine.ipaddress, e))
        return
示例#3
0
    def test_03_snapshot_detachedDisk(self):
        """Test snapshot from detached disk
        """
        # Validate the following
        # 1. login in VM  and write some data on data disk(use fdisk to
        #    partition datadisk,fdisk, and make filesystem using
        #    mkfs.ext3)
        # 2. Detach the data disk and write some data on data disk
        # 3. perform the snapshot on the detached volume
        # 4. listvolumes with VM id shouldn't show the detached volume
        # 5. listSnapshots should list the snapshot that was created
        # 6. verify backup_snap_id was non null in the `snapshots` table

        volumes = list_volumes(self.apiclient,
                               virtualmachineid=self.virtual_machine.id,
                               type='DATADISK',
                               listall=True)
        self.assertEqual(isinstance(volumes, list), True,
                         "Check list response returns a valid list")
        volume = volumes[0]
        random_data_0 = random_gen(size=100)
        random_data_1 = random_gen(size=100)
        try:
            ssh_client = self.virtual_machine.get_ssh_client()

            # Format partition using ext3
            format_volume_to_ext3(
                ssh_client,
                self.services["volume"][self.hypervisor]["datadiskdevice_1"])
            cmds = [
                "mkdir -p %s" % self.services["paths"]["mount_dir"],
                "mount %s1 %s" %
                (self.services["volume"][self.hypervisor]["datadiskdevice_1"],
                 self.services["paths"]["mount_dir"]),
                "pushd %s" % self.services["paths"]["mount_dir"],
                "mkdir -p %s/{%s,%s} " %
                (self.services["paths"]["sub_dir"],
                 self.services["paths"]["sub_lvl_dir1"],
                 self.services["paths"]["sub_lvl_dir2"]),
                "echo %s > %s/%s/%s" %
                (random_data_0, self.services["paths"]["sub_dir"],
                 self.services["paths"]["sub_lvl_dir1"],
                 self.services["paths"]["random_data"]),
                "echo %s > %s/%s/%s" %
                (random_data_1, self.services["paths"]["sub_dir"],
                 self.services["paths"]["sub_lvl_dir2"],
                 self.services["paths"]["random_data"]),
                "sync",
                "umount %s" % (self.services["paths"]["mount_dir"]),
            ]
            for c in cmds:
                self.debug(ssh_client.execute(c))

            # detach volume from VM
            cmd = detachVolume.detachVolumeCmd()
            cmd.id = volume.id
            self.apiclient.detachVolume(cmd)

            # Create snapshot from detached volume
            snapshot = Snapshot.create(self.apiclient, volume.id)

            volumes = list_volumes(self.apiclient,
                                   virtualmachineid=self.virtual_machine.id,
                                   type='DATADISK',
                                   listall=True)

            self.assertEqual(volumes, None, "Check Volume is detached")

            # Verify the snapshot was created or not
            snapshots = list_snapshots(self.apiclient, id=snapshot.id)
            self.assertNotEqual(
                snapshots, None,
                "Check if result exists in list snapshots call")
            self.assertEqual(snapshots[0].id, snapshot.id,
                             "Check snapshot id in list resources call")
        except Exception as e:
            self.fail("SSH failed for VM with IP: %s - %s" %
                      (self.virtual_machine.ssh_ip, e))

        qresultset = self.dbclient.execute(
            "select id from snapshots where uuid = '%s';" % snapshot.id)
        self.assertNotEqual(len(qresultset), 0, "Check DB Query result set")

        qresult = qresultset[0]
        self.assertNotEqual(str(qresult[0]), 'NULL',
                            "Check if backup_snap_id is not null")
        return
示例#4
0
    def test_01_volume_from_snapshot(self):
        """Test Creating snapshot from volume having spaces in name(KVM)
        """
        # Validate the following
        # 1. Create a virtual machine and data volume
        # 2. Attach data volume to VM
        # 3. Login to machine; create temp/test directories on data volume
        #    and write some random data
        # 4. Snapshot the Volume
        # 5. Create another Volume from snapshot
        # 6. Mount/Attach volume to another virtual machine
        # 7. Compare data, data should match

        random_data_0 = random_gen(size=100)
        random_data_1 = random_gen(size=100)

        self.debug("random_data_0 : %s" % random_data_0)
        self.debug("random_data_1: %s" % random_data_1)

        try:
            ssh_client = self.virtual_machine.get_ssh_client()
        except Exception as e:
            self.fail("SSH failed for VM: %s" % self.virtual_machine.ipaddress)

        volume = Volume.create(self.apiclient,
                               self.services["volume"],
                               zoneid=self.zone.id,
                               account=self.account.name,
                               domainid=self.account.domainid,
                               diskofferingid=self.disk_offering.id)
        self.debug("Created volume with ID: %s" % volume.id)
        self.virtual_machine.attach_volume(self.apiclient, volume)
        self.debug("Attach volume: %s to VM: %s" %
                   (volume.id, self.virtual_machine.id))

        self.debug("Formatting volume: %s to ext3" % volume.id)
        # Format partition using ext3
        # Note that this is the second data disk partition of virtual machine
        # as it was already containing data disk before attaching the new
        # volume, Hence datadiskdevice_2
        format_volume_to_ext3(
            ssh_client,
            self.services["volume"][self.hypervisor]["datadiskdevice_2"])
        cmds = [
            "fdisk -l",
            "mkdir -p %s" % self.services["paths"]["mount_dir"],
            "mount -t ext3 %s1 %s" %
            (self.services["volume"][self.hypervisor]["datadiskdevice_2"],
             self.services["paths"]["mount_dir"]),
            "mkdir -p %s/%s/{%s,%s} " %
            (self.services["paths"]["mount_dir"],
             self.services["paths"]["sub_dir"],
             self.services["paths"]["sub_lvl_dir1"],
             self.services["paths"]["sub_lvl_dir2"]),
            "echo %s > %s/%s/%s/%s" %
            (random_data_0, self.services["paths"]["mount_dir"],
             self.services["paths"]["sub_dir"],
             self.services["paths"]["sub_lvl_dir1"],
             self.services["paths"]["random_data"]),
            "echo %s > %s/%s/%s/%s" %
            (random_data_1, self.services["paths"]["mount_dir"],
             self.services["paths"]["sub_dir"],
             self.services["paths"]["sub_lvl_dir2"],
             self.services["paths"]["random_data"]),
            "cat %s/%s/%s/%s" % (self.services["paths"]["mount_dir"],
                                 self.services["paths"]["sub_dir"],
                                 self.services["paths"]["sub_lvl_dir1"],
                                 self.services["paths"]["random_data"])
        ]
        for c in cmds:
            self.debug("Command: %s" % c)
            result = ssh_client.execute(c)
            self.debug(result)

        # Unmount the Sec Storage
        cmds = [
            "umount %s" % (self.services["paths"]["mount_dir"]),
        ]
        for c in cmds:
            self.debug("Command: %s" % c)
            ssh_client.execute(c)

        list_volume_response = Volume.list(
            self.apiclient,
            virtualmachineid=self.virtual_machine.id,
            type='DATADISK',
            id=volume.id)

        self.assertEqual(isinstance(list_volume_response, list), True,
                         "Check list volume response for valid data")
        volume_response = list_volume_response[0]
        # Create snapshot from attached volume
        snapshot = Snapshot.create(self.apiclient,
                                   volume_response.id,
                                   account=self.account.name,
                                   domainid=self.account.domainid)
        self.debug("Created snapshot: %s" % snapshot.id)
        # Create volume from snapshot
        volume_from_snapshot = Volume.create_from_snapshot(
            self.apiclient,
            snapshot.id,
            self.services["volume"],
            account=self.account.name,
            domainid=self.account.domainid)

        # Detach the volume from virtual machine
        self.virtual_machine.detach_volume(self.apiclient, volume)
        self.debug("Detached volume: %s from VM: %s" %
                   (volume.id, self.virtual_machine.id))

        self.debug("Created Volume: %s from Snapshot: %s" %
                   (volume_from_snapshot.id, snapshot.id))
        volumes = Volume.list(self.apiclient, id=volume_from_snapshot.id)
        self.assertEqual(isinstance(volumes, list), True,
                         "Check list response returns a valid list")

        self.assertNotEqual(len(volumes), None, "Check Volume list Length")
        self.assertEqual(volumes[0].id, volume_from_snapshot.id,
                         "Check Volume in the List Volumes")
        # Attaching volume to new VM
        new_virtual_machine = VirtualMachine.create(
            self.apiclient,
            self.services["server_without_disk"],
            templateid=self.template.id,
            accountid=self.account.name,
            domainid=self.account.domainid,
            serviceofferingid=self.service_offering.id,
            mode=self.services["mode"])
        self.debug("Deployed new VM for account: %s" % self.account.name)
        # self.cleanup.append(new_virtual_machine)

        self.debug("Attaching volume: %s to VM: %s" %
                   (volume_from_snapshot.id, new_virtual_machine.id))

        new_virtual_machine.attach_volume(self.apiclient, volume_from_snapshot)

        # Rebooting is required so that newly attached disks are detected
        self.debug("Rebooting : %s" % new_virtual_machine.id)

        new_virtual_machine.reboot(self.apiclient)

        try:
            # Login to VM to verify test directories and files
            ssh = new_virtual_machine.get_ssh_client()

            # Mount datadiskdevice_1 because this is the first data disk of the
            # new virtual machine
            cmds = [
                "fdisk -l",
                "mkdir -p %s" % self.services["paths"]["mount_dir"],
                "mount -t ext3 %s1 %s" %
                (self.services["volume"][self.hypervisor]["datadiskdevice_1"],
                 self.services["paths"]["mount_dir"]),
            ]

            for c in cmds:
                self.debug("Command: %s" % c)
                result = ssh.execute(c)
                self.debug(result)

            returned_data_0 = ssh.execute(
                "cat %s/%s/%s/%s" % (self.services["paths"]["mount_dir"],
                                     self.services["paths"]["sub_dir"],
                                     self.services["paths"]["sub_lvl_dir1"],
                                     self.services["paths"]["random_data"]))
            returned_data_1 = ssh.execute(
                "cat %s/%s/%s/%s" % (self.services["paths"]["mount_dir"],
                                     self.services["paths"]["sub_dir"],
                                     self.services["paths"]["sub_lvl_dir2"],
                                     self.services["paths"]["random_data"]))
        except Exception as e:
            self.fail("SSH access failed for VM: %s, Exception: %s" %
                      (new_virtual_machine.ipaddress, e))

        self.debug("returned_data_0: %s" % returned_data_0[0])
        self.debug("returned_data_1: %s" % returned_data_1[0])

        # Verify returned data
        self.assertEqual(
            random_data_0, returned_data_0[0],
            "Verify newly attached volume contents with existing one")
        self.assertEqual(
            random_data_1, returned_data_1[0],
            "Verify newly attached volume contents with existing one")
        # Unmount the Sec Storage
        cmds = [
            "umount %s" % (self.services["paths"]["mount_dir"]),
        ]
        for c in cmds:
            self.debug("Command: %s" % c)
            ssh_client.execute(c)
        return
示例#5
0
    def test_03_snapshot_detachedDisk(self):
        """Test snapshot from detached disk
        """
        # Validate the following
        # 1. login in VM  and write some data on data disk(use fdisk to
        #    partition datadisk,fdisk, and make filesystem using
        #    mkfs.ext3)
        # 2. Detach the data disk and write some data on data disk
        # 3. perform the snapshot on the detached volume
        # 4. listvolumes with VM id shouldn't show the detached volume
        # 5. listSnapshots should list the snapshot that was created
        # 6. verify backup_snap_id was non null in the `snapshots` table

        if self.hypervisor.lower() in ['hyperv']:
            self.skipTest("Snapshots feature is not supported on Hyper-V")

        volumes = list_volumes(
            self.apiclient,
            virtualmachineid=self.virtual_machine.id,
            type='DATADISK',
            listall=True
        )
        self.assertEqual(
            isinstance(volumes, list),
            True,
            "Check list response returns a valid list"
        )
        volume = volumes[0]
        random_data_0 = random_gen(size=100)
        random_data_1 = random_gen(size=100)
        try:
            ssh_client = self.virtual_machine.get_ssh_client()

            # Format partition using ext3
            format_volume_to_ext3(
                ssh_client,
                self.services["volume"][self.hypervisor]["datadiskdevice_1"]
            )
            cmds = [
                "mkdir -p %s" %
                self.services["paths"]["mount_dir"],
                "mount %s1 %s" %
                (self.services["volume"][
                    self.hypervisor]["datadiskdevice_1"],
                    self.services["paths"]["mount_dir"]),
                "pushd %s" %
                self.services["paths"]["mount_dir"],
                "mkdir -p %s/{%s,%s} " %
                (self.services["paths"]["sub_dir"],
                    self.services["paths"]["sub_lvl_dir1"],
                    self.services["paths"]["sub_lvl_dir2"]),
                "echo %s > %s/%s/%s" %
                (random_data_0,
                    self.services["paths"]["sub_dir"],
                    self.services["paths"]["sub_lvl_dir1"],
                    self.services["paths"]["random_data"]),
                "echo %s > %s/%s/%s" %
                (random_data_1,
                    self.services["paths"]["sub_dir"],
                    self.services["paths"]["sub_lvl_dir2"],
                    self.services["paths"]["random_data"]),
                "sync",
                "umount %s" %
                (self.services["paths"]["mount_dir"]),
            ]
            for c in cmds:
                self.debug(ssh_client.execute(c))

            # detach volume from VM
            cmd = detachVolume.detachVolumeCmd()
            cmd.id = volume.id
            self.apiclient.detachVolume(cmd)

            # Create snapshot from detached volume
            snapshot = Snapshot.create(self.apiclient, volume.id)

            volumes = list_volumes(
                self.apiclient,
                virtualmachineid=self.virtual_machine.id,
                type='DATADISK',
                listall=True
            )

            self.assertEqual(
                volumes,
                None,
                "Check Volume is detached"
            )

            # Verify the snapshot was created or not
            snapshots = list_snapshots(
                self.apiclient,
                id=snapshot.id
            )
            self.assertNotEqual(
                snapshots,
                None,
                "Check if result exists in list snapshots call"
            )
            self.assertEqual(
                snapshots[0].id,
                snapshot.id,
                "Check snapshot id in list resources call"
            )
        except Exception as e:
            self.fail("SSH failed for VM with IP: %s - %s" %
                      (self.virtual_machine.ssh_ip, e))

        qresultset = self.dbclient.execute(
            "select id from snapshots where uuid = '%s';"
            % snapshot.id
        )
        self.assertNotEqual(
            len(qresultset),
            0,
            "Check DB Query result set"
        )

        qresult = qresultset[0]
        self.assertNotEqual(
            str(qresult[0]),
            'NULL',
            "Check if backup_snap_id is not null"
        )
        return
示例#6
0
    def test_01_volume_from_snapshot(self):
        """Test Creating snapshot from volume having spaces in name(KVM)
        """
        # Validate the following
        # 1. Create a virtual machine and data volume
        # 2. Attach data volume to VM
        # 3. Login to machine; create temp/test directories on data volume
        #    and write some random data
        # 4. Snapshot the Volume
        # 5. Create another Volume from snapshot
        # 6. Mount/Attach volume to another virtual machine
        # 7. Compare data, data should match

        if self.hypervisor.lower() in ['hyperv']:
            self.skipTest("Snapshots feature is not supported on Hyper-V")

        random_data_0 = random_gen(size=100)
        random_data_1 = random_gen(size=100)

        self.debug("random_data_0 : %s" % random_data_0)
        self.debug("random_data_1: %s" % random_data_1)

        try:
            ssh_client = self.virtual_machine.get_ssh_client()
        except Exception as e:
            self.fail("SSH failed for VM: %s" %
                      self.virtual_machine.ipaddress)

        volume = Volume.create(
            self.apiclient,
            self.services["volume"],
            zoneid=self.zone.id,
            account=self.account.name,
            domainid=self.account.domainid,
            diskofferingid=self.disk_offering.id
        )
        self.debug("Created volume with ID: %s" % volume.id)
        self.virtual_machine.attach_volume(
            self.apiclient,
            volume
        )
        self.debug("Attach volume: %s to VM: %s" %
                   (volume.id, self.virtual_machine.id))

        self.debug("Formatting volume: %s to ext3" % volume.id)
        # Format partition using ext3
        # Note that this is the second data disk partition of virtual machine
        # as it was already containing data disk before attaching the new
        # volume, Hence datadiskdevice_2
        format_volume_to_ext3(
            ssh_client,
            self.services["volume"][self.hypervisor]["datadiskdevice_2"]
        )
        cmds = [
            "fdisk -l",
            "mkdir -p %s" %
            self.services["paths"]["mount_dir"],
            "mount -t ext3 %s1 %s" %
            (self.services["volume"][
                self.hypervisor]["datadiskdevice_2"],
                self.services["paths"]["mount_dir"]),
            "mkdir -p %s/%s/{%s,%s} " %
            (self.services["paths"]["mount_dir"],
                self.services["paths"]["sub_dir"],
                self.services["paths"]["sub_lvl_dir1"],
                self.services["paths"]["sub_lvl_dir2"]),
            "echo %s > %s/%s/%s/%s" %
            (random_data_0,
                self.services["paths"]["mount_dir"],
                self.services["paths"]["sub_dir"],
                self.services["paths"]["sub_lvl_dir1"],
                self.services["paths"]["random_data"]),
            "echo %s > %s/%s/%s/%s" %
            (random_data_1,
                self.services["paths"]["mount_dir"],
                self.services["paths"]["sub_dir"],
                self.services["paths"]["sub_lvl_dir2"],
                self.services["paths"]["random_data"]),
            "cat %s/%s/%s/%s" %
            (self.services["paths"]["mount_dir"],
                self.services["paths"]["sub_dir"],
                self.services["paths"]["sub_lvl_dir1"],
                self.services["paths"]["random_data"])]
        for c in cmds:
            self.debug("Command: %s" % c)
            result = ssh_client.execute(c)
            self.debug(result)

        # Unmount the Sec Storage
        cmds = [
            "umount %s" % (self.services["paths"]["mount_dir"]),
        ]
        for c in cmds:
            self.debug("Command: %s" % c)
            ssh_client.execute(c)

        list_volume_response = Volume.list(
            self.apiclient,
            virtualmachineid=self.virtual_machine.id,
            type='DATADISK',
            id=volume.id
        )

        self.assertEqual(
            isinstance(list_volume_response, list),
            True,
            "Check list volume response for valid data"
        )
        volume_response = list_volume_response[0]
        # Create snapshot from attached volume
        snapshot = Snapshot.create(
            self.apiclient,
            volume_response.id,
            account=self.account.name,
            domainid=self.account.domainid
        )
        self.debug("Created snapshot: %s" % snapshot.id)
        # Create volume from snapshot
        volume_from_snapshot = Volume.create_from_snapshot(
            self.apiclient,
            snapshot.id,
            self.services["volume"],
            account=self.account.name,
            domainid=self.account.domainid
        )

        # Detach the volume from virtual machine
        self.virtual_machine.detach_volume(
            self.apiclient,
            volume
        )
        self.debug("Detached volume: %s from VM: %s" %
                   (volume.id, self.virtual_machine.id))

        self.debug("Created Volume: %s from Snapshot: %s" % (
            volume_from_snapshot.id,
            snapshot.id))
        volumes = Volume.list(
            self.apiclient,
            id=volume_from_snapshot.id
        )
        self.assertEqual(
            isinstance(volumes, list),
            True,
            "Check list response returns a valid list"
        )

        self.assertNotEqual(
            len(volumes),
            None,
            "Check Volume list Length"
        )
        self.assertEqual(
            volumes[0].id,
            volume_from_snapshot.id,
            "Check Volume in the List Volumes"
        )
        # Attaching volume to new VM
        new_virtual_machine = VirtualMachine.create(
            self.apiclient,
            self.services["server_without_disk"],
            templateid=self.template.id,
            accountid=self.account.name,
            domainid=self.account.domainid,
            serviceofferingid=self.service_offering.id,
            mode=self.services["mode"]
        )
        self.debug("Deployed new VM for account: %s" % self.account.name)
        # self.cleanup.append(new_virtual_machine)

        self.debug("Attaching volume: %s to VM: %s" % (
            volume_from_snapshot.id,
            new_virtual_machine.id
        ))

        new_virtual_machine.attach_volume(
            self.apiclient,
            volume_from_snapshot
        )

        # Rebooting is required so that newly attached disks are detected
        self.debug("Rebooting : %s" % new_virtual_machine.id)

        new_virtual_machine.reboot(self.apiclient)

        try:
            # Login to VM to verify test directories and files
            ssh = new_virtual_machine.get_ssh_client()

            # Mount datadiskdevice_1 because this is the first data disk of the
            # new virtual machine
            cmds = [
                "fdisk -l",
                "mkdir -p %s" %
                self.services["paths"]["mount_dir"],
                "mount -t ext3 %s1 %s" %
                (self.services["volume"][
                    self.hypervisor]["datadiskdevice_1"],
                    self.services["paths"]["mount_dir"]),
            ]

            for c in cmds:
                self.debug("Command: %s" % c)
                result = ssh.execute(c)
                self.debug(result)

            returned_data_0 = ssh.execute(
                "cat %s/%s/%s/%s" % (
                    self.services["paths"]["mount_dir"],
                    self.services["paths"]["sub_dir"],
                    self.services["paths"]["sub_lvl_dir1"],
                    self.services["paths"]["random_data"]
                ))
            returned_data_1 = ssh.execute(
                "cat %s/%s/%s/%s" % (
                    self.services["paths"]["mount_dir"],
                    self.services["paths"]["sub_dir"],
                    self.services["paths"]["sub_lvl_dir2"],
                    self.services["paths"]["random_data"]
                ))
        except Exception as e:
            self.fail("SSH access failed for VM: %s, Exception: %s" %
                      (new_virtual_machine.ipaddress, e))

        self.debug("returned_data_0: %s" % returned_data_0[0])
        self.debug("returned_data_1: %s" % returned_data_1[0])

        # Verify returned data
        self.assertEqual(
            random_data_0,
            returned_data_0[0],
            "Verify newly attached volume contents with existing one"
        )
        self.assertEqual(
            random_data_1,
            returned_data_1[0],
            "Verify newly attached volume contents with existing one"
        )
        # Unmount the Sec Storage
        cmds = [
            "umount %s" % (self.services["paths"]["mount_dir"]),
        ]
        for c in cmds:
            self.debug("Command: %s" % c)
            ssh_client.execute(c)
        return