示例#1
0
def paasta_rollback(args):
    """Call mark_for_deployment with rollback parameters
    :param args: contains all the arguments passed onto the script: service,
    deploy groups and sha. These arguments will be verified and passed onto
    mark_for_deployment.
    """
    service = figure_out_service_name(args)
    git_url = get_git_url(service)
    commit = args.commit
    given_deploy_groups = [deploy_group for deploy_group in args.deploy_groups.split(",") if deploy_group]

    service_deploy_groups = set(config.get_deploy_group() for config in get_instance_config_for_service(
        soa_dir=DEFAULT_SOA_DIR,
        service=service,
    ))
    deploy_groups, invalid = validate_given_deploy_groups(service_deploy_groups, given_deploy_groups)
    if len(invalid) > 0:
        print PaastaColors.yellow("These deploy groups are not valid and will be skipped: %s.\n" % (",").join(invalid))

    if len(deploy_groups) == 0:
        print PaastaColors.red("ERROR: No valid deploy groups specified for %s.\n" % (service))
        returncode = 1

    for deploy_group in deploy_groups:
        returncode = mark_for_deployment(
            git_url=git_url,
            service=service,
            deploy_group=deploy_group,
            commit=commit,
        )

    sys.exit(returncode)
示例#2
0
文件: info.py 项目: ashwinaj/paasta
def get_service_info(service):
    service_configuration = read_service_configuration(service)
    description = service_configuration.get('description', NO_DESCRIPTION_MESSAGE)
    external_link = service_configuration.get('external_link', NO_EXTERNAL_LINK_MESSAGE)
    pipeline_url = get_pipeline_url(service)
    smartstack_endpoints = get_smartstack_endpoints(service)
    git_url = get_git_url(service)

    output = []
    output.append('Service Name: %s' % service)
    output.append('Description: %s' % description)
    output.append('External Link: %s' % PaastaColors.cyan(external_link))
    output.append('Monitored By: team %s' % get_team(service=service, overrides={}))
    output.append('Runbook: %s' % PaastaColors.cyan(get_runbook(service=service, overrides={})))
    output.append('Git Repo: %s' % git_url)
    output.append('Jenkins Pipeline: %s' % pipeline_url)
    output.append('Deployed to the following clusters:')
    output.extend(get_deployments_strings(service))
    if smartstack_endpoints:
        output.append('Smartstack endpoint(s):')
        for endpoint in smartstack_endpoints:
            output.append(' - %s' % endpoint)
    output.append('Dashboard(s):')
    output.extend(get_dashboard_urls(service))

    return '\n'.join(output)
示例#3
0
def issue_state_change_for_service(service_config, force_bounce, desired_state):
    ref_mutator = make_mutate_refs_func(
        service_config=service_config,
        force_bounce=force_bounce,
        desired_state=desired_state,
    )
    remote_git.create_remote_refs(utils.get_git_url(service_config.get_service()), ref_mutator)
    log_event(
        service_config=service_config,
        desired_state=desired_state,
    )
    if isinstance(service_config, MarathonServiceConfig):
        if desired_state == 'start':
            extra_message = (
                "A 'start' command will signal to Marathon that the service should have the normal "
                "instance count. A restart will cause new tasks to replace the old ones gracefully."
            )
        elif desired_state == 'stop':
            extra_message = (
                "A 'stop' command will signal to Marathon that the service should be in Marathon, "
                "but scaled down to 0 instances gracefully. Use 'paasta start' or make a new deployment to "
                "make the service start back up."
            )
    elif isinstance(service_config, ChronosJobConfig):
        if desired_state == 'start':
            extra_message = (
                "'Start' will tell Chronos to start scheduling the job. "
                "If you need the job to start regardless of the schedule, use 'paasta emergency-start'."
            )
        elif desired_state == 'stop':
            extra_message = (
                "'Stop' for a Chronos job will cause the job to be disabled until the "
                "next deploy or a 'start' command is issued."
            )
    print extra_message
示例#4
0
def paasta_start_or_stop(args, desired_state):
    """Requests a change of state to start or stop given branches of a service."""
    instance = args.instance
    cluster = args.cluster
    soa_dir = args.soa_dir
    service = figure_out_service_name(args=args, soa_dir=soa_dir)

    service_config = get_instance_config(
        service=service,
        cluster=cluster,
        instance=instance,
        soa_dir=soa_dir,
        load_deployments=False,
    )

    remote_refs = remote_git.list_remote_refs(utils.get_git_url(service))

    if 'refs/heads/paasta-%s' % service_config.get_deploy_group() not in remote_refs:
        print "No branches found for %s in %s." % \
            (service_config.get_deploy_group(), remote_refs)
        print "Has it been deployed there yet?"
        sys.exit(1)

    force_bounce = utils.format_timestamp(datetime.datetime.utcnow())
    issue_state_change_for_service(
        service_config=service_config,
        force_bounce=force_bounce,
        desired_state=desired_state,
    )
示例#5
0
def get_branches(service):
    paasta_branches = set(get_branches_for_service(SOA_DIR, service))
    remote_refs = remote_git.list_remote_refs(utils.get_git_url(service))

    for branch in paasta_branches:
        if 'refs/heads/%s' % branch in remote_refs:
            yield branch
示例#6
0
文件: check.py 项目: seco/paasta
def git_repo_check(service):
    git_url = get_git_url(service)
    cmd = 'git ls-remote %s' % git_url
    returncode, _ = _run(cmd, timeout=5)
    if returncode == 0:
        print PaastaCheckMessages.GIT_REPO_FOUND
    else:
        print PaastaCheckMessages.git_repo_missing(git_url)
def get_branches(service, soa_dir):
    paasta_control_branches = set(('paasta-%s' % config.get_branch()
                                   for config in get_instance_config_for_service(soa_dir, service)))
    remote_refs = remote_git.list_remote_refs(utils.get_git_url(service))

    for branch in paasta_control_branches:
        if 'refs/heads/%s' % branch in remote_refs:
            yield branch
示例#8
0
def get_git_repo_for_fab_repo(service):
    """Returns the 'repo' in fab_repo terms. fab_repo just wants the trailing
    section of the git_url, after the colon.
    """
    git_url = get_git_url(service)
    validate_git_url_for_fab_repo(git_url)
    repo = git_url.split(':')[1]
    return repo
示例#9
0
def issue_state_change_for_branches(service, instance, cluster, branches, force_bounce,
                                    desired_state):
    ref_mutator = make_mutate_refs_func(
        branches=branches,
        force_bounce=force_bounce,
        desired_state=desired_state
    )
    remote_git.create_remote_refs(utils.get_git_url(service), ref_mutator)
    log_event(service, instance, cluster, desired_state)
示例#10
0
def test_get_git_url_provided_by_serviceyaml():
    service = 'giiiiiiiiiiit'
    expected = 'git@some_random_host:foobar'
    with (
        mock.patch('service_configuration_lib.read_service_configuration', autospec=True)
    ) as mock_read_service_configuration:
        mock_read_service_configuration.return_value = {'git_url': expected}
        assert utils.get_git_url(service) == expected
        mock_read_service_configuration.assert_called_once_with(service, soa_dir=utils.DEFAULT_SOA_DIR)
示例#11
0
def test_get_git_url_default():
    service = 'giiiiiiiiiiit'
    expected = '[email protected]:services/%s.git' % service
    with (
        mock.patch('service_configuration_lib.read_service_configuration', autospec=True)
    ) as mock_read_service_configuration:
        mock_read_service_configuration.return_value = {}
        assert utils.get_git_url(service) == expected
        mock_read_service_configuration.assert_called_once_with(service, soa_dir=utils.DEFAULT_SOA_DIR)
示例#12
0
文件: rollback.py 项目: j4w3d/paasta
def paasta_rollback(args):
    """Call mark_for_deployment with rollback parameters
    :param args: contains all the arguments passed onto the script: service,
    deploy groups and sha. These arguments will be verified and passed onto
    mark_for_deployment.
    """
    soa_dir = args.soa_dir
    service = figure_out_service_name(args, soa_dir)

    git_url = get_git_url(service, soa_dir)
    given_deploy_groups = {
        deploy_group
        for deploy_group in args.deploy_groups.split(",") if deploy_group
    }

    service_deploy_groups = {
        config.get_deploy_group()
        for config in get_instance_config_for_service(
            service=service,
            soa_dir=soa_dir,
        )
    }
    deploy_groups, invalid = validate_given_deploy_groups(
        service_deploy_groups, given_deploy_groups)

    if len(invalid) > 0:
        print PaastaColors.yellow(
            "These deploy groups are not valid and will be skipped: %s.\n" %
            (",").join(invalid))

    if len(deploy_groups) == 0:
        print PaastaColors.red(
            "ERROR: No valid deploy groups specified for %s.\n" % (service))
        return 1

    commit = args.commit
    if not commit:
        list_previous_commits(service, deploy_groups,
                              bool(given_deploy_groups), soa_dir)
        return 1

    returncode = 0

    for deploy_group in deploy_groups:
        returncode = max(
            mark_for_deployment(
                git_url=git_url,
                service=service,
                deploy_group=deploy_group,
                commit=commit,
            ),
            returncode,
        )

    return returncode
示例#13
0
def paasta_start_or_stop(args, desired_state):
    """Requests a change of state to start or stop given branches of a service."""
    instance = args.instance
    clusters = args.clusters
    soa_dir = args.soa_dir
    service = figure_out_service_name(args=args, soa_dir=soa_dir)

    if args.clusters is not None:
        clusters = args.clusters.split(",")
    else:
        clusters = list_clusters(service)

    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)
        print msg
        return 1

    invalid_deploy_groups = []
    for cluster in clusters:
        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())
            issue_state_change_for_service(
                service_config=service_config,
                force_bounce=force_bounce,
                desired_state=desired_state,
            )

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

    return return_val
