def test_repair_reload_set_uri(cartridge_cmd, start_stop_cli, project_with_cartridge, tmpdir):
    project = project_with_cartridge
    cli = start_stop_cli

    cmd = [
        cartridge_cmd,
        "build",
        project.path
    ]
    process = subprocess.run(cmd, cwd=tmpdir)
    assert process.returncode == 0, "Error during building the project"

    # patch cartridge.cfg to don't change process title
    patch_cartridge_proc_titile(project)

    # start instances
    INSTANCE1 = 'instance-1'
    INSTANCE2 = 'instance-2'

    ID1 = get_instance_id(project.name, INSTANCE1)
    ID2 = get_instance_id(project.name, INSTANCE2)

    ADMIN_HTTP_PORT = 8081
    ADVERTISE_URI_TO_CHANGE = 'localhost:3302'
    NEW_ADVERTISE_URI = 'localhost:3322'
    INSTANCE_TO_SET_URI = INSTANCE2

    cfg = {
        ID1: {
            'advertise_uri': 'localhost:3301',
            'http_port': ADMIN_HTTP_PORT,
            'replication_connect_quorum': 0,
            'custom_proc_title': '',
        },
        ID2: {
            'advertise_uri': ADVERTISE_URI_TO_CHANGE,
            'http_port': 8082,
            'replication_connect_quorum': 0,
            'custom_proc_title': '',
        },
    }

    write_conf(os.path.join(project.path, DEFAULT_CFG), cfg)

    # start instance-1 and instance-2
    cli.start(project, daemonized=True)
    check_instances_running(cli, project, [INSTANCE1, INSTANCE2], daemonized=True)

    advertise_uris = [cfg[id]['advertise_uri'] for id in cfg]

    admin_api_url = 'http://localhost:%s/admin/api' % ADMIN_HTTP_PORT

    # join instances to replicaset
    replicaset_uuid = create_replicaset(admin_api_url, advertise_uris, ['vshard-storage'])

    replicaset = get_replicaset(admin_api_url, replicaset_uuid)
    instance_to_set_uri_uuid = None
    for instance in replicaset['servers']:
        if instance['uri'] == ADVERTISE_URI_TO_CHANGE:
            instance_to_set_uri_uuid = instance['uuid']
            break

    assert instance_to_set_uri_uuid is not None

    # first, change URI in config and restart instance
    INSTANCE_ID = get_instance_id(project.name, INSTANCE_TO_SET_URI)

    cfg[INSTANCE_ID]['advertise_uri'] = NEW_ADVERTISE_URI
    write_conf(os.path.join(project.path, DEFAULT_CFG), cfg)

    cli.stop(project, [INSTANCE_TO_SET_URI])
    check_instances_stopped(cli, project, [INSTANCE_TO_SET_URI])

    cli.start(project, [INSTANCE_TO_SET_URI], daemonized=True)
    check_instances_running(cli, project, [INSTANCE1, INSTANCE2],  daemonized=True, skip_env_checks=True)

    # then, update cluster-wide configs
    data_dir = os.path.join(project.path, DEFAULT_DATA_DIR)
    run_dir = os.path.join(project.path, DEFAULT_RUN_DIR)

    cmd = [
        cartridge_cmd, 'repair', 'set-advertise-uri',
        '--name', project.name,
        '--data-dir', data_dir,
        '--run-dir', run_dir,
        '--reload',
        '--verbose',
        instance_to_set_uri_uuid, NEW_ADVERTISE_URI,
    ]

    rc, output = run_command_and_get_output(cmd, cwd=tmpdir)
    assert rc == 0

    wait_for_replicaset_is_healthy(admin_api_url, replicaset_uuid)

    new_replicaset = get_replicaset(admin_api_url, replicaset_uuid)
    new_replicaset_instance_advertise_uri = None
    for instance in new_replicaset['servers']:
        if instance['uuid'] == instance_to_set_uri_uuid:
            new_replicaset_instance_advertise_uri = instance['uri']
            break

    assert new_replicaset_instance_advertise_uri == NEW_ADVERTISE_URI
