trove/trove/tests/scenario/runners/replication_runners.py

279 lines
12 KiB
Python

# Copyright 2015 Tesora Inc.
# All Rights Reserved.
#
# 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.
from trove.common import utils
from trove.tests.api.instances import CheckInstance
from trove.tests.scenario.helpers.test_helper import DataType
from trove.tests.scenario.runners.test_runners import TestRunner
from troveclient.compat import exceptions
class ReplicationRunner(TestRunner):
def __init__(self):
super(ReplicationRunner, self).__init__()
self.master_id = self.instance_info.id
self.replica_1_id = 0
self.replica_2_id = 0
self.master_host = self.get_instance_host(self.master_id)
self.replica_1_host = None
self.master_backup_count = None
self.used_data_sets = set()
def run_add_data_for_replication(self, data_type=DataType.small):
self.assert_add_replication_data(data_type, self.master_host)
def assert_add_replication_data(self, data_type, host):
"""In order for this to work, the corresponding datastore
'helper' class should implement the 'add_<data_type>_data' method.
"""
self.test_helper.add_data(data_type, host)
self.used_data_sets.add(data_type)
def run_verify_data_for_replication(self, data_type=DataType.small):
self.assert_verify_replication_data(data_type, self.master_host)
def assert_verify_replication_data(self, data_type, host):
"""In order for this to work, the corresponding datastore
'helper' class should implement the 'verify_<data_type>_data' method.
"""
self.test_helper.verify_data(data_type, host)
def run_create_single_replica(self, expected_states=['BUILD', 'ACTIVE'],
expected_http_code=200):
master_id = self.instance_info.id
self.master_backup_count = len(
self.auth_client.instances.backups(master_id))
self.replica_1_id = self.assert_replica_create(
master_id, 'replica1', 1, expected_states, expected_http_code)
self.replica_1_host = self.get_instance_host(self.replica_1_id)
def assert_replica_create(
self, master_id, replica_name, replica_count,
expected_states, expected_http_code):
replica = self.auth_client.instances.create(
self.instance_info.name + replica_name,
self.instance_info.dbaas_flavor_href,
self.instance_info.volume, slave_of=master_id,
nics=self.instance_info.nics,
replica_count=replica_count)
replica_id = replica.id
self.assert_instance_action(replica_id, expected_states,
expected_http_code)
self._assert_is_master(master_id, [replica_id])
self._assert_is_replica(replica_id, master_id)
return replica_id
def _assert_is_master(self, instance_id, replica_ids):
instance = self.get_instance(instance_id)
self.assert_client_code(200)
CheckInstance(instance._info).slaves()
self.assert_true(
set(replica_ids).issubset(self._get_replica_set(instance_id)))
def _get_replica_set(self, master_id):
instance = self.get_instance(master_id)
return set([replica['id'] for replica in instance._info['replicas']])
def _assert_is_replica(self, instance_id, master_id):
instance = self.get_instance(instance_id)
self.assert_client_code(200)
CheckInstance(instance._info).slave_of()
self.assert_equal(master_id, instance._info['replica_of']['id'],
'Unexpected replication master ID')
def run_create_multiple_replicas(self, expected_states=['BUILD', 'ACTIVE'],
expected_http_code=200):
master_id = self.instance_info.id
self.replica_2_id = self.assert_replica_create(
master_id, 'replica2', 2, expected_states, expected_http_code)
def run_add_data_to_replicate(self):
self.assert_add_replication_data(DataType.tiny, self.master_host)
def run_verify_data_to_replicate(self):
self.assert_verify_replication_data(DataType.tiny, self.master_host)
def run_wait_for_data_to_replicate(self):
self.test_helper.wait_for_replicas()
def run_verify_replica_data_orig(self):
self.assert_verify_replica_data(self.instance_info.id, DataType.small)
def assert_verify_replica_data(self, master_id, data_type):
replica_ids = self._get_replica_set(master_id)
for replica_id in replica_ids:
replica_instance = self.get_instance(replica_id)
host = str(replica_instance._info['ip'][0])
self.report.log("Checking data on host %s" % host)
self.assert_verify_replication_data(data_type, host)
def run_verify_replica_data_new(self):
self.assert_verify_replica_data(self.instance_info.id, DataType.tiny)
def run_promote_master(self, expected_exception=exceptions.BadRequest,
expected_http_code=400):
self.assert_raises(
expected_exception, expected_http_code,
self.auth_client.instances.promote_to_replica_source,
self.instance_info.id)
def run_eject_replica(self, expected_exception=exceptions.BadRequest,
expected_http_code=400):
self.assert_raises(
expected_exception, expected_http_code,
self.auth_client.instances.eject_replica_source,
self.replica_1_id)
def run_eject_valid_master(self, expected_exception=exceptions.BadRequest,
expected_http_code=400):
self.assert_raises(
expected_exception, expected_http_code,
self.auth_client.instances.eject_replica_source,
self.instance_info.id)
def run_delete_valid_master(self, expected_exception=exceptions.Forbidden,
expected_http_code=403):
self.assert_raises(
expected_exception, expected_http_code,
self.auth_client.instances.delete,
self.instance_info.id)
def run_promote_to_replica_source(self,
expected_states=['PROMOTE', 'ACTIVE'],
expected_http_code=202):
self.assert_promote_to_replica_source(
self.replica_1_id, self.instance_info.id, expected_states,
expected_http_code)
def assert_promote_to_replica_source(
self, new_master_id, old_master_id,
expected_states, expected_http_code):
original_replica_ids = self._get_replica_set(old_master_id)
other_replica_ids = list(original_replica_ids)
other_replica_ids.remove(new_master_id)
# Promote replica
self.assert_replica_promote(new_master_id, expected_states,
expected_http_code)
current_replica_ids = list(other_replica_ids)
current_replica_ids.append(old_master_id)
self._assert_is_master(new_master_id, current_replica_ids)
self._assert_is_replica(old_master_id, new_master_id)
def assert_replica_promote(
self, new_master_id, expected_states, expected_http_code):
self.auth_client.instances.promote_to_replica_source(new_master_id)
self.assert_instance_action(new_master_id, expected_states,
expected_http_code)
def run_add_data_to_replicate2(self):
self.assert_add_replication_data(DataType.tiny2, self.replica_1_host)
def run_verify_data_to_replicate2(self):
self.assert_verify_replication_data(DataType.tiny2,
self.replica_1_host)
def run_verify_replica_data_new2(self):
self.assert_verify_replica_data(self.replica_1_id, DataType.tiny2)
def run_promote_original_source(self,
expected_states=['PROMOTE', 'ACTIVE'],
expected_http_code=202):
self.assert_promote_to_replica_source(
self.instance_info.id, self.replica_1_id, expected_states,
expected_http_code)
def run_remove_replicated_data(self):
self.assert_remove_replicated_data(self.master_host)
def assert_remove_replicated_data(self, host):
"""In order for this to work, the corresponding datastore
'helper' class should implement the 'remove_<type>_data' method.
"""
for data_set in self.used_data_sets:
self.report.log("Removing replicated data set: %s" % data_set)
self.test_helper.remove_data(data_set, host)
def run_detach_replica_from_source(self,
expected_states=['ACTIVE'],
expected_http_code=202):
self.assert_detach_replica_from_source(
self.instance_info.id, self.replica_1_id,
expected_states, expected_http_code)
def assert_detach_replica_from_source(
self, master_id, replica_id, expected_states,
expected_http_code):
other_replica_ids = self._get_replica_set(master_id)
other_replica_ids.remove(replica_id)
self.assert_detach_replica(
replica_id, expected_states, expected_http_code)
self._assert_is_master(master_id, other_replica_ids)
self._assert_is_not_replica(replica_id, master_id)
def assert_detach_replica(
self, replica_id, expected_states, expected_http_code):
self.auth_client.instances.edit(replica_id,
detach_replica_source=True)
self.assert_instance_action(
replica_id, expected_states, expected_http_code)
def _assert_is_not_replica(self, instance_id, master_id):
try:
self._assert_is_replica(instance_id, master_id)
self.fail("Non-replica '%s' is still replica of '%s'" %
(instance_id, master_id))
except AssertionError:
pass
def run_delete_detached_replica(self,
expected_last_state=['SHUTDOWN'],
expected_http_code=202):
self.assert_delete_instances(
self.replica_1_id, expected_last_state=expected_last_state,
expected_http_code=expected_http_code)
def assert_delete_instances(
self, instance_ids, expected_last_state, expected_http_code):
instance_ids = (instance_ids if utils.is_collection(instance_ids)
else [instance_ids])
for instance_id in instance_ids:
self.auth_client.instances.delete(instance_id)
self.assert_client_code(expected_http_code)
self.assert_all_gone(instance_ids, expected_last_state)
def run_delete_all_replicas(self, expected_last_state=['SHUTDOWN'],
expected_http_code=202):
self.assert_delete_all_replicas(
self.instance_info.id, expected_last_state,
expected_http_code)
def assert_delete_all_replicas(
self, master_id, expected_last_state, expected_http_code):
self.report.log("Deleting a replication set: %s" % master_id)
replica_ids = self._get_replica_set(master_id)
self.assert_delete_instances(replica_ids, expected_last_state,
expected_http_code)
def run_test_backup_deleted(self):
backup = self.auth_client.instances.backups(self.master_id)
self.assert_equal(self.master_backup_count, len(backup))