示例#14
0
def paasta_start_or_stop(args, desired_state):
    """Requests a change of state to start or stop given branches of a service."""
    instance = args.instance
    clusters = args.clusters
    soa_dir = args.soa_dir
    service = figure_out_service_name(args=args, soa_dir=soa_dir)

    if args.clusters is not None:
        clusters = args.clusters.split(",")
    else:
        clusters = list_clusters(service)

    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)
        print msg
        return 1

    invalid_deploy_groups = []
    for cluster in clusters:
        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())
            issue_state_change_for_service(
                service_config=service_config,
                force_bounce=force_bounce,
                desired_state=desired_state,
            )

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

    return return_val
def get_deploy_group_mappings(soa_dir, service, old_mappings):
    """Gets mappings from service:deploy_group to services-service:paasta-hash,
    where hash is the current SHA at the HEAD of branch_name.
    This is done for all services in soa_dir.

    :param soa_dir: The SOA configuration directory to read from
    :param old_mappings: A dictionary like the return dictionary. Used for fallback if there is a problem with a new
                         mapping.
    :returns: A dictionary mapping service:deploy_group to a dictionary containing:

    - 'docker_image': something like "services-service:paasta-hash". This is relative to the paasta docker
      registry.
    - 'desired_state': either 'start' or 'stop'. Says whether this branch should be running.
    - 'force_bounce': An arbitrary value, which may be None. A change in this value should trigger a bounce, even if
      the other properties of this app have not changed.
    """
    mappings = {}

    service_configs = get_instance_config_for_service(
        soa_dir=soa_dir,
        service=service,
    )

    deploy_group_branch_mappings = dict((config.get_branch(), config.get_deploy_group()) for config in service_configs)
    if not deploy_group_branch_mappings:
        log.info('Service %s has no valid deploy groups. Skipping.', service)
        return {}

    git_url = get_git_url(
        service=service,
        soa_dir=soa_dir,
    )
    remote_refs = remote_git.list_remote_refs(git_url)

    for control_branch, deploy_group in deploy_group_branch_mappings.items():
        deploy_ref_name = 'refs/heads/paasta-%s' % deploy_group
        if deploy_ref_name in remote_refs:
            commit_sha = remote_refs[deploy_ref_name]
            control_branch_alias = '%s:paasta-%s' % (service, control_branch)
            deploy_group_branch_alias = '%s:paasta-%s' % (service, deploy_group)
            docker_image = build_docker_image_name(service, commit_sha)
            log.info('Mapping deploy_group %s to docker image %s', deploy_group_branch_alias, docker_image)
            mapping = mappings.setdefault(control_branch_alias, {})
            mapping['docker_image'] = docker_image

            desired_state, force_bounce = get_desired_state(
                service=service,
                branch=control_branch,
                remote_refs=remote_refs,
                deploy_group=deploy_group,
            )
            mapping['desired_state'] = desired_state
            mapping['force_bounce'] = force_bounce
    return mappings
示例#16
0
def issue_state_change_for_service(service_config, force_bounce, desired_state):
    ref_mutator = make_mutate_refs_func(
        service_config=service_config,
        force_bounce=force_bounce,
        desired_state=desired_state,
    )
    remote_git.create_remote_refs(utils.get_git_url(service_config.get_service()), ref_mutator)
    log_event(
        service_config=service_config,
        desired_state=desired_state,
    )
示例#17
0
def issue_state_change_for_service(service_config, force_bounce, desired_state):
    ref_mutator = make_mutate_refs_func(
        service_config=service_config,
        force_bounce=force_bounce,
        desired_state=desired_state,
    )
    remote_git.create_remote_refs(utils.get_git_url(service_config.get_service()), ref_mutator)
    log_event(
        service_config=service_config,
        desired_state=desired_state,
    )
示例#18
0
def paasta_wait_for_deployment(args):
    """Wrapping wait_for_deployment"""
    if args.verbose:
        log.setLevel(level=logging.DEBUG)
    else:
        log.setLevel(level=logging.INFO)

    service = args.service
    if service and service.startswith('services-'):
        service = service.split('services-', 1)[1]

    if args.git_url is None:
        args.git_url = get_git_url(service=service, soa_dir=args.soa_dir)

    try:
        validate_full_git_sha(args.commit)
    except ArgumentTypeError:
        refs = remote_git.list_remote_refs(args.git_url)
        commits = short_to_full_git_sha(short=args.commit, refs=refs)
        if len(commits) != 1:
            raise ValueError(
                "%s matched %d git shas (with refs pointing at them). Must match exactly 1." %
                (args.commit, len(commits)))
        args.commit = commits[0]

    try:
        validate_service_name(service, soa_dir=args.soa_dir)
        validate_deploy_group(args.deploy_group, service, args.soa_dir)
        validate_git_sha(args.commit, args.git_url,
                         args.deploy_group, service)
    except (GitShaError, DeployGroupError, NoSuchService) as e:
        paasta_print(PaastaColors.red('{}'.format(e)))
        return 1

    try:
        wait_for_deployment(service=service,
                            deploy_group=args.deploy_group,
                            git_sha=args.commit,
                            soa_dir=args.soa_dir,
                            timeout=args.timeout)
        _log(service=service,
             component='deploy',
             line=("Deployment of {} for {} complete".
                   format(args.commit, args.deploy_group)),
             level='event')

    except (KeyboardInterrupt, TimeoutError):
        paasta_print("Waiting for deployment aborted.")
        return 1
    except NoInstancesFound:
        return 1

    return 0
示例#19
0
def paasta_wait_for_deployment(args):
    """Wrapping wait_for_deployment"""
    if args.verbose:
        log.setLevel(level=logging.DEBUG)
    else:
        log.setLevel(level=logging.INFO)

    service = args.service
    if service and service.startswith("services-"):
        service = service.split("services-", 1)[1]

    if args.git_url is None:
        args.git_url = get_git_url(service=service, soa_dir=args.soa_dir)

    args.commit = validate_git_sha(sha=args.commit, git_url=args.git_url)

    version = DeploymentVersion(sha=args.commit,
                                image_version=args.image_version)

    try:
        validate_service_name(service, soa_dir=args.soa_dir)
        validate_deploy_group(args.deploy_group, service, args.soa_dir)
        validate_version_is_latest(version, args.git_url, args.deploy_group,
                                   service)
    except (VersionError, DeployGroupError, NoSuchService) as e:
        print(PaastaColors.red(f"{e}"))
        return 1

    try:
        asyncio.run(
            wait_for_deployment(
                service=service,
                deploy_group=args.deploy_group,
                git_sha=args.commit,
                image_version=args.image_version,
                soa_dir=args.soa_dir,
                timeout=args.timeout,
                polling_interval=args.polling_interval,
                diagnosis_interval=args.diagnosis_interval,
                time_before_first_diagnosis=args.time_before_first_diagnosis,
            ))
        _log(
            service=service,
            component="deploy",
            line=(f"Deployment of {version} for {args.deploy_group} complete"),
            level="event",
        )

    except (KeyboardInterrupt, TimeoutError, NoSuchCluster):
        report_waiting_aborted(service, args.deploy_group)
        return 1

    return 0
示例#20
0
def issue_state_change_for_service(service_config, force_bounce,
                                   desired_state):
    ref_mutator = make_mutate_refs_func(
        service_config=service_config,
        force_bounce=force_bounce,
        desired_state=desired_state,
    )
    git_url = utils.get_git_url(service_config.get_service())
    remote_git.create_remote_refs(git_url, ref_mutator)
    if "yelpcorp.com" in git_url:
        trigger_deploys(service_config.get_service())
    log_event(service_config=service_config, desired_state=desired_state)
示例#21
0
def get_deploy_group_mappings(soa_dir, service, old_mappings):
    """Gets mappings from service:deploy_group to services-service:paasta-hash,
    where hash is the current SHA at the HEAD of branch_name.
    This is done for all services in soa_dir.

    :param soa_dir: The SOA configuration directory to read from
    :param old_mappings: A dictionary like the return dictionary. Used for fallback if there is a problem with a new
                         mapping.
    :returns: A dictionary mapping service:deploy_group to a dictionary containing:

    - 'docker_image': something like "services-service:paasta-hash". This is relative to the paasta docker
      registry.
    - 'desired_state': either 'start' or 'stop'. Says whether this branch should be running.
    - 'force_bounce': An arbitrary value, which may be None. A change in this value should trigger a bounce, even if
      the other properties of this app have not changed.
    """
    mappings = {}

    service_configs = get_instance_config_for_service(
        soa_dir=soa_dir,
        service=service,
    )

    deploy_group_branch_mappings = dict((config.get_branch(), config.get_deploy_group()) for config in service_configs)
    if not deploy_group_branch_mappings:
        log.info('Service %s has no valid deploy groups. Skipping.', service)
        return {}

    git_url = get_git_url(
        service=service,
        soa_dir=soa_dir,
    )
    remote_refs = remote_git.list_remote_refs(git_url)

    for control_branch, deploy_group in deploy_group_branch_mappings.items():
        deploy_ref_name = 'refs/heads/paasta-%s' % deploy_group
        if deploy_ref_name in remote_refs:
            commit_sha = remote_refs[deploy_ref_name]
            control_branch_alias = '%s:paasta-%s' % (service, control_branch)
            deploy_group_branch_alias = '%s:paasta-%s' % (service, deploy_group)
            docker_image = build_docker_image_name(service, commit_sha)
            log.info('Mapping deploy_group %s to docker image %s', deploy_group_branch_alias, docker_image)
            mapping = mappings.setdefault(control_branch_alias, {})
            mapping['docker_image'] = docker_image

            desired_state, force_bounce = get_desired_state(
                branch=control_branch,
                remote_refs=remote_refs,
                deploy_group=deploy_group,
            )
            mapping['desired_state'] = desired_state
            mapping['force_bounce'] = force_bounce
    return mappings