def test_repair_reload_set_leader(cartridge_cmd, start_stop_cli, project_with_cartridge, tmpdir):
    project = project_with_cartridge
    cli = start_stop_cli

    cmd = [
        cartridge_cmd,
        "build",
        project.path
    ]
    process = subprocess.run(cmd, cwd=tmpdir)
    assert process.returncode == 0, "Error during building the project"

    # patch cartridge.cfg to don't change process title
    patch_cartridge_proc_titile(project)

    # start instances
    INSTANCE1 = 'instance-1'
    INSTANCE2 = 'instance-2'

    ID1 = get_instance_id(project.name, INSTANCE1)
    ID2 = get_instance_id(project.name, INSTANCE2)

    ADMIN_HTTP_PORT = 8081

    cfg = {
        ID1: {
            'advertise_uri': 'localhost:3301',
            'http_port': ADMIN_HTTP_PORT,
        },
        ID2: {
            'advertise_uri': 'localhost:3302',
            'http_port': 8082,
        },
    }

    write_conf(os.path.join(project.path, DEFAULT_CFG), cfg)

    # start instance-1 and instance-2
    cli.start(project, daemonized=True)
    check_instances_running(cli, project, [INSTANCE1, INSTANCE2], daemonized=True)

    advertise_uris = [cfg[id]['advertise_uri'] for id in cfg]

    # join instances to replicaset
    admin_api_url = 'http://localhost:%s/admin/api' % ADMIN_HTTP_PORT
    replicaset_uuid = create_replicaset(admin_api_url, advertise_uris, ['vshard-storage'])

    replicaset = get_replicaset(admin_api_url, replicaset_uuid)
    cluster_instances = replicaset['servers']

    # change leader
    instances_by_priority = sorted(cluster_instances, key=lambda i: i['priority'])
    new_leader_uuid = instances_by_priority[-1]['uuid']

    data_dir = os.path.join(project.path, DEFAULT_DATA_DIR)
    run_dir = os.path.join(project.path, DEFAULT_RUN_DIR)

    cmd = [
        cartridge_cmd, 'repair', 'set-leader',
        '--name', project.name,
        '--data-dir', data_dir,
        '--run-dir', run_dir,
        '--reload',
        '--verbose',
        replicaset_uuid, new_leader_uuid,
    ]

    rc, output = run_command_and_get_output(cmd, cwd=tmpdir)
    assert rc == 0

    wait_for_replicaset_is_healthy(admin_api_url, replicaset_uuid)

    new_replicaset = get_replicaset(admin_api_url, replicaset_uuid)
    new_replicaset_leader_uuid = new_replicaset['master']['uuid']

    assert new_replicaset_leader_uuid == new_leader_uuid
def test_repair_reload_remove_instance(cartridge_cmd, start_stop_cli, project_with_cartridge, tmpdir):
    project = project_with_cartridge
    cli = start_stop_cli

    cmd = [
        cartridge_cmd,
        "build",
        project.path
    ]
    process = subprocess.run(cmd, cwd=tmpdir)
    assert process.returncode == 0, "Error during building the project"

    # patch cartridge.cfg to don't change process title
    patch_cartridge_proc_titile(project)

    # start instances
    INSTANCE1 = 'instance-1'
    INSTANCE2 = 'instance-2'

    ID1 = get_instance_id(project.name, INSTANCE1)
    ID2 = get_instance_id(project.name, INSTANCE2)

    ADVERTISE_URI_TO_REMOVE = 'localhost:3302'
    ADMIN_HTTP_PORT = 8081

    cfg = {
        # this instance shouldn't be removed since we use it's http port
        ID1: {
            'advertise_uri': 'localhost:3301',
            'http_port': ADMIN_HTTP_PORT,
        },
        ID2: {
            'advertise_uri': ADVERTISE_URI_TO_REMOVE,
            'http_port': 8082,
        },
    }

    write_conf(os.path.join(project.path, DEFAULT_CFG), cfg)

    # start instance-1 and instance-2
    cli.start(project, daemonized=True)
    check_instances_running(cli, project, [INSTANCE1, INSTANCE2], daemonized=True)

    advertise_uris = [cfg[id]['advertise_uri'] for id in cfg]

    admin_api_url = 'http://localhost:%s/admin/api' % ADMIN_HTTP_PORT

    # join instances to replicaset
    replicaset_uuid = create_replicaset(admin_api_url, advertise_uris, ['vshard-storage'])

    replicaset = get_replicaset(admin_api_url, replicaset_uuid)
    cluster_instances = replicaset['servers']

    # change leader
    instance_to_remove_uuid = None
    for instance in cluster_instances:
        if instance['uri'] == ADVERTISE_URI_TO_REMOVE:
            instance_to_remove_uuid = instance['uuid']
            break

    assert instance_to_remove_uuid is not None

    data_dir = os.path.join(project.path, DEFAULT_DATA_DIR)
    run_dir = os.path.join(project.path, DEFAULT_RUN_DIR)

    cmd = [
        cartridge_cmd, 'repair', 'remove-instance',
        '--name', project.name,
        '--data-dir', data_dir,
        '--run-dir', run_dir,
        '--reload',
        '--verbose',
        instance_to_remove_uuid,
    ]

    rc, output = run_command_and_get_output(cmd, cwd=tmpdir)
    assert rc == 0

    wait_for_replicaset_is_healthy(admin_api_url, replicaset_uuid)

    new_replicaset = get_replicaset(admin_api_url, replicaset_uuid)
    new_replicaset_instances_uuids = [
        instance['uuid'] for instance in new_replicaset['servers']
    ]

    assert instance_to_remove_uuid not in new_replicaset_instances_uuids
