예제 #1
0
def test_apply_args_filters_clusters_return_none_when_instance_not_in_deploy_group(
    mock_figure_out_service_name,
    mock_list_services,
    mock_get_instance_configs_for_service,
):
    args = StatusArgs(
        service='fake_service',
        soa_dir='/fake/soa/dir',
        deploy_group='fake_deploy_group',
        clusters=None,
        instances='instance5',
        owner=None,
        registration=None,
        verbose=False,
    )
    mock_figure_out_service_name.return_value = 'fake_service'
    mock_list_services.return_value = ['fake_service']
    mock_get_instance_configs_for_service.return_value = [
        make_fake_instance_conf('cluster1', 'fake_service', 'instance1',
                                'other_fake_deploy_group'),
        make_fake_instance_conf('cluster1', 'fake_service', 'instance2',
                                'other_fake_deploy_group'),
        make_fake_instance_conf('cluster2', 'fake_service', 'instance3',
                                'other_fake_deploy_group'),
    ]

    assert len(apply_args_filters(args)) == 0
예제 #2
0
def test_apply_args_filters_clusters_and_instances(
    mock_figure_out_service_name,
    mock_list_services,
    mock_get_instance_configs_for_service,
):
    args = StatusArgs(
        service='fake_service',
        soa_dir='/fake/soa/dir',
        deploy_group=None,
        clusters='cluster1',
        instances='instance1,instance3',
        owner=None,
        registration=None,
        verbose=False,
    )
    mock_figure_out_service_name.return_value = 'fake_service'
    mock_list_services.return_value = ['fake_service']
    mock_inst1 = make_fake_instance_conf('cluster1', 'fake_service',
                                         'instance1', 'fake_deploy_group')
    mock_inst2 = make_fake_instance_conf('cluster1', 'fake_service',
                                         'instance2', 'fake_deploy_group')
    mock_inst3 = make_fake_instance_conf('cluster1', 'fake_service',
                                         'instance3', 'fake_deploy_group')
    mock_get_instance_configs_for_service.return_value = [
        mock_inst1,
        mock_inst2,
        mock_inst3,
    ]

    pargs = apply_args_filters(args)
    assert sorted(pargs.keys()) == ['cluster1']
    assert pargs['cluster1']['fake_service'] == {
        'instance1': mock_inst1.__class__,
        'instance3': mock_inst3.__class__
    }
예제 #3
0
def test_apply_args_filters_clusters_return_none_when_instance_not_in_deploy_group(
    mock_figure_out_service_name,
    mock_list_services,
    mock_get_instance_configs_for_service,
):
    PaastaArgs = namedtuple('PaastaArgs', [
        'service', 'soa_dir', 'clusters', 'instances', 'deploy_group', 'owner'
    ])
    args = PaastaArgs(
        service='fake_service',
        soa_dir='/fake/soa/dir',
        deploy_group='fake_deploy_group',
        clusters=None,
        instances='instance5',
        owner=None,
    )
    mock_figure_out_service_name.return_value = 'fake_service'
    mock_list_services.return_value = ['fake_service']
    mock_get_instance_configs_for_service.return_value = [
        make_fake_instance_conf('cluster1', 'fake_service', 'instance1',
                                'other_fake_deploy_group'),
        make_fake_instance_conf('cluster1', 'fake_service', 'instance2',
                                'other_fake_deploy_group'),
        make_fake_instance_conf('cluster2', 'fake_service', 'instance3',
                                'other_fake_deploy_group'),
    ]

    assert len(apply_args_filters(args)) == 0
예제 #4
0
def test_apply_args_filters_clusters_and_instances(
    mock_figure_out_service_name,
    mock_list_services,
    mock_get_instance_configs_for_service,
):
    PaastaArgs = namedtuple('PaastaArgs', [
        'service', 'soa_dir', 'clusters', 'instances', 'deploy_group', 'owner'
    ])
    args = PaastaArgs(
        service='fake_service',
        soa_dir='/fake/soa/dir',
        deploy_group=None,
        clusters='cluster1',
        instances='instance1,instance3',
        owner=None,
    )
    mock_figure_out_service_name.return_value = 'fake_service'
    mock_list_services.return_value = ['fake_service']
    mock_get_instance_configs_for_service.return_value = [
        make_fake_instance_conf('cluster1', 'fake_service', 'instance1',
                                'fake_deploy_group'),
        make_fake_instance_conf('cluster1', 'fake_service', 'instance2',
                                'fake_deploy_group'),
        make_fake_instance_conf('cluster1', 'fake_service', 'instance3',
                                'fake_deploy_group'),
    ]

    pargs = apply_args_filters(args)
    assert sorted(pargs.keys()) == ['cluster1']
    assert pargs['cluster1']['fake_service'] == {'instance1', 'instance3'}