示例#22
0
def paasta_rollback(args):
    """Call mark_for_deployment with rollback parameters
    :param args: contains all the arguments passed onto the script: service,
    deploy groups and sha. These arguments will be verified and passed onto
    mark_for_deployment.
    """
    soa_dir = args.soa_dir
    service = figure_out_service_name(args, soa_dir)

    git_url = get_git_url(service, soa_dir)
    given_deploy_groups = {deploy_group for deploy_group in args.deploy_groups.split(",") if deploy_group}

    all_deploy_groups = list_deploy_groups(service=service, soa_dir=soa_dir)
    deploy_groups, invalid = validate_given_deploy_groups(all_deploy_groups, given_deploy_groups)

    if len(invalid) > 0:
        paasta_print(
            PaastaColors.yellow(
                "These deploy groups are not valid and will be skipped: %s.\n" % (",").join(invalid),
            ),
        )

    if len(deploy_groups) == 0:
        paasta_print(PaastaColors.red("ERROR: No valid deploy groups specified for %s.\n" % (service)))
        return 1

    git_shas = get_git_shas_for_service(service, deploy_groups, soa_dir)
    commit = args.commit
    if not commit:
        paasta_print("Please specify a commit to mark for rollback (-k, --commit).")
        list_previous_commits(service, deploy_groups, bool(given_deploy_groups), git_shas)
        return 1
    elif commit not in git_shas and not args.force:
        paasta_print(PaastaColors.red("This Git SHA has never been deployed before."))
        paasta_print("Please double check it or use --force to skip this verification.\n")
        list_previous_commits(service, deploy_groups, bool(given_deploy_groups), git_shas)
        return 1

    returncode = 0

    for deploy_group in deploy_groups:
        returncode = max(
            mark_for_deployment(
                git_url=git_url,
                service=service,
                deploy_group=deploy_group,
                commit=commit,
            ),
            returncode,
        )

    return returncode
示例#23
0
def paasta_wait_for_deployment(args):
    """Wrapping wait_for_deployment"""
    if args.verbose:
        log.setLevel(level=logging.DEBUG)
    else:
        log.setLevel(level=logging.INFO)

    service = args.service
    if service and service.startswith('services-'):
        service = service.split('services-', 1)[1]

    if args.git_url is None:
        args.git_url = get_git_url(service=service, soa_dir=args.soa_dir)

    args.commit = validate_git_sha(sha=args.commit, git_url=args.git_url)

    try:
        validate_service_name(service, soa_dir=args.soa_dir)
        validate_deploy_group(args.deploy_group, service, args.soa_dir)
        validate_git_sha_is_latest(
            args.commit,
            args.git_url,
            args.deploy_group,
            service,
        )
    except (GitShaError, DeployGroupError, NoSuchService) as e:
        paasta_print(PaastaColors.red(f'{e}'))
        return 1

    try:
        wait_for_deployment(
            service=service,
            deploy_group=args.deploy_group,
            git_sha=args.commit,
            soa_dir=args.soa_dir,
            timeout=args.timeout,
        )
        _log(
            service=service,
            component='deploy',
            line=("Deployment of {} for {} complete".format(
                args.commit, args.deploy_group)),
            level='event',
        )

    except (KeyboardInterrupt, TimeoutError, NoSuchCluster):
        report_waiting_aborted(service, args.deploy_group)
        return 1

    return 0
示例#24
0
def paasta_rollback(args):
    """Call mark_for_deployment with rollback parameters
    :param args: contains all the arguments passed onto the script: service,
    deploy groups and sha. These arguments will be verified and passed onto
    mark_for_deployment.
    """
    soa_dir = args.soa_dir
    service = figure_out_service_name(args, soa_dir)

    git_url = get_git_url(service, soa_dir)
    given_deploy_groups = {deploy_group for deploy_group in args.deploy_groups.split(",") if deploy_group}

    service_deploy_groups = {config.get_deploy_group() for config in get_instance_config_for_service(
        service=service,
        soa_dir=soa_dir,
    )}
    deploy_groups, invalid = validate_given_deploy_groups(service_deploy_groups, given_deploy_groups)

    if len(invalid) > 0:
        print PaastaColors.yellow("These deploy groups are not valid and will be skipped: %s.\n" % (",").join(invalid))

    if len(deploy_groups) == 0:
        print PaastaColors.red("ERROR: No valid deploy groups specified for %s.\n" % (service))
        return 1

    commit = args.commit
    if not commit:
        list_previous_commits(service, deploy_groups, bool(given_deploy_groups), soa_dir)
        return 1

    returncode = 0

    for deploy_group in deploy_groups:
        returncode = max(
            mark_for_deployment(
                git_url=git_url,
                service=service,
                deploy_group=deploy_group,
                commit=commit,
            ),
            returncode,
        )

    return returncode
示例#25
0
def paasta_wait_for_deployment(args):
    """Wrapping wait_for_deployment"""
    if args.verbose:
        log.setLevel(level=logging.DEBUG)
    else:
        log.setLevel(level=logging.INFO)

    service = args.service
    if service and service.startswith('services-'):
        service = service.split('services-', 1)[1]

    if args.git_url is None:
        args.git_url = get_git_url(service=service, soa_dir=args.soa_dir)

    try:
        validate_service_name(service, soa_dir=args.soa_dir)
        validate_deploy_group(args.deploy_group, service, args.soa_dir)
        validate_git_sha(args.commit, args.git_url, args.deploy_group, service)
    except (GitShaError, DeployGroupError, NoSuchService) as e:
        paasta_print(PaastaColors.red('{}'.format(e)))
        return 1

    try:
        wait_for_deployment(
            service=service,
            deploy_group=args.deploy_group,
            git_sha=args.commit,
            soa_dir=args.soa_dir,
            timeout=args.timeout)
        _log(
            service=service,
            component='deploy',
            line=("Deployment of {0} for {1} complete".format(
                args.commit, args.deploy_group)),
            level='event')

    except (KeyboardInterrupt, TimeoutError):
        paasta_print("Waiting for deployment aborted.")
        return 1
    except NoInstancesFound:
        return 1

    return 0
示例#26
0
def paasta_get_latest_deployment(args):
    service = args.service
    deploy_group = args.deploy_group
    soa_dir = args.soa_dir
    validate_service_name(service, soa_dir)

    git_url = get_git_url(
        service=service,
        soa_dir=soa_dir,
    )
    remote_refs = list_remote_refs(git_url)

    _, git_sha = get_latest_deployment_tag(remote_refs, deploy_group)
    if not git_sha:
        print PaastaColors.red("A deployment could not be found for %s in %s" % (deploy_group, service))
        return 1
    else:
        print git_sha
        return 0
示例#27
0
def paasta_wait_for_deployment(args):
    """Wrapping wait_for_deployment"""
    if args.verbose:
        log.setLevel(level=logging.DEBUG)
    else:
        log.setLevel(level=logging.INFO)

    service = args.service
    if service and service.startswith('services-'):
        service = service.split('services-', 1)[1]

    if args.git_url is None:
        args.git_url = get_git_url(service=service, soa_dir=args.soa_dir)

    try:
        validate_service_name(service, soa_dir=args.soa_dir)
        validate_deploy_group(args.deploy_group, service, args.soa_dir)
        validate_git_sha(args.commit, args.git_url,
                         args.deploy_group, service)
    except (GitShaError, DeployGroupError, NoSuchService) as e:
        paasta_print(PaastaColors.red('{}'.format(e)))
        return 1

    try:
        wait_for_deployment(service=service,
                            deploy_group=args.deploy_group,
                            git_sha=args.commit,
                            soa_dir=args.soa_dir,
                            timeout=args.timeout)
        _log(service=service,
             component='deploy',
             line=("Deployment of {0} for {1} complete".
                   format(args.commit, args.deploy_group)),
             level='event')

    except (KeyboardInterrupt, TimeoutError):
        paasta_print("Waiting for deployment aborted.")
        return 1
    except NoInstancesFound:
        return 1

    return 0
示例#28
0
文件: rollback.py 项目: sbcoba/paasta
def paasta_rollback(args):
    """Call mark_for_deployment with rollback parameters
    :param args: contains all the arguments passed onto the script: service,
    cluster, instance and sha. These arguments will be verified and passed onto
    mark_for_deployment.
    """
    service = figure_out_service_name(args)
    cluster = args.cluster
    git_url = get_git_url(service)
    commit = args.commit
    given_instances = args.instances.split(",")

    if cluster in list_clusters(service):
        service_instances = list_all_instances_for_service(service)
        instances, invalid = validate_given_instances(service_instances,
                                                      given_instances)

        if len(invalid) > 0:
            print PaastaColors.yellow(
                "These instances are not valid and will be skipped: %s.\n" %
                (",").join(invalid))

        if len(instances) is 0:
            print PaastaColors.red(
                "ERROR: No valid instances specified for %s.\n" % (service))
            returncode = 1

        for instance in instances:
            returncode = mark_for_deployment(
                git_url=git_url,
                cluster=cluster,
                instance=instance,
                service=service,
                commit=commit,
            )
    else:
        print PaastaColors.red(
            "ERROR: The service %s is not deployed into cluster %s.\n" %
            (service, cluster))
        returncode = 1

    sys.exit(returncode)
