Esempio n. 1
0
def purge_snapshots_by_volume(volume, purge_limit):
    """
    Purge snapshots per volume
    @return: count of snapshots purged
    """
    config = helpers.get_db_config()
    ontap = OntapService(config['ontap_api'], config['ontap_apiuser'], config['ontap_apipass'],
                         config['ontap_svm_name'], config['ontap_aggr_name'], config['ontap_data_ip'])
    ontap_snapshot_list = ontap.get_snapshot_list(volume)

    if ontap_snapshot_list is None:
        return 0

    delete_count = len(ontap_snapshot_list) - purge_limit

    if delete_count <= 0:
        return 0

    database = helpers.connect_db()

    sorted_by_timestamp = sorted(ontap_snapshot_list, key=lambda snap: snap['timestamp'])
    delete_snapshot_list = sorted_by_timestamp[:delete_count]
    for snap in delete_snapshot_list:
        status = ontap.delete_snapshot(volume, snap['snapshot_name'])
        if helpers.verify_successful_response(status):
            # delete snapshot document from db
            doc = Database.get_document_by_name(database, snap['snapshot_name'])
            if not doc:  # if snapshot to be deleted is not found in DB
                logging.info("Purge: snapshot document not found for %s", snap['snapshot_name'])
            else:
                database.delete(doc)
                logging.info("Purge: snapshot deleted from DB and ONTAP: %s",
                             snap['snapshot_name'])
    return delete_count
Esempio n. 2
0
def snapshot_delete():
    """
    Delete snapshot
    ---
    tags:
      - snapshot
    parameters:
      - in: body
        name: snapshot_name
        required: true
        description: name of the snapshot being created
        type: string
      - in: body
        name: volume_name
        required: true
        description: name of the volume that needs to be snapshot
        type: string
    responses:
      200:
        description: snapshot was deleted successfully
    """
    database = helpers.connect_db()
    config_document = helpers.get_db_config()
    if not config_document:
        raise GenericException(
            500,
            "Customer config doc not found, please contact your administrator",
            "Database Exception")
    ontap = OntapService(config_document['ontap_api'],
                         config_document['ontap_apiuser'],
                         config_document['ontap_apipass'],
                         config_document['ontap_svm_name'],
                         config_document['ontap_aggr_name'],
                         config_document['ontap_data_ip'])
    status = ontap.delete_snapshot(request.form['volume_name'],
                                   request.form['snapshot_name'])
    return jsonify(status)