예제 #5
0
def test_apply_args_filters_no_instances_found(
    mock_figure_out_service_name, mock_list_services, mock_get_instance_configs_for_service,
    mock_list_all_instances_for_service, capfd,
):
    args = StatusArgs(
        service='fake_service',
        soa_dir='/fake/soa/dir',
        deploy_group=None,
        clusters='cluster1',
        instances='instance4,instance5',
        owner=None,
        registration=None,
        verbose=False,
    )
    mock_figure_out_service_name.return_value = 'fake_service'
    mock_list_services.return_value = ['fake_service']
    mock_get_instance_configs_for_service.return_value = [
        make_fake_instance_conf('cluster1', 'fake_service', 'instance1', 'fake_deploy_group'),
        make_fake_instance_conf('cluster1', 'fake_service', 'instance2', 'fake_deploy_group'),
        make_fake_instance_conf('cluster1', 'fake_service', 'instance3', 'fake_deploy_group'),
    ]
    mock_list_all_instances_for_service.return_value = ['instance1', 'instance2', 'instance3']
    pargs = apply_args_filters(args)
    output, _ = capfd.readouterr()
    assert len(pargs.keys()) == 0
    assert "fake_service doesn't have any instances matching instance4, instance5 on cluster1." in output
    assert "Did you mean any of these?" in output
    for i in ["instance1", "instance2", "instance3"]:
        assert i in output
예제 #6
0
def test_apply_args_filters_clusters_uses_deploy_group_when_no_clusters_and_instances(
    mock_figure_out_service_name, mock_list_services, mock_get_instance_configs_for_service,
):
    args = StatusArgs(
        service='fake_service',
        soa_dir='/fake/soa/dir',
        deploy_group='fake_deploy_group',
        clusters=None,
        instances=None,
        owner=None,
        registration=None,
        verbose=False,
    )

    mock_figure_out_service_name.return_value = 'fake_service'
    mock_list_services.return_value = ['fake_service']
    mock_get_instance_configs_for_service.return_value = [
        make_fake_instance_conf('cluster1', 'fake_service', 'instance1', 'fake_deploy_group'),
        make_fake_instance_conf('cluster1', 'fake_service', 'instance2', 'fake_deploy_group'),
        make_fake_instance_conf('cluster2', 'fake_service', 'instance3', 'fake_deploy_group'),
    ]

    pargs = apply_args_filters(args)
    assert sorted(pargs.keys()) == ['cluster1', 'cluster2']
    assert pargs['cluster1']['fake_service'] == {'instance1', 'instance2'}
    assert pargs['cluster2']['fake_service'] == {'instance3'}
예제 #7
0
def paasta_restart(args):
    pargs = apply_args_filters(args)
    soa_dir = args.soa_dir

    affected_flinks = []
    affected_non_flinks = []
    for cluster, service_instances in pargs.items():
        for service, instances in service_instances.items():
            for instance in instances.keys():
                service_config = get_instance_config(
                    service=service,
                    cluster=cluster,
                    instance=instance,
                    soa_dir=soa_dir,
                    load_deployments=False,
                )
                if isinstance(service_config, FlinkDeploymentConfig):
                    affected_flinks.append(service_config)
                else:
                    affected_non_flinks.append(service_config)

    if affected_flinks:
        flinks_info = ", ".join(
            [f"{f.service}.{f.instance}" for f in affected_flinks])
        print(
            f"WARN: paasta restart is currently unsupported for Flink instances ({flinks_info})."
        )
        print("To restart, please run:", end="\n\n")
        for flink in affected_flinks:
            print(
                f"paasta stop -s {flink.service} -i {flink.instance} -c {flink.cluster}"
            )
            print(
                f"paasta start -s {flink.service} -i {flink.instance} -c {flink.cluster}",
                end="\n\n",
            )

        if not affected_non_flinks:
            return 1

        non_flinks_info = ", ".join(
            [f"{f.service}.{f.instance}" for f in affected_non_flinks])
        proceed = choice.Binary(
            f"Would you like to restart the other instances ({non_flinks_info}) anyway?",
            False,
        ).ask()

        if not proceed:
            return 1

    return paasta_start(args)