示例#29
0
def paasta_get_latest_deployment(args):
    service = args.service
    deploy_group = args.deploy_group
    soa_dir = args.soa_dir
    validate_service_name(service, soa_dir)

    git_url = get_git_url(
        service=service,
        soa_dir=soa_dir,
    )
    remote_refs = list_remote_refs(git_url)

    _, git_sha = get_latest_deployment_tag(remote_refs, deploy_group)
    if not git_sha:
        print PaastaColors.red("A deployment could not be found for %s in %s" %
                               (deploy_group, service))
        return 1
    else:
        print git_sha
        return 0
示例#30
0
def paasta_start_or_stop(args, desired_state):
    """Requests a change of state to start or stop given branches of a service."""
    instance = args.instance
    cluster = args.cluster
    soa_dir = args.soa_dir
    service = figure_out_service_name(args=args, soa_dir=soa_dir)

    service_config = get_instance_config(
        service=service,
        cluster=cluster,
        instance=instance,
        soa_dir=soa_dir,
        load_deployments=False,
    )

    try:
        remote_refs = remote_git.list_remote_refs(utils.get_git_url(service))
    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

    if 'refs/heads/paasta-%s' % service_config.get_deploy_group() not in remote_refs:
        print "No branches found for %s in %s." % \
            (service_config.get_deploy_group(), remote_refs)
        print "Has it been deployed there yet?"
        return 1

    force_bounce = utils.format_timestamp(datetime.datetime.utcnow())
    issue_state_change_for_service(
        service_config=service_config,
        force_bounce=force_bounce,
        desired_state=desired_state,
    )
示例#31
0
def paasta_rollback(args):
    """Call mark_for_deployment with rollback parameters
    :param args: contains all the arguments passed onto the script: service,
    deploy groups and sha. These arguments will be verified and passed onto
    mark_for_deployment.
    """
    service = figure_out_service_name(args)
    git_url = get_git_url(service)
    commit = args.commit
    given_deploy_groups = [
        deploy_group for deploy_group in args.deploy_groups.split(",")
        if deploy_group
    ]

    service_deploy_groups = set(config.get_deploy_group()
                                for config in get_instance_config_for_service(
                                    soa_dir=DEFAULT_SOA_DIR,
                                    service=service,
                                ))
    deploy_groups, invalid = validate_given_deploy_groups(
        service_deploy_groups, given_deploy_groups)
    if len(invalid) > 0:
        print PaastaColors.yellow(
            "These deploy groups are not valid and will be skipped: %s.\n" %
            (",").join(invalid))

    if len(deploy_groups) == 0:
        print PaastaColors.red(
            "ERROR: No valid deploy groups specified for %s.\n" % (service))
        returncode = 1

    for deploy_group in deploy_groups:
        returncode = mark_for_deployment(
            git_url=git_url,
            service=service,
            deploy_group=deploy_group,
            commit=commit,
        )

    sys.exit(returncode)
def get_branch_mappings(soa_dir, service, old_mappings):
    """Gets mappings from service:branch_name to services-service:paasta-hash,
    where hash is the current SHA at the HEAD of branch_name.
    This is done for all services in soa_dir.

    :param soa_dir: The SOA configuration directory to read from
    :param old_mappings: A dictionary like the return dictionary. Used for fallback if there is a problem with a new
                         mapping.
    :returns: A dictionary mapping service:branch_name to a dictionary containing:

    - 'docker_image': something like "services-service:paasta-hash". This is relative to the paasta docker
      registry.
    - 'desired_state': either 'start' or 'stop'. Says whether this branch should be running.
    - 'force_bounce': An arbitrary value, which may be None. A change in this value should trigger a bounce, even if
      the other properties of this app have not changed.
    """
    mappings = {}
    valid_branches = get_branches_for_service(soa_dir, service)
    if not valid_branches:
        log.info("Service %s has no valid branches. Skipping.", service)
        return {}

    git_url = get_git_url(service, soa_dir=soa_dir)
    remote_refs = remote_git.list_remote_refs(git_url)

    for branch in valid_branches:
        ref_name = "refs/heads/%s" % branch
        if ref_name in remote_refs:
            commit_sha = remote_refs[ref_name]
            branch_alias = "%s:%s" % (service, branch)
            docker_image = build_docker_image_name(service, commit_sha)
            log.info("Mapping branch %s to docker image %s", branch_alias, docker_image)
            mapping = mappings.setdefault(branch_alias, {})
            mapping["docker_image"] = docker_image

            desired_state, force_bounce = get_desired_state(service, branch, remote_refs)
            mapping["desired_state"] = desired_state
            mapping["force_bounce"] = force_bounce

    return mappings
示例#33
0
def get_git_shas_for_service(service, deploy_groups, soa_dir):
    """Returns a dictionary of 2-tuples of the form (timestamp, deploy_group) for each deploy sha"""
    if service is None:
        return []
    git_url = get_git_url(service=service, soa_dir=soa_dir)
    all_deploy_groups = list_deploy_groups(service=service, soa_dir=soa_dir)
    deploy_groups, _ = validate_given_deploy_groups(all_deploy_groups, deploy_groups)
    previously_deployed_shas = {}
    for ref, sha in list_remote_refs(git_url).items():
        regex_match = extract_tags(ref)
        try:
            deploy_group = regex_match["deploy_group"]
            tstamp = regex_match["tstamp"]
        except KeyError:
            pass
        else:
            # Now we filter and dedup by picking the most recent sha for a deploy group
            # Note that all strings are greater than ''
            if deploy_group in deploy_groups:
                tstamp_so_far = previously_deployed_shas.get(sha, ("all", ""))[1]
                if tstamp > tstamp_so_far:
                    previously_deployed_shas[sha] = (tstamp, deploy_group)
    return previously_deployed_shas
示例#34
0
def get_git_shas_for_service(service, deploy_groups, soa_dir):
    """Returns a dictionary of 2-tuples of the form (timestamp, deploy_group) for each deploy sha"""
    if service is None:
        return []
    git_url = get_git_url(service=service, soa_dir=soa_dir)
    all_deploy_groups = list_deploy_groups(
        service=service,
        soa_dir=soa_dir,
    )
    deploy_groups, _ = validate_given_deploy_groups(all_deploy_groups, deploy_groups)
    previously_deployed_shas = {}
    for ref, sha in list_remote_refs(git_url).items():
        regex_match = extract_tags(ref)
        try:
            deploy_group = regex_match['deploy_group']
            tstamp = regex_match['tstamp']
        except KeyError:
            pass
        else:
            # note that all strings are greater than ''
            if deploy_group in deploy_groups and tstamp > previously_deployed_shas.get(sha, ''):
                previously_deployed_shas[sha] = (tstamp, deploy_group)
    return previously_deployed_shas.items()
示例#35
0
文件: info.py 项目: ycaihua/paasta
def get_service_info(service, soa_dir):
    service_configuration = read_service_configuration(service, soa_dir)
    description = service_configuration.get('description', NO_DESCRIPTION_MESSAGE)
    external_link = service_configuration.get('external_link', NO_EXTERNAL_LINK_MESSAGE)
    smartstack_endpoints = get_smartstack_endpoints(service, soa_dir)
    git_url = get_git_url(service, soa_dir)

    output = []
    output.append('Service Name: %s' % service)
    output.append('Description: %s' % description)
    output.append('External Link: %s' % PaastaColors.cyan(external_link))
    output.append('Monitored By: team %s' % get_team(service=service, overrides={}))
    output.append('Runbook: %s' % PaastaColors.cyan(get_runbook(service=service, overrides={})))
    output.append('Git Repo: %s' % git_url)
    output.append('Deployed to the following clusters:')
    output.extend(get_deployments_strings(service, soa_dir))
    if smartstack_endpoints:
        output.append('Smartstack endpoint(s):')
        for endpoint in smartstack_endpoints:
            output.append(' - %s' % endpoint)
    output.append('Dashboard(s):')
    output.extend(get_dashboard_urls(service))

    return '\n'.join(output)
示例#36
0
def paasta_rollback(args):
    """Call mark_for_deployment with rollback parameters
    :param args: contains all the arguments passed onto the script: service,
    cluster, instance and sha. These arguments will be verified and passed onto
    mark_for_deployment.
    """
    service = figure_out_service_name(args)
    cluster = args.cluster
    git_url = get_git_url(service)
    commit = args.commit
    given_instances = args.instances.split(",")

    if cluster in list_clusters(service):
        service_instances = list_all_instances_for_service(service)
        instances, invalid = validate_given_instances(service_instances, given_instances)

        if len(invalid) > 0:
            print PaastaColors.yellow("These instances are not valid and will be skipped: %s.\n" % (",").join(invalid))

        if len(instances) is 0:
            print PaastaColors.red("ERROR: No valid instances specified for %s.\n" % (service))
            returncode = 1

        for instance in instances:
            returncode = mark_for_deployment(
                git_url=git_url,
                cluster=cluster,
                instance=instance,
                service=service,
                commit=commit,
            )
    else:
        print PaastaColors.red("ERROR: The service %s is not deployed into cluster %s.\n" % (service, cluster))
        returncode = 1

    sys.exit(returncode)