def test_api(start_stop_cli, cartridge_cmd, project_getting_started):
    project = project_getting_started
    cli = start_stop_cli

    APP_INSTANCES = [project.get_instance_id('router')]
    S1_INSTANCES = [
        project.get_instance_id('s1-master'),
        project.get_instance_id('s1-replica')
    ]
    S2_INSTANCES = [
        project.get_instance_id('s2-master'),
        project.get_instance_id('s2-replica')
    ]

    # build app
    process = subprocess.run([cartridge_cmd, 'build'], cwd=project.path)
    assert process.returncode == 0

    patch_cartridge_proc_titile(project)

    # check config and get instances
    instances_conf = get_instances_from_conf(project)
    instance_ids = list(instances_conf.keys())
    instances = [instance_id.split(".")[1] for instance_id in instance_ids]

    assert all([
        instance_id in instance_ids
        for instance_id in APP_INSTANCES + S1_INSTANCES + S2_INSTANCES
    ])

    router_http_port = instances_conf[APP_INSTANCES[0]]['http_port']
    admin_api_url = 'http://localhost:{}/admin/api'.format(router_http_port)

    # start application in interactive mode (to easily check logs on debug)
    cli.start(project)
    check_instances_running(cli, project, instances)

    # create app replicaset
    uris = [
        instances_conf[instance_id]['advertise_uri']
        for instance_id in APP_INSTANCES
    ]
    roles = ['api']
    app_replicaset_uuid = create_replicaset(admin_api_url, uris, roles)
    wait_for_replicaset_is_healthy(admin_api_url, app_replicaset_uuid)

    replicaset_roles = get_replicaset_roles(admin_api_url, app_replicaset_uuid)
    # api role should contain vshard-router dependency
    assert set(replicaset_roles) == set(['api', 'vshard-router'])

    # create s1 replicaset
    uris = [
        instances_conf[instance_id]['advertise_uri']
        for instance_id in S1_INSTANCES
    ]
    roles = ['storage']
    s1_replicaset_uuid = create_replicaset(admin_api_url, uris, roles)
    wait_for_replicaset_is_healthy(admin_api_url, s1_replicaset_uuid)

    replicaset_roles = get_replicaset_roles(admin_api_url, s1_replicaset_uuid)
    # storage role should contain vshard-storage dependency
    assert set(replicaset_roles) == set(['storage', 'vshard-storage'])

    # create s2 replicaset
    uris = [
        instances_conf[instance_id]['advertise_uri']
        for instance_id in S2_INSTANCES
    ]
    roles = ['storage']
    s2_replicaset_uuid = create_replicaset(admin_api_url, uris, roles)
    wait_for_replicaset_is_healthy(admin_api_url, s2_replicaset_uuid)

    replicaset_roles = get_replicaset_roles(admin_api_url, s2_replicaset_uuid)
    # storage role should contain vshard-storage dependency
    assert set(replicaset_roles) == set(['storage', 'vshard-storage'])

    # bootstrap vshard
    bootstrap_vshard(admin_api_url)

    # test HTTP API
    CUSTOMER_ID = 10
    CUSTOMER_NAME = 'Elizabeth'
    customer = {'customer_id': CUSTOMER_ID, 'name': CUSTOMER_NAME}

    # create new customer
    url = 'http://localhost:{}/storage/customers/create'.format(
        router_http_port)
    r = requests.post(url, json=customer)
    assert r.status_code == requests.status_codes.codes.CREATED
    resp = r.json()
    assert 'info' in resp
    assert resp['info'] == 'Successfully created'

    # # create the same customer again
    # r = requests.post(url, json=customer)
    # # XXX: r.status_code is 500 now

    # get customer
    url = 'http://localhost:{}/storage/customers/{}'.format(
        router_http_port, CUSTOMER_ID)
    r = requests.get(url, json=customer)
    assert r.status_code == requests.status_codes.codes.OK
    resp = r.json()
    assert resp == {
        'customer_id': CUSTOMER_ID,
        'name': CUSTOMER_NAME,
        'accounts': [],
    }

    # get customer by wrong id
    url = 'http://localhost:{}/storage/customers/{}'.format(
        router_http_port, CUSTOMER_ID + 1)
    r = requests.get(url, json=customer)
    assert r.status_code == requests.status_codes.codes.NOT_FOUND
    resp = r.json()
    assert 'info' in resp
    assert resp['info'] == 'Customer not found'