예제 #8
0
def test_apply_args_filters_bad_service_name(mock_list_services, capfd):
    args = StatusArgs(
        service='fake-service',
        soa_dir='/fake/soa/dir',
        deploy_group=None,
        clusters='cluster1',
        instances='instance4,instance5',
        owner=None,
        registration=None,
        verbose=False,
    )
    mock_list_services.return_value = ['fake_service']
    pargs = apply_args_filters(args)
    output, _ = capfd.readouterr()
    assert len(pargs) == 0
    assert 'The service "fake-service" does not exist.' in output
    assert 'Did you mean any of these?' in output
    assert '  fake_service' in output
예제 #9
0
def test_apply_args_filters_bad_service_name(mock_list_services, capfd):
    PaastaArgs = namedtuple('PaastaArgs', [
        'service', 'soa_dir', 'clusters', 'instances', 'deploy_group', 'owner'
    ])
    args = PaastaArgs(
        service='fake-service',
        soa_dir='/fake/soa/dir',
        deploy_group=None,
        clusters='cluster1',
        instances='instance4,instance5',
        owner=None,
    )
    mock_list_services.return_value = ['fake_service']
    pargs = apply_args_filters(args)
    output, _ = capfd.readouterr()
    assert len(pargs) == 0
    assert 'The service "fake-service" does not exist.' in output
    assert 'Did you mean any of these?' in output
    assert '  fake_service' in output
예제 #10
0
def paasta_start_or_stop(args, desired_state):
    """Requests a change of state to start or stop given branches of a service."""
    soa_dir = args.soa_dir

    pargs = apply_args_filters(args)
    if len(pargs) == 0:
        return 1

    affected_services = {s for service_list in pargs.values() for s in service_list.keys()}
    if len(affected_services) > 1:
        paasta_print(PaastaColors.red("Warning: trying to start/stop/restart multiple services:"))

        for cluster, services_instances in pargs.items():
            paasta_print("Cluster %s:" % cluster)
            for service, instances in services_instances.items():
                paasta_print("    Service %s:" % service)
                paasta_print("        Instances %s" % ",".join(instances))

        if sys.stdin.isatty():
            confirm = choice.Binary('Are you sure you want to continue?', False).ask()
        else:
            confirm = False
        if not confirm:
            paasta_print()
            paasta_print("exiting")
            return 1

    invalid_deploy_groups = []
    marathon_message_printed, chronos_message_printed = False, False
    for cluster, services_instances in pargs.items():
        for service, instances in services_instances.items():
            try:
                remote_refs = remote_git.list_remote_refs(utils.get_git_url(service, soa_dir))
            except remote_git.LSRemoteException as e:
                msg = (
                    "Error talking to the git server: %s\n"
                    "This PaaSTA command requires access to the git server to operate.\n"
                    "The git server may be down or not reachable from here.\n"
                    "Try again from somewhere where the git server can be reached, "
                    "like your developer environment."
                ) % str(e)
                paasta_print(msg)
                return 1

            for instance in instances:
                service_config = get_instance_config(
                    service=service,
                    cluster=cluster,
                    instance=instance,
                    soa_dir=soa_dir,
                    load_deployments=False,
                )
                deploy_group = service_config.get_deploy_group()
                (deploy_tag, _) = get_latest_deployment_tag(remote_refs, deploy_group)

                if deploy_tag not in remote_refs:
                    invalid_deploy_groups.append(deploy_group)
                else:
                    force_bounce = utils.format_timestamp(datetime.datetime.utcnow())
                    if isinstance(service_config, MarathonServiceConfig) and not marathon_message_printed:
                        print_marathon_message(desired_state)
                        marathon_message_printed = True
                    elif isinstance(service_config, ChronosJobConfig) and not chronos_message_printed:
                        print_chronos_message(desired_state)
                        chronos_message_printed = True

                    issue_state_change_for_service(
                        service_config=service_config,
                        force_bounce=force_bounce,
                        desired_state=desired_state,
                    )

    return_val = 0
    if invalid_deploy_groups:
        paasta_print("No branches found for %s in %s." %
                     (", ".join(invalid_deploy_groups), remote_refs))
        paasta_print("Has %s been deployed there yet?" % service)
        return_val = 1

    return return_val