示例#37
0
def get_git_shas_for_service(service, deploy_groups, soa_dir):
    """Returns a list of 2-tuples of the form (sha, timestamp) for each deploy tag in a service's git
    repository"""
    if service is None:
        return []
    git_url = get_git_url(service=service, soa_dir=soa_dir)
    all_deploy_groups = {config.get_deploy_group() for config in get_instance_config_for_service(
        service=service,
        soa_dir=soa_dir,
    )}
    deploy_groups, _ = validate_given_deploy_groups(all_deploy_groups, deploy_groups)
    previously_deployed_shas = {}
    for ref, sha in list_remote_refs(git_url).items():
        regex_match = extract_tags(ref)
        try:
            deploy_group = regex_match['deploy_group']
            tstamp = regex_match['tstamp']
        except KeyError:
            pass
        else:
            # note that all strings are greater than ''
            if deploy_group in deploy_groups and tstamp > previously_deployed_shas.get(sha, ''):
                previously_deployed_shas[sha] = tstamp
    return previously_deployed_shas.items()
示例#38
0
def paasta_rollback(args):
    """Call mark_for_deployment with rollback parameters
    :param args: contains all the arguments passed onto the script: service,
    deploy groups and sha. These arguments will be verified and passed onto
    mark_for_deployment.
    """
    soa_dir = args.soa_dir
    service = figure_out_service_name(args, soa_dir)

    deploy_info = get_deploy_info(service=service, soa_dir=args.soa_dir)
    deploy_authz_check(deploy_info, service)

    git_url = get_git_url(service, soa_dir)
    given_deploy_groups = {
        deploy_group for deploy_group in args.deploy_groups.split(",") if deploy_group
    }

    all_deploy_groups = list_deploy_groups(service=service, soa_dir=soa_dir)
    deploy_groups, invalid = validate_given_deploy_groups(
        all_deploy_groups, given_deploy_groups
    )

    if len(invalid) > 0:
        print(
            PaastaColors.yellow(
                "These deploy groups are not valid and will be skipped: %s.\n"
                % (",").join(invalid)
            )
        )

    if len(deploy_groups) == 0:
        print(
            PaastaColors.red(
                "ERROR: No valid deploy groups specified for %s.\n" % (service)
            )
        )
        return 1

    git_shas = get_git_shas_for_service(service, deploy_groups, soa_dir)
    commit = args.commit
    if not commit:
        print("Please specify a commit to mark for rollback (-k, --commit).")
        list_previous_commits(
            service, deploy_groups, bool(given_deploy_groups), git_shas
        )
        return 1
    elif commit not in git_shas and not args.force:
        print(PaastaColors.red("This Git SHA has never been deployed before."))
        print("Please double check it or use --force to skip this verification.\n")
        list_previous_commits(
            service, deploy_groups, bool(given_deploy_groups), git_shas
        )
        return 1

    returncode = 0

    for deploy_group in deploy_groups:
        rolled_back_from = get_currently_deployed_sha(service, deploy_group)
        returncode |= mark_for_deployment(
            git_url=git_url, service=service, deploy_group=deploy_group, commit=commit
        )

        # we could also gate this by the return code from m-f-d, but we probably care more about someone wanting to
        # rollback than we care about if the underlying machinery was successfully able to complete the request
        if rolled_back_from != commit:
            audit_action_details = {
                "rolled_back_from": rolled_back_from,
                "rolled_back_to": commit,
                "rollback_type": RollbackTypes.USER_INITIATED_ROLLBACK.value,
                "deploy_group": deploy_group,
            }
            _log_audit(
                action="rollback", action_details=audit_action_details, service=service
            )

    return returncode
def get_deploy_group_mappings(
    soa_dir: str, service: str
) -> Tuple[Dict[str, V1_Mapping], V2_Mappings]:
    """Gets mappings from service:deploy_group to services-service:paasta-hash,
    where hash is the current SHA at the HEAD of branch_name.
    This is done for all services in soa_dir.

    :param soa_dir: The SOA configuration directory to read from
    :returns: A dictionary mapping service:deploy_group to a dictionary
      containing:

    - 'docker_image': something like "services-service:paasta-hash". This is
      relative to the paasta docker registry.
    - 'desired_state': either 'start' or 'stop'. Says whether this branch
      should be running.
    - 'force_bounce': An arbitrary value, which may be None. A change in this
      value should trigger a bounce, even if the other properties of this app
      have not changed.
    """
    mappings: Dict[str, V1_Mapping] = {}
    v2_mappings: V2_Mappings = {"deployments": {}, "controls": {}}
    git_url = get_git_url(service=service, soa_dir=soa_dir)

    # Most of the time of this function is in two parts:
    # 1. getting remote refs from git. (Mostly IO, just waiting for git to get back to us.)
    # 2. loading instance configs. (Mostly CPU, copy.deepcopying yaml over and over again)
    # Let's do these two things in parallel.

    executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)
    remote_refs_future = executor.submit(remote_git.list_remote_refs, git_url)

    service_configs = get_instance_configs_for_service(soa_dir=soa_dir, service=service)

    deploy_group_branch_mappings = {
        config.get_branch(): config.get_deploy_group() for config in service_configs
    }
    if not deploy_group_branch_mappings:
        log.info("Service %s has no valid deploy groups. Skipping.", service)
        return mappings, v2_mappings

    remote_refs = remote_refs_future.result()

    tag_by_deploy_group = {
        dg: get_latest_deployment_tag(remote_refs, dg)
        for dg in set(deploy_group_branch_mappings.values())
    }
    state_by_branch_and_sha = get_desired_state_by_branch_and_sha(remote_refs)

    for control_branch, deploy_group in deploy_group_branch_mappings.items():
        (deploy_ref_name, deploy_ref_sha) = tag_by_deploy_group[deploy_group]
        if deploy_ref_name in remote_refs:
            commit_sha = remote_refs[deploy_ref_name]
            control_branch_alias = f"{service}:paasta-{control_branch}"
            control_branch_alias_v2 = f"{service}:{control_branch}"
            docker_image = build_docker_image_name(service, commit_sha)
            desired_state, force_bounce = state_by_branch_and_sha.get(
                (control_branch, deploy_ref_sha), ("start", None)
            )
            log.info("Mapping %s to docker image %s", control_branch, docker_image)

            v2_mappings["deployments"][deploy_group] = {
                "docker_image": docker_image,
                "git_sha": commit_sha,
            }
            mappings[control_branch_alias] = {
                "docker_image": docker_image,
                "desired_state": desired_state,
                "force_bounce": force_bounce,
            }
            v2_mappings["controls"][control_branch_alias_v2] = {
                "desired_state": desired_state,
                "force_bounce": force_bounce,
            }
    return mappings, v2_mappings
示例#40
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
    service = figure_out_service_name(args=args, soa_dir=soa_dir)

    if args.clusters is not None:
        clusters = args.clusters.split(",")
    else:
        clusters = list_clusters(service)

    if args.instances is not None:
        instances = args.instances.split(",")
    else:
        instances = None

    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)
        print msg
        return 1

    invalid_deploy_groups = []
    marathon_message_printed, chronos_message_printed = False, False
    for cluster in clusters:
        # If they haven't specified what instances to act on, do it for all of them.
        # If they have specified what instances, only iterate over them if they're
        # actually within this cluster.
        if instances is None:
            cluster_instances = list_all_instances_for_service(service, clusters=[cluster], soa_dir=soa_dir)
        else:
            all_cluster_instances = list_all_instances_for_service(service, clusters=[cluster], soa_dir=soa_dir)
            cluster_instances = all_cluster_instances.intersection(set(instances))

        for instance in cluster_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:
        print "No branches found for %s in %s." % \
            (", ".join(invalid_deploy_groups), remote_refs)
        print "Has %s been deployed there yet?" % service
        return_val = 1

    return return_val
示例#41
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
    service = figure_out_service_name(args=args, soa_dir=soa_dir)
    instances = args.instances.split(",") if args.instances else None

    # assert that each of the clusters that the user specifies are 'valid'
    # for the instance list provided; that is, assert that at least one of the instances
    # provided in the -i argument is deployed there.
    # if there are no instances defined in the args, then assert that the service
    # is deployed to that cluster.
    # If args.clusters is falsey, then default to *all* clusters that a service is deployed to,
    # and we figure out which ones are needed for each service later.
    if instances:
        instance_clusters = [list_clusters(service, soa_dir, instance) for instance in args.instances]
        valid_clusters = sorted(list(set([cluster for cluster_list in instance_clusters for cluster in cluster_list])))
    else:
        valid_clusters = list_clusters(service, soa_dir)

    if args.clusters:
        clusters = args.clusters.split(",")
        invalid_clusters = [cluster for cluster in clusters if cluster not in valid_clusters]
        if invalid_clusters:
            print ("Invalid cluster name(s) specified: %s." "Valid options: %s") % (
                " ".join(invalid_clusters),
                " ".join(valid_clusters),
            )
            return 1
    else:
        clusters = valid_clusters

    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)
        print msg
        return 1

    invalid_deploy_groups = []
    marathon_message_printed, chronos_message_printed = False, False
    for cluster in clusters:
        # If they haven't specified what instances to act on, do it for all of them.
        # If they have specified what instances, only iterate over them if they're
        # actually within this cluster.
        if instances is None:
            cluster_instances = list_all_instances_for_service(service, clusters=[cluster], soa_dir=soa_dir)
            print ("no instances specified; restarting all instances for service")
        else:
            all_cluster_instances = list_all_instances_for_service(service, clusters=[cluster], soa_dir=soa_dir)
            cluster_instances = all_cluster_instances.intersection(set(instances))

        for instance in cluster_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:
        print "No branches found for %s in %s." % (", ".join(invalid_deploy_groups), remote_refs)
        print "Has %s been deployed there yet?" % service
        return_val = 1

    return return_val