class TestONTAPService(unittest.TestCase):
    ''' Test ONTAP Service '''
    def setUp(self):
        api_credentials = {'api_server': 'ip-address.com', 'username': '******', 'password': '******'}
        self.ontap = OntapService(api_credentials, 'vserver-test', 'aggregate-test')

    @patch('web_service.ontap.ontap_service.Volume.delete_snapshot')
    def test_delete_snapshot(self, mock_delete_snapshot):
        mock_delete_snapshot.return_value = 'COMPLETED', ''

        logging.basicConfig(level='INFO')
        volume_name = 'test_volume_for_ontap_services'
        [response] = self.ontap.delete_snapshot(volume_name, 'test_snapshot')

        self.assertEqual(response['code'], 201)

    @patch('logging.warning')
    @patch('web_service.ontap.ontap_service.Volume.delete_snapshot')
    def test_delete_snapshot_fail(self, mock_delete_snapshot, mock_logger):
        ''' Log ONTAP delete error if snapshot is active '''
        mock_delete_snapshot.return_value = 'FAILED', 'snapshot has not expired or is locked'

        logging.basicConfig(level='WARNING')
        volume_name = 'test_volume_for_ontap_services'
        [response] = self.ontap.delete_snapshot(volume_name, 'test_snapshot')

        mock_logger.assert_called_with(
            'Failed to delete snapshot %s. Most likely clone is in use. error: %s',
            'test_snapshot', 'snapshot has not expired or is locked'
        )
        self.assertEqual(response['code'], 400)

    @patch('logging.error')
    @patch('web_service.ontap.ontap_service.Volume.delete_snapshot')
    def test_delete_snapshot_fail_other(self, mock_delete_snapshot, mock_logger):
        ''' Log ONTAP delete error for other reasons '''
        mock_delete_snapshot.return_value = 'FAILED', 'other error'

        logging.basicConfig(level='WARNING')
        volume_name = 'test_volume_for_ontap_services'
        [response] = self.ontap.delete_snapshot(volume_name, 'test_snapshot')

        mock_logger.assert_called_with(
            'Failed to delete snapshot %s, unexpected error: %s', 'test_snapshot', 'other error'
        )
        self.assertEqual(response['code'], 400)

    @patch('web_service.ontap.ontap_service.OntapService.delete_volume')
    @patch('web_service.ontap.ontap_service.Volume.get_snapdiff')
    @patch('web_service.ontap.ontap_service.OntapService.get_oldest_and_latest_snapshots')
    def test_get_snapdiff_and_delete(self, mock_get_oldest_latest_snapshots, mock_get_snapdiff, mock_delete_volume):
        mock_delete_volume.return_value = mocks.CREATE_VOL_RETURN_VAL
        mock_get_snapdiff.return_value = 0
        mock_get_oldest_latest_snapshots.return_value = ('weekly.5678', '1503002079'), ('weekly.1234', '1503002065')

        deleted, message = self.ontap.get_snapdiff_and_delete('test', 100)
        self.assertEqual(deleted, True)
        self.assertTrue("test has been inactive for" in message)

    @patch('web_service.ontap.ontap_service.Volume.get_snapdiff')
    @patch('web_service.ontap.ontap_service.OntapService.get_oldest_and_latest_snapshots')
    def test_get_snapdiff_and_delete_active(self, mock_get_oldest_latest_snapshots, mock_get_snapdiff):
        mock_get_snapdiff.return_value = 1
        mock_get_oldest_latest_snapshots.return_value = ('weekly.5678', '1503002079'), ('weekly.1234', '1503002065')

        deleted, message = self.ontap.get_snapdiff_and_delete('test', 2)
        self.assertEqual(deleted, False)
        self.assertTrue("test is active" in message)

    @patch('web_service.ontap.ontap_service.OntapService.get_oldest_and_latest_snapshots')
    def test_get_snapdiff_and_delete_new(self, mock_get_oldest_latest_snapshots):
        mock_get_oldest_latest_snapshots.return_value = None, None
        deleted, message = self.ontap.get_snapdiff_and_delete('test', 2)
        self.assertEqual(deleted, False)
        self.assertTrue("Workspace is less than" in message)

    @patch('web_service.ontap.ontap_service.OntapService.get_snapshot_list')
    def test_get_oldest_and_latest_snapshots(self, mock_get_snapshot_list):
        today = datetime.now()
        two_days_old_epoch = (today - timedelta(days=2)).strftime('%s')
        today_epoch = today.strftime('%s')
        two_days_snap = ('two_days_old', two_days_old_epoch)
        today_snap = ('today', today_epoch)
        mock_get_snapshot_list.return_value = [
            two_days_snap,
            today_snap,
        ], ""

        recent, old = self.ontap.get_oldest_and_latest_snapshots('test', 1)
        self.assertEqual(two_days_snap, old)
        self.assertEqual(today_snap, recent)

    @patch('web_service.ontap.ontap_service.OntapService.get_snapshot_list')
    def test_get_oldest_and_latest_snapshots_none(self, mock_get_snapshot_list):
        today = datetime.now()
        one_day_old_epoch = (today - timedelta(days=1)).strftime('%s')
        today_epoch = today.strftime('%s')
        one_day_snap = ('one_day_old', one_day_old_epoch)
        today_snap = ('today', today_epoch)
        mock_get_snapshot_list.return_value = [
            one_day_snap,
            today_snap,
        ], ""

        recent, old = self.ontap.get_oldest_and_latest_snapshots('test', 1)
        self.assertEqual(None, old)
        self.assertEqual(today_snap, recent)

    @patch('web_service.ontap.ontap_service.OntapService.get_snapshot_list')
    def test_get_oldest_and_latest_snapshots_empty(self, mock_get_snapshot_list):
        today = datetime.now()
        one_day_old_epoch = (today - timedelta(days=1)).strftime('%s')
        today_epoch = today.strftime('%s')
        one_day_snap = ('one_day_old', one_day_old_epoch)
        today_snap = ('today', today_epoch)
        mock_get_snapshot_list.return_value = None, "some error message"

        recent, old = self.ontap.get_oldest_and_latest_snapshots('test', 1)
        self.assertIsNone(old)
        self.assertIsNone(recent)