예제 #11
0
def paasta_start_or_stop(args, desired_state):
    """Requests a change of state to start or stop given branches of a service."""
    soa_dir = args.soa_dir

    pargs = apply_args_filters(args)
    if len(pargs) == 0:
        return 1

    affected_services = {
        s
        for service_list in pargs.values() for s in service_list.keys()
    }
    if len(affected_services) > 1:
        print(
            PaastaColors.red(
                "Warning: trying to start/stop/restart multiple services:"))

        for cluster, services_instances in pargs.items():
            print("Cluster %s:" % cluster)
            for service, instances in services_instances.items():
                print("    Service %s:" % service)
                print("        Instances %s" % ",".join(instances.keys()))

        if sys.stdin.isatty():
            confirm = choice.Binary("Are you sure you want to continue?",
                                    False).ask()
        else:
            confirm = False
        if not confirm:
            print()
            print("exiting")
            return 1

    invalid_deploy_groups = []
    marathon_message_printed = False
    affected_flinks = []

    if args.clusters is None or args.instances is None:
        if confirm_to_continue(pargs.items(), desired_state) is False:
            print()
            print("exiting")
            return 1

    for cluster, services_instances in pargs.items():
        for service, instances in services_instances.items():
            for instance in instances.keys():
                service_config = get_instance_config(
                    service=service,
                    cluster=cluster,
                    instance=instance,
                    soa_dir=soa_dir,
                    load_deployments=False,
                )
                if isinstance(service_config, FlinkDeploymentConfig):
                    affected_flinks.append(service_config)
                    continue

                try:
                    remote_refs = get_remote_refs(service, soa_dir)
                except remote_git.LSRemoteException as e:
                    msg = (
                        "Error talking to the git server: %s\n"
                        "This PaaSTA command requires access to the git server to operate.\n"
                        "The git server may be down or not reachable from here.\n"
                        "Try again from somewhere where the git server can be reached, "
                        "like your developer environment.") % str(e)
                    print(msg)
                    return 1

                deploy_group = service_config.get_deploy_group()
                (deploy_tag,
                 _) = get_latest_deployment_tag(remote_refs, deploy_group)

                if deploy_tag not in remote_refs:
                    invalid_deploy_groups.append(deploy_group)
                else:
                    force_bounce = utils.format_timestamp(
                        datetime.datetime.utcnow())
                    if (isinstance(service_config, MarathonServiceConfig)
                            and not marathon_message_printed):
                        print_marathon_message(desired_state)
                        marathon_message_printed = True

                    issue_state_change_for_service(
                        service_config=service_config,
                        force_bounce=force_bounce,
                        desired_state=desired_state,
                    )

    return_val = 0

    # TODO: Refactor to discover if set_state is available for given
    #       instance_type in API
    if affected_flinks:
        print_flink_message(desired_state)
        csi = defaultdict(lambda: defaultdict(list))
        for service_config in affected_flinks:
            csi[service_config.cluster][service_config.service].append(
                service_config.instance)

        system_paasta_config = load_system_paasta_config()
        for cluster, services_instances in csi.items():
            client = get_paasta_api_client(cluster, system_paasta_config)
            if not client:
                print("Cannot get a paasta-api client")
                exit(1)

            for service, instances in services_instances.items():
                for instance in instances:
                    try:
                        client.service.instance_set_state(
                            service=service,
                            instance=instance,
                            desired_state=desired_state,
                        ).result()
                    except HTTPError as exc:
                        print(exc.response.text)
                        return exc.status_code

                return_val = 0

    if invalid_deploy_groups:
        print(f"No deploy tags found for {', '.join(invalid_deploy_groups)}.")
        print(f"Has {service} been deployed there yet?")
        return_val = 1

    return return_val