示例#42
0
def paasta_mark_for_deployment(args):
    """Wrapping mark_for_deployment"""
    if args.verbose:
        log.setLevel(level=logging.DEBUG)
    else:
        log.setLevel(level=logging.INFO)

    service = args.service
    if service and service.startswith('services-'):
        service = service.split('services-', 1)[1]
    validate_service_name(service, soa_dir=args.soa_dir)

    in_use_deploy_groups = list_deploy_groups(
        service=service,
        soa_dir=args.soa_dir,
    )
    _, invalid_deploy_groups = validate_given_deploy_groups(
        in_use_deploy_groups, [args.deploy_group])

    if len(invalid_deploy_groups) == 1:
        paasta_print(
            PaastaColors.red(
                "ERROR: These deploy groups are not currently used anywhere: %s.\n"
                % (",").join(invalid_deploy_groups)))
        paasta_print(
            PaastaColors.red(
                "This isn't technically wrong because you can mark-for-deployment before deploying there"
            ))
        paasta_print(
            PaastaColors.red(
                "but this is probably a typo. Did you mean one of these in-use deploy groups?:"
            ))
        paasta_print(
            PaastaColors.red("   %s" % (",").join(in_use_deploy_groups)))
        paasta_print()
        paasta_print(PaastaColors.red("Continuing regardless..."))

    if args.git_url is None:
        args.git_url = get_git_url(service=service, soa_dir=args.soa_dir)

    old_git_sha = get_currently_deployed_sha(service=service,
                                             deploy_group=args.deploy_group)
    if old_git_sha == args.commit:
        paasta_print(
            "Warning: The sha asked to be deployed already matches what is set to be deployed:"
        )
        paasta_print(old_git_sha)
        paasta_print("Continuing anyway.")

    ret = mark_for_deployment(
        git_url=args.git_url,
        deploy_group=args.deploy_group,
        service=service,
        commit=args.commit,
    )
    if args.block:
        try:
            wait_for_deployment(service=service,
                                deploy_group=args.deploy_group,
                                git_sha=args.commit,
                                soa_dir=args.soa_dir,
                                timeout=args.timeout)
            line = "Deployment of {} for {} complete".format(
                args.commit, args.deploy_group)
            _log(service=service, component='deploy', line=line, level='event')
        except (KeyboardInterrupt, TimeoutError):
            if args.auto_rollback is True:
                if old_git_sha == args.commit:
                    paasta_print(
                        "Error: --auto-rollback was requested, but the previous sha"
                    )
                    paasta_print(
                        "is the same that was requested with --commit. Can't rollback"
                    )
                    paasta_print("automatically.")
                else:
                    paasta_print(
                        "Auto-Rollback requested. Marking the previous sha")
                    paasta_print("(%s) for %s as desired." %
                                 (args.deploy_group, old_git_sha))
                    mark_for_deployment(
                        git_url=args.git_url,
                        deploy_group=args.deploy_group,
                        service=service,
                        commit=old_git_sha,
                    )
            else:
                paasta_print(
                    "Waiting for deployment aborted. PaaSTA will continue to try to deploy this code."
                )
                paasta_print("If you wish to see the status, run:")
                paasta_print()
                paasta_print("    paasta status -s %s -v" % service)
                paasta_print()
            ret = 1
        except NoInstancesFound:
            return 1
    if old_git_sha is not None and old_git_sha != args.commit and not args.auto_rollback:
        paasta_print()
        paasta_print("If you wish to roll back, you can run:")
        paasta_print()
        paasta_print(
            PaastaColors.bold(
                "    paasta rollback --service %s --deploy-group %s --commit %s "
                % (service, args.deploy_group, old_git_sha)))
    return ret
示例#43
0
def paasta_mark_for_deployment(args):
    """Wrapping mark_for_deployment"""
    if args.verbose:
        log.setLevel(level=logging.DEBUG)
    else:
        log.setLevel(level=logging.INFO)

    service = args.service
    if service and service.startswith('services-'):
        service = service.split('services-', 1)[1]
    validate_service_name(service, soa_dir=args.soa_dir)

    in_use_deploy_groups = list_deploy_groups(
        service=service,
        soa_dir=args.soa_dir,
    )
    _, invalid_deploy_groups = validate_given_deploy_groups(in_use_deploy_groups, [args.deploy_group])

    if len(invalid_deploy_groups) == 1:
        paasta_print(PaastaColors.red(
            "ERROR: These deploy groups are not currently used anywhere: %s.\n" % (",").join(invalid_deploy_groups)))
        paasta_print(PaastaColors.red(
            "This isn't technically wrong because you can mark-for-deployment before deploying there"))
        paasta_print(PaastaColors.red("but this is probably a typo. Did you mean one of these in-use deploy groups?:"))
        paasta_print(PaastaColors.red("   %s" % (",").join(in_use_deploy_groups)))
        paasta_print()
        paasta_print(PaastaColors.red("Continuing regardless..."))

    if args.git_url is None:
        args.git_url = get_git_url(service=service, soa_dir=args.soa_dir)

    old_git_sha = get_currently_deployed_sha(service=service, deploy_group=args.deploy_group)
    if old_git_sha == args.commit:
        paasta_print("Warning: The sha asked to be deployed already matches what is set to be deployed:")
        paasta_print(old_git_sha)
        paasta_print("Continuing anyway.")

    ret = mark_for_deployment(
        git_url=args.git_url,
        deploy_group=args.deploy_group,
        service=service,
        commit=args.commit,
    )
    if args.block:
        try:
            wait_for_deployment(service=service,
                                deploy_group=args.deploy_group,
                                git_sha=args.commit,
                                soa_dir=args.soa_dir,
                                timeout=args.timeout)
            line = "Deployment of {0} for {1} complete".format(args.commit, args.deploy_group)
            _log(
                service=service,
                component='deploy',
                line=line,
                level='event'
            )
        except (KeyboardInterrupt, TimeoutError):
            if args.auto_rollback is True:
                if old_git_sha == args.commit:
                    paasta_print("Error: --auto-rollback was requested, but the previous sha")
                    paasta_print("is the same that was requested with --commit. Can't rollback")
                    paasta_print("automatically.")
                else:
                    paasta_print("Auto-Rollback requested. Marking the previous sha")
                    paasta_print("(%s) for %s as desired." % (args.deploy_group, old_git_sha))
                    mark_for_deployment(
                        git_url=args.git_url,
                        deploy_group=args.deploy_group,
                        service=service,
                        commit=old_git_sha,
                    )
            else:
                paasta_print("Waiting for deployment aborted. PaaSTA will continue to try to deploy this code.")
                paasta_print("If you wish to see the status, run:")
                paasta_print()
                paasta_print("    paasta status -s %s -v" % service)
                paasta_print()
            ret = 1
        except NoInstancesFound:
            return 1
    if old_git_sha is not None and old_git_sha != args.commit and not args.auto_rollback:
        paasta_print()
        paasta_print("If you wish to roll back, you can run:")
        paasta_print()
        paasta_print(PaastaColors.bold("    paasta rollback --service %s --deploy-group %s --commit %s " % (
            service, args.deploy_group, old_git_sha))
        )
    return ret
示例#44
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
    service = figure_out_service_name(args=args, soa_dir=soa_dir)
    instances = args.instances.split(",") if args.instances else None

    # assert that each of the clusters that the user specifies are 'valid'
    # for the instance list provided; that is, assert that at least one of the instances
    # provided in the -i argument is deployed there.
    # if there are no instances defined in the args, then assert that the service
    # is deployed to that cluster.
    # If args.clusters is falsey, then default to *all* clusters that a service is deployed to,
    # and we figure out which ones are needed for each service later.
    if instances:
        instance_clusters = [
            list_clusters(service, soa_dir, instance)
            for instance in args.instances
        ]
        valid_clusters = sorted(
            list(
                set([
                    cluster for cluster_list in instance_clusters
                    for cluster in cluster_list
                ])))
    else:
        valid_clusters = list_clusters(service, soa_dir)

    if args.clusters:
        clusters = args.clusters.split(",")
        invalid_clusters = [
            cluster for cluster in clusters if cluster not in valid_clusters
        ]
        if invalid_clusters:
            print("Invalid cluster name(s) specified: %s."
                  "Valid options: %s") % (" ".join(invalid_clusters),
                                          " ".join(valid_clusters))
            return 1
    else:
        clusters = valid_clusters

    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)
        print msg
        return 1

    invalid_deploy_groups = []
    marathon_message_printed, chronos_message_printed = False, False
    for cluster in clusters:
        # If they haven't specified what instances to act on, do it for all of them.
        # If they have specified what instances, only iterate over them if they're
        # actually within this cluster.
        if instances is None:
            cluster_instances = list_all_instances_for_service(
                service, clusters=[cluster], soa_dir=soa_dir)
            print(
                "no instances specified; restarting all instances for service")
        else:
            all_cluster_instances = list_all_instances_for_service(
                service, clusters=[cluster], soa_dir=soa_dir)
            cluster_instances = all_cluster_instances.intersection(
                set(instances))

        for instance in cluster_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:
        print "No branches found for %s in %s." % \
            (", ".join(invalid_deploy_groups), remote_refs)
        print "Has %s been deployed there yet?" % service
        return_val = 1

    return return_val
示例#45
0
def paasta_rollback(args: argparse.Namespace) -> int:
    """Call mark_for_deployment with rollback parameters
    :param args: contains all the arguments passed onto the script: service,
    deploy groups and sha. These arguments will be verified and passed onto
    mark_for_deployment.
    """
    soa_dir = args.soa_dir
    service = figure_out_service_name(args, soa_dir)

    deploy_info = get_deploy_info(service=service, soa_dir=args.soa_dir)
    if not can_user_deploy_service(deploy_info, service):
        return 1

    git_url = get_git_url(service, soa_dir)

    if args.all_deploy_groups:
        given_deploy_groups = list_deploy_groups(service=service,
                                                 soa_dir=soa_dir)
    else:
        given_deploy_groups = {
            deploy_group
            for deploy_group in args.deploy_groups.split(",") if deploy_group
        }

    all_deploy_groups = list_deploy_groups(service=service, soa_dir=soa_dir)
    deploy_groups, invalid = validate_given_deploy_groups(
        all_deploy_groups, given_deploy_groups)

    if len(invalid) > 0:
        print(
            PaastaColors.yellow(
                "These deploy groups are not valid and will be skipped: %s.\n"
                % (",").join(invalid)))

    if len(deploy_groups) == 0 and not args.all_deploy_groups:
        print(
            PaastaColors.red(
                "ERROR: No valid deploy groups specified for %s.\n Use the flag -a to rollback all valid deploy groups for this service"
                % (service)))
        return 1

    versions = get_versions_for_service(service, deploy_groups, soa_dir)
    commit = args.commit
    image_version = args.image_version
    new_version = DeploymentVersion(sha=commit, image_version=image_version)
    if not commit:
        print("Please specify a commit to mark for rollback (-k, --commit).")
        list_previous_versions(service, deploy_groups,
                               bool(given_deploy_groups), versions)
        return 1
    elif new_version not in versions and not args.force:
        print(
            PaastaColors.red(
                f"This version {new_version} has never been deployed before."))
        print(
            "Please double check it or use --force to skip this verification.\n"
        )
        list_previous_versions(service, deploy_groups,
                               bool(given_deploy_groups), versions)
        return 1

    # TODO: Add similar check for when image_version is empty and no-commit redeploys is enforced for requested deploy_group

    returncode = 0

    for deploy_group in deploy_groups:
        rolled_back_from = get_currently_deployed_version(
            service, deploy_group)
        returncode |= mark_for_deployment(
            git_url=git_url,
            service=service,
            deploy_group=deploy_group,
            commit=commit,
            image_version=image_version,
        )

        # we could also gate this by the return code from m-f-d, but we probably care more about someone wanting to
        # rollback than we care about if the underlying machinery was successfully able to complete the request

        if rolled_back_from != new_version:
            audit_action_details = {
                "rolled_back_from": str(rolled_back_from),
                "rolled_back_to": str(new_version),
                "rollback_type": RollbackTypes.USER_INITIATED_ROLLBACK.value,
                "deploy_group": deploy_group,
            }
            _log_audit(action="rollback",
                       action_details=audit_action_details,
                       service=service)

    return returncode
示例#46
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
示例#47
0
def paasta_mark_for_deployment(args):
    """Wrapping mark_for_deployment"""
    if args.verbose:
        log.setLevel(level=logging.DEBUG)
    else:
        log.setLevel(level=logging.INFO)

    service = args.service
    if service and service.startswith('services-'):
        service = service.split('services-', 1)[1]
    validate_service_name(service, soa_dir=args.soa_dir)

    in_use_deploy_groups = list_deploy_groups(
        service=service,
        soa_dir=args.soa_dir,
    )
    _, invalid_deploy_groups = validate_given_deploy_groups(
        in_use_deploy_groups, [args.deploy_group])

    if len(invalid_deploy_groups) == 1:
        print PaastaColors.red(
            "ERROR: These deploy groups are not currently used anywhere: %s.\n"
            % (",").join(invalid_deploy_groups))
        print PaastaColors.red(
            "This isn't technically wrong because you can mark-for-deployment before deploying there"
        )
        print PaastaColors.red(
            "but this is probably a typo. Did you mean one of these in-use deploy groups?:"
        )
        print PaastaColors.red("   %s" % (",").join(in_use_deploy_groups))
        print ""
        print PaastaColors.red("Continuing regardless...")

    if args.git_url is None:
        args.git_url = get_git_url(service=service, soa_dir=args.soa_dir)

    old_git_sha = get_currently_deployed_sha(service=service,
                                             deploy_group=args.deploy_group)
    if old_git_sha == args.commit:
        print "Warning: The sha asked to be deployed already matches what is set to be deployed:"
        print old_git_sha
        print "Continuing anyway."

    ret = mark_for_deployment(
        git_url=args.git_url,
        deploy_group=args.deploy_group,
        service=service,
        commit=args.commit,
    )
    if args.block:
        try:
            print "Waiting for deployment of {0} for '{1}' complete...".format(
                args.commit, args.deploy_group)
            wait_for_deployment(service=service,
                                deploy_group=args.deploy_group,
                                git_sha=args.commit,
                                soa_dir=args.soa_dir,
                                timeout=args.timeout)
            line = "Deployment of {0} for {1} complete".format(
                args.commit, args.deploy_group)
            _log(service=service, component='deploy', line=line, level='event')
        except (KeyboardInterrupt, TimeoutError):
            print "Waiting for deployment aborted. PaaSTA will continue to try to deploy this code."
            print "If you wish to see the status, run:"
            print ""
            print "    paasta status -s %s -v" % service
            print ""
            ret = 1
    if old_git_sha is not None and old_git_sha != args.commit:
        print ""
        print "If you wish to roll back, you can run:"
        print ""
        print PaastaColors.bold(
            "    paasta rollback --service %s --deploy-group %s --commit %s " %
            (service, args.deploy_group, old_git_sha))
    return ret
示例#48
0
def get_remote_refs(service, soa_dir):
    if service not in REMOTE_REFS:
        REMOTE_REFS[service] = remote_git.list_remote_refs(
            utils.get_git_url(service, soa_dir))
    return REMOTE_REFS[service]
示例#49
0
def paasta_mark_for_deployment(args):
    """Wrapping mark_for_deployment"""
    if args.verbose:
        log.setLevel(level=logging.DEBUG)
    else:
        log.setLevel(level=logging.INFO)

    service = args.service
    if service and service.startswith('services-'):
        service = service.split('services-', 1)[1]
    validate_service_name(service, soa_dir=args.soa_dir)

    in_use_deploy_groups = list_deploy_groups(
        service=service,
        soa_dir=args.soa_dir,
    )
    _, invalid_deploy_groups = validate_given_deploy_groups(
        in_use_deploy_groups, [args.deploy_group])

    if len(invalid_deploy_groups) == 1:
        paasta_print(
            PaastaColors.red(
                "ERROR: These deploy groups are not currently used anywhere: %s.\n"
                % (",").join(invalid_deploy_groups), ))
        paasta_print(
            PaastaColors.red(
                "This isn't technically wrong because you can mark-for-deployment before deploying there",
            ))
        paasta_print(
            PaastaColors.red(
                "but this is probably a typo. Did you mean one of these in-use deploy groups?:"
            ))
        paasta_print(
            PaastaColors.red("   %s" % (",").join(in_use_deploy_groups)))
        paasta_print()
        paasta_print(PaastaColors.red("Continuing regardless..."))

    if args.git_url is None:
        args.git_url = get_git_url(service=service, soa_dir=args.soa_dir)

    try:
        validate_full_git_sha(args.commit)
    except ArgumentTypeError:
        refs = remote_git.list_remote_refs(args.git_url)
        commits = short_to_full_git_sha(short=args.commit, refs=refs)
        if len(commits) != 1:
            raise ValueError(
                "%s matched %d git shas (with refs pointing at them). Must match exactly 1."
                % (args.commit, len(commits)), )
        args.commit = commits[0]

    old_git_sha = get_currently_deployed_sha(service=service,
                                             deploy_group=args.deploy_group)
    if old_git_sha == args.commit:
        paasta_print(
            "Warning: The sha asked to be deployed already matches what is set to be deployed:"
        )
        paasta_print(old_git_sha)
        paasta_print("Continuing anyway.")

    if args.verify_image:
        if not is_docker_image_already_in_registry(service, args.soa_dir,
                                                   args.commit):
            raise ValueError(
                'Failed to find image in the registry for the following sha %s'
                % args.commit)

    ret = mark_for_deployment(
        git_url=args.git_url,
        deploy_group=args.deploy_group,
        service=service,
        commit=args.commit,
    )
    if args.block and ret == 0:
        try:
            wait_for_deployment(
                service=service,
                deploy_group=args.deploy_group,
                git_sha=args.commit,
                soa_dir=args.soa_dir,
                timeout=args.timeout,
            )
            line = "Deployment of {} for {} complete".format(
                args.commit, args.deploy_group)
            _log(
                service=service,
                component='deploy',
                line=line,
                level='event',
            )
        except (KeyboardInterrupt, TimeoutError):
            if args.auto_rollback is True:
                if old_git_sha == args.commit:
                    paasta_print(
                        "Error: --auto-rollback was requested, but the previous sha"
                    )
                    paasta_print(
                        "is the same that was requested with --commit. Can't rollback"
                    )
                    paasta_print("automatically.")
                else:
                    paasta_print(
                        "Auto-Rollback requested. Marking the previous sha")
                    paasta_print("(%s) for %s as desired." %
                                 (args.deploy_group, old_git_sha))
                    mark_for_deployment(
                        git_url=args.git_url,
                        deploy_group=args.deploy_group,
                        service=service,
                        commit=old_git_sha,
                    )
            else:
                report_waiting_aborted(service, args.deploy_group)
            ret = 1
        except NoSuchCluster:
            report_waiting_aborted(service, args.deploy_group)
    if old_git_sha is not None and old_git_sha != args.commit and not args.auto_rollback:
        paasta_print()
        paasta_print("If you wish to roll back, you can run:")
        paasta_print()
        paasta_print(
            PaastaColors.bold(
                "    paasta rollback --service %s --deploy-group %s --commit %s "
                % (
                    service,
                    args.deploy_group,
                    old_git_sha,
                )), )
    return ret