예제 #12
0
def paasta_start_or_stop(args, desired_state):
    """Requests a change of state to start or stop given branches of a service."""
    soa_dir = args.soa_dir

    pargs = apply_args_filters(args)
    if len(pargs) == 0:
        return 1

    affected_services = {
        s
        for service_list in pargs.values() for s in service_list.keys()
    }
    if len(affected_services) > 1:
        paasta_print(
            PaastaColors.red(
                "Warning: trying to start/stop/restart multiple services:"))

        for cluster, services_instances in pargs.items():
            paasta_print("Cluster %s:" % cluster)
            for service, instances in services_instances.items():
                paasta_print("    Service %s:" % service)
                paasta_print("        Instances %s" %
                             ",".join(instances.keys()))

        if sys.stdin.isatty():
            confirm = choice.Binary('Are you sure you want to continue?',
                                    False).ask()
        else:
            confirm = False
        if not confirm:
            paasta_print()
            paasta_print("exiting")
            return 1

    invalid_deploy_groups = []
    marathon_message_printed = False
    chronos_message_printed = False
    affected_flinkclusters = []

    if args.clusters is None or args.instances is None:
        if confirm_to_continue(pargs.items(), desired_state) is False:
            paasta_print()
            paasta_print("exiting")
            return 1

    for cluster, services_instances in pargs.items():
        for service, instances in services_instances.items():
            for instance in instances.keys():
                service_config = get_instance_config(
                    service=service,
                    cluster=cluster,
                    instance=instance,
                    soa_dir=soa_dir,
                    load_deployments=False,
                )
                if isinstance(service_config, FlinkClusterConfig):
                    affected_flinkclusters.append(service_config)
                    continue

                try:
                    remote_refs = get_remote_refs(service, soa_dir)
                except remote_git.LSRemoteException as e:
                    msg = (
                        "Error talking to the git server: %s\n"
                        "This PaaSTA command requires access to the git server to operate.\n"
                        "The git server may be down or not reachable from here.\n"
                        "Try again from somewhere where the git server can be reached, "
                        "like your developer environment.") % str(e)
                    paasta_print(msg)
                    return 1

                deploy_group = service_config.get_deploy_group()
                (deploy_tag,
                 _) = get_latest_deployment_tag(remote_refs, deploy_group)

                if deploy_tag not in remote_refs:
                    invalid_deploy_groups.append(deploy_group)
                else:
                    force_bounce = utils.format_timestamp(
                        datetime.datetime.utcnow())
                    if isinstance(service_config, MarathonServiceConfig
                                  ) and not marathon_message_printed:
                        print_marathon_message(desired_state)
                        marathon_message_printed = True
                    elif isinstance(
                            service_config,
                            ChronosJobConfig) and not chronos_message_printed:
                        print_chronos_message(desired_state)
                        chronos_message_printed = True

                    issue_state_change_for_service(
                        service_config=service_config,
                        force_bounce=force_bounce,
                        desired_state=desired_state,
                    )

    return_val = 0

    if affected_flinkclusters:
        if os.environ.get('ON_PAASTA_MASTER'):
            print_flinkcluster_message(desired_state)
            kube_client = KubeClient()
            for service_config in affected_flinkclusters:
                set_flinkcluster_desired_state(
                    kube_client=kube_client,
                    service=service_config.service,
                    instance=service_config.instance,
                    desired_state=dict(start='running',
                                       stop='stopped')[desired_state],
                )
        else:
            csi = defaultdict(lambda: defaultdict(list))
            for service_config in affected_flinkclusters:
                csi[service_config.cluster][service_config.service].append(
                    service_config.instance)

            system_paasta_config = load_system_paasta_config()
            for cluster, services_instances in csi.items():
                for service, instances in services_instances.items():
                    cmd_parts = [
                        'ON_PAASTA_MASTER=1',
                        'paasta',
                        desired_state,
                        '-c',
                        cluster,
                        '-s',
                        service,
                        '-i',
                        ','.join(instances),
                    ]
                    return_val, _ = run_on_master(
                        cluster=cluster,
                        system_paasta_config=system_paasta_config,
                        cmd_parts=cmd_parts,
                        graceful_exit=True,
                    )

    if invalid_deploy_groups:
        paasta_print("No branches found for %s in %s." %
                     (", ".join(invalid_deploy_groups), remote_refs))
        paasta_print("Has %s been deployed there yet?" % service)
        return_val = 1

    return return_val