示例#50
0
def get_deploy_group_mappings(
    soa_dir: str,
    service: str,
) -> Tuple[Dict[str, V1_Mapping], V2_Mappings]:
    """Gets mappings from service:deploy_group to services-service:paasta-hash,
    where hash is the current SHA at the HEAD of branch_name.
    This is done for all services in soa_dir.

    :param soa_dir: The SOA configuration directory to read from
    :returns: A dictionary mapping service:deploy_group to a dictionary
      containing:

    - 'docker_image': something like "services-service:paasta-hash". This is
      relative to the paasta docker registry.
    - 'desired_state': either 'start' or 'stop'. Says whether this branch
      should be running.
    - 'force_bounce': An arbitrary value, which may be None. A change in this
      value should trigger a bounce, even if the other properties of this app
      have not changed.
    """
    mappings: Dict[str, V1_Mapping] = {}
    v2_mappings: V2_Mappings = {'deployments': {}, 'controls': {}}

    service_configs = get_instance_configs_for_service(
        soa_dir=soa_dir,
        service=service,
    )

    deploy_group_branch_mappings = {
        config.get_branch(): config.get_deploy_group()
        for config in service_configs
    }
    if not deploy_group_branch_mappings:
        log.info('Service %s has no valid deploy groups. Skipping.', service)
        return mappings, v2_mappings

    git_url = get_git_url(
        service=service,
        soa_dir=soa_dir,
    )
    remote_refs = remote_git.list_remote_refs(git_url)

    for control_branch, deploy_group in deploy_group_branch_mappings.items():
        (deploy_ref_name,
         _) = get_latest_deployment_tag(remote_refs, deploy_group)
        if deploy_ref_name in remote_refs:
            commit_sha = remote_refs[deploy_ref_name]
            control_branch_alias = f'{service}:paasta-{control_branch}'
            control_branch_alias_v2 = f'{service}:{control_branch}'
            docker_image = build_docker_image_name(service, commit_sha)
            desired_state, force_bounce = get_desired_state(
                branch=control_branch,
                remote_refs=remote_refs,
                deploy_group=deploy_group,
            )
            log.info('Mapping %s to docker image %s', control_branch,
                     docker_image)

            v2_mappings['deployments'][deploy_group] = {
                'docker_image': docker_image,
                'git_sha': commit_sha,
            }
            mappings[control_branch_alias] = {
                'docker_image': docker_image,
                'desired_state': desired_state,
                'force_bounce': force_bounce,
            }
            v2_mappings['controls'][control_branch_alias_v2] = {
                'desired_state': desired_state,
                'force_bounce': force_bounce,
            }
    return mappings, v2_mappings
示例#51
0
def paasta_mark_for_deployment(args):
    """Wrapping mark_for_deployment"""
    if args.verbose:
        log.setLevel(level=logging.DEBUG)
    else:
        log.setLevel(level=logging.INFO)

    service = args.service
    if service and service.startswith("services-"):
        service = service.split("services-", 1)[1]
    validate_service_name(service, soa_dir=args.soa_dir)

    deploy_group = args.deploy_group
    in_use_deploy_groups = list_deploy_groups(service=service, soa_dir=args.soa_dir)
    _, invalid_deploy_groups = validate_given_deploy_groups(
        in_use_deploy_groups, [deploy_group]
    )

    if len(invalid_deploy_groups) == 1:
        paasta_print(
            PaastaColors.red(
                "ERROR: These deploy groups are not currently used anywhere: %s.\n"
                % (",").join(invalid_deploy_groups)
            )
        )
        paasta_print(
            PaastaColors.red(
                "This isn't technically wrong because you can mark-for-deployment before deploying there"
            )
        )
        paasta_print(
            PaastaColors.red(
                "but this is probably a typo. Did you mean one of these in-use deploy groups?:"
            )
        )
        paasta_print(PaastaColors.red("   %s" % (",").join(in_use_deploy_groups)))
        paasta_print()
        paasta_print(PaastaColors.red("Continuing regardless..."))

    if args.git_url is None:
        args.git_url = get_git_url(service=service, soa_dir=args.soa_dir)

    commit = validate_git_sha(sha=args.commit, git_url=args.git_url)

    old_git_sha = get_currently_deployed_sha(service=service, deploy_group=deploy_group)
    if old_git_sha == commit:
        paasta_print(
            "Warning: The sha asked to be deployed already matches what is set to be deployed:"
        )
        paasta_print(old_git_sha)
        paasta_print("Continuing anyway.")

    if args.verify_image:
        if not is_docker_image_already_in_registry(service, args.soa_dir, commit):
            raise ValueError(
                "Failed to find image in the registry for the following sha %s" % commit
            )

    deploy_info = get_deploy_info(service=service, soa_dir=args.soa_dir)
    deploy_process = MarkForDeploymentProcess(
        service=service,
        deploy_info=deploy_info,
        deploy_group=deploy_group,
        commit=commit,
        old_git_sha=old_git_sha,
        git_url=args.git_url,
        auto_rollback=args.auto_rollback,
        block=args.block,
        soa_dir=args.soa_dir,
        timeout=args.timeout,
        auto_certify_delay=args.auto_certify_delay,
        auto_abandon_delay=args.auto_abandon_delay,
        auto_rollback_delay=args.auto_rollback_delay,
    )
    ret = deploy_process.run()
    return ret
示例#52
0
def paasta_mark_for_deployment(args):
    """Wrapping mark_for_deployment"""
    if args.verbose:
        log.setLevel(level=logging.DEBUG)
    else:
        log.setLevel(level=logging.INFO)

    service = args.service
    if service and service.startswith('services-'):
        service = service.split('services-', 1)[1]
    validate_service_name(service, soa_dir=args.soa_dir)

    deploy_group = args.deploy_group
    in_use_deploy_groups = list_deploy_groups(
        service=service,
        soa_dir=args.soa_dir,
    )
    _, invalid_deploy_groups = validate_given_deploy_groups(
        in_use_deploy_groups, [deploy_group])

    if len(invalid_deploy_groups) == 1:
        paasta_print(
            PaastaColors.red(
                "ERROR: These deploy groups are not currently used anywhere: %s.\n"
                % (",").join(invalid_deploy_groups), ))
        paasta_print(
            PaastaColors.red(
                "This isn't technically wrong because you can mark-for-deployment before deploying there",
            ))
        paasta_print(
            PaastaColors.red(
                "but this is probably a typo. Did you mean one of these in-use deploy groups?:"
            ))
        paasta_print(
            PaastaColors.red("   %s" % (",").join(in_use_deploy_groups)))
        paasta_print()
        paasta_print(PaastaColors.red("Continuing regardless..."))

    if args.git_url is None:
        args.git_url = get_git_url(service=service, soa_dir=args.soa_dir)

    commit = validate_git_sha(sha=args.commit, git_url=args.git_url)

    old_git_sha = get_currently_deployed_sha(service=service,
                                             deploy_group=deploy_group)
    if old_git_sha == commit:
        paasta_print(
            "Warning: The sha asked to be deployed already matches what is set to be deployed:"
        )
        paasta_print(old_git_sha)
        paasta_print("Continuing anyway.")

    if args.verify_image:
        if not is_docker_image_already_in_registry(service, args.soa_dir,
                                                   commit):
            raise ValueError(
                'Failed to find image in the registry for the following sha %s'
                % commit)

    deploy_info = get_deploy_info(service=service, soa_dir=args.soa_dir)
    slack_notifier = SlackDeployNotifier(
        deploy_info=deploy_info,
        service=service,
        deploy_group=deploy_group,
        commit=commit,
        old_commit=old_git_sha,
        git_url=args.git_url,
    )

    ret = mark_for_deployment(
        git_url=args.git_url,
        deploy_group=deploy_group,
        service=service,
        commit=commit,
    )
    slack_notifier.notify_after_mark(ret=ret)

    if args.block and ret == 0:
        try:
            wait_for_deployment(
                service=service,
                deploy_group=deploy_group,
                git_sha=commit,
                soa_dir=args.soa_dir,
                timeout=args.timeout,
            )
            line = f"Deployment of {commit} for {deploy_group} complete"
            _log(
                service=service,
                component='deploy',
                line=line,
                level='event',
            )
            slack_notifier.notify_after_good_deploy()
        except (KeyboardInterrupt, TimeoutError):
            if args.auto_rollback is True:
                if old_git_sha == commit:
                    paasta_print(
                        "Error: --auto-rollback was requested, but the previous sha"
                    )
                    paasta_print(
                        "is the same that was requested with --commit. Can't rollback"
                    )
                    paasta_print("automatically.")
                else:
                    paasta_print(
                        "Auto-Rollback requested. Marking the previous sha")
                    paasta_print(
                        f"({deploy_group}) for {old_git_sha} as desired.")
                    mark_for_deployment(
                        git_url=args.git_url,
                        deploy_group=deploy_group,
                        service=service,
                        commit=old_git_sha,
                    )
                    slack_notifier.notify_after_auto_rollback()
            else:
                report_waiting_aborted(service, deploy_group)
                slack_notifier.notify_after_abort()
            ret = 1
        except NoSuchCluster:
            report_waiting_aborted(service, deploy_group)
            slack_notifier.notify_after_abort()
    if old_git_sha is not None and old_git_sha != commit and not args.auto_rollback:
        paasta_print()
        paasta_print("If you wish to roll back, you can run:")
        paasta_print()
        paasta_print(
            PaastaColors.bold(
                "    paasta rollback --service {} --deploy-group {} --commit {} "
                .format(
                    service,
                    deploy_group,
                    old_git_sha,
                )), )
    return ret