Example #1
0
 def test_instances_from_amis(self, mock_config, **kwargs):
     '''test get instances using ami ids '''
     aws = DiscoAWS(config=mock_config, environment_name=TEST_ENV_NAME)
     instance = create_autospec(boto.ec2.instance.Instance)
     instance.id = "i-123123aa"
     instances = [instance]
     aws.instances = MagicMock(return_value=instances)
     self.assertEqual(aws.instances_from_amis('ami-12345678'), instances)
     aws.instances.assert_called_with(filters={"image_id": 'ami-12345678'}, instance_ids=None)
Example #2
0
 def test_instances_from_amis(self, mock_config, **kwargs):
     '''test get instances using ami ids '''
     aws = DiscoAWS(config=mock_config, environment_name=TEST_ENV_NAME)
     instance = create_autospec(boto.ec2.instance.Instance)
     instance.id = "i-123123aa"
     instances = [instance]
     aws.instances = MagicMock(return_value=instances)
     self.assertEqual(aws.instances_from_amis('ami-12345678'), instances)
     aws.instances.assert_called_with(filters={"image_id": 'ami-12345678'}, instance_ids=None)
Example #3
0
 def test_instances_from_amis_with_group_name(self, mock_config, **kwargs):
     '''test get instances using ami ids in a specified group name'''
     aws = DiscoAWS(config=mock_config, environment_name=TEST_ENV_NAME)
     instance = create_autospec(boto.ec2.instance.Instance)
     instance.id = "i-123123aa"
     instances = [instance]
     aws.instances_from_asgs = MagicMock(return_value=instances)
     aws.instances = MagicMock(return_value=instances)
     self.assertEqual(aws.instances_from_amis('ami-12345678', group_name='test_group'), instances)
     aws.instances_from_asgs.assert_called_with(['test_group'])
Example #4
0
 def test_instances_from_amis_with_group_name(self, mock_config, **kwargs):
     '''test get instances using ami ids in a specified group name'''
     aws = DiscoAWS(config=mock_config, environment_name=TEST_ENV_NAME)
     instance = create_autospec(boto.ec2.instance.Instance)
     instance.id = "i-123123aa"
     instances = [instance]
     aws.instances_from_asgs = MagicMock(return_value=instances)
     aws.instances = MagicMock(return_value=instances)
     self.assertEqual(aws.instances_from_amis('ami-12345678', group_name='test_group'), instances)
     aws.instances_from_asgs.assert_called_with(['test_group'])
Example #5
0
    def test_instances_from_amis_with_launch_date(self, mock_config, **kwargs):
        '''test get instances using ami ids and with date after a specified date time'''
        aws = DiscoAWS(config=mock_config, environment_name=TEST_ENV_NAME)
        now = datetime.utcnow()

        instance1 = create_autospec(boto.ec2.instance.Instance)
        instance1.id = "i-123123aa"
        instance1.launch_time = str(now + timedelta(minutes=10))
        instance2 = create_autospec(boto.ec2.instance.Instance)
        instance2.id = "i-123123ff"
        instance2.launch_time = str(now - timedelta(days=1))
        instances = [instance1, instance2]

        aws.instances = MagicMock(return_value=instances)
        self.assertEqual(aws.instances_from_amis('ami-12345678', launch_time=now),
                         [instance1])
        aws.instances.assert_called_with(filters={"image_id": 'ami-12345678'}, instance_ids=None)
Example #6
0
    def test_instances_from_amis_with_launch_date(self, mock_config, **kwargs):
        '''test get instances using ami ids and with date after a specified date time'''
        aws = DiscoAWS(config=mock_config, environment_name=TEST_ENV_NAME)
        now = datetime.utcnow()

        instance1 = create_autospec(boto.ec2.instance.Instance)
        instance1.id = "i-123123aa"
        instance1.launch_time = str(now + timedelta(minutes=10))
        instance2 = create_autospec(boto.ec2.instance.Instance)
        instance2.id = "i-123123ff"
        instance2.launch_time = str(now - timedelta(days=1))
        instances = [instance1, instance2]

        aws.instances = MagicMock(return_value=instances)
        self.assertEqual(aws.instances_from_amis('ami-12345678', launch_time=now),
                         [instance1])
        aws.instances.assert_called_with(filters={"image_id": 'ami-12345678'}, instance_ids=None)
Example #7
0
def run():
    """Parses command line and dispatches the commands"""
    config = read_config()

    parser = get_parser()
    args = parser.parse_args()
    configure_logging(args.debug)

    environment_name = args.env or config.get("disco_aws",
                                              "default_environment")

    aws = DiscoAWS(config, environment_name=environment_name)
    if args.mode == "provision":
        hostclass_dicts = [{
            "sequence": 1,
            "hostclass": args.hostclass,
            "instance_type": args.instance_type,
            "extra_space": args.extra_space,
            "extra_disk": args.extra_disk,
            "iops": args.iops,
            "smoke_test": "no" if args.no_smoke else "yes",
            "ami": args.ami,
            "min_size": args.min_size,
            "desired_size": args.desired_size,
            "max_size": args.max_size,
            "chaos": "no" if args.no_chaos else None
        }]
        aws.spinup(hostclass_dicts, testing=args.testing)
    elif args.mode == "listhosts":
        instances = aws.instances_from_hostclass(
            args.hostclass) if args.hostclass else aws.instances()
        instances_filtered = [i for i in instances if i.state != u"terminated"]
        instances_sorted = sorted(instances_filtered,
                                  key=lambda i:
                                  (i.state, i.tags.get("hostclass", "-"),
                                   i.tags.get("hostname", "-")))
        instance_to_private_ip = {
            i.id: get_preferred_private_ip(i)
            for i in instances_sorted
        }
        most = args.all or args.most

        if args.ami_age or args.uptime or most:
            bake = DiscoBake(config, aws.connection)
            ami_dict = bake.list_amis_by_instance(instances)
            now = datetime.utcnow()

        for instance in instances_sorted:
            line = u"{0} {1:<30} {2:<15}".format(
                instance.id, instance.tags.get("hostclass", "-"),
                instance.ip_address or instance_to_private_ip[instance.id])
            if args.state or most:
                line += u" {0:<10}".format(instance.state)
            if args.hostname or most:
                line += u" {0:<1}".format(
                    "-" if instance.tags.get("hostname") is None else "y")
            if args.owner or most:
                line += u" {0:<11}".format(instance.tags.get("owner", u"-"))
            if args.instance_type or most:
                line += u" {0:<10}".format(instance.instance_type)
            if args.ami or most:
                line += u" {0:<12}".format(instance.image_id)
            if args.smoke or most:
                line += u" {0:<1}".format(
                    "-" if instance.tags.get("smoketest") is None else "y")
            if args.ami_age or most:
                creation_time = bake.get_ami_creation_time(
                    ami_dict.get(instance.id))
                line += u" {0:<4}".format(
                    DiscoBake.time_diff_in_hours(now, creation_time))
            if args.uptime or most:
                launch_time = dateutil_parser.parse(instance.launch_time)
                now_with_tz = now.replace(
                    tzinfo=launch_time.tzinfo)  # use a timezone-aware `now`
                line += u" {0:<3}".format(
                    DiscoBake.time_diff_in_hours(now_with_tz, launch_time))
            if args.private_ip or args.all:
                line += u" {0:<16}".format(instance_to_private_ip[instance.id])
            if args.availability_zone or args.all:
                line += u" {0:<12}".format(instance.placement)
            if args.productline or args.all:
                productline = instance.tags.get("productline", u"unknown")
                line += u" {0:<15}".format(
                    productline if productline != u"unknown" else u"-")
            print(line)

    elif args.mode == "terminate":
        instances = instances_from_args(aws, args)
        terminated_instances = aws.terminate(instances)
        print("Terminated: {0}".format(",".join(
            [str(inst) for inst in terminated_instances])))
    elif args.mode == "stop":
        instances = instances_from_args(aws, args)
        stopped_instances = aws.stop(instances)
        print("Stopped: {0}".format(",".join(
            [str(inst) for inst in stopped_instances])))
    elif args.mode == "exec":
        instances = instances_from_args(aws, args)
        exit_code = 0
        for instance in instances:
            _code, _stdout = aws.remotecmd(instance, [args.command],
                                           user=args.user,
                                           nothrow=True)
            sys.stdout.write(_stdout)
            exit_code = _code if _code else exit_code
        sys.exit(exit_code)
    elif args.mode == "isready":
        instances = instances_from_args(aws, args)
        if not instances:
            print("No instances found")
        ready_count = 0
        for instance in instances:
            name = "{0} {1}".format(instance.tags.get("hostname"), instance.id)
            print("Checking {0}...".format(name))
            try:
                aws.smoketest_once(instance)
                print("...{0} is ready".format(name))
                ready_count += 1
            except SmokeTestError:
                print("..{0} failed smoke test".format(name))
            except TimeoutError:
                print("...{0} is NOT ready".format(name))
        sys.exit(0 if ready_count == len(instances) else 1)
    elif args.mode == "tag":
        for instance in aws.instances(instance_ids=args.instances):
            instance.remove_tag(args.key)
            if args.value:
                instance.add_tag(args.key, args.value)
    elif args.mode == "spinup":
        with open(args.pipeline_definition_file, "r") as f:
            reader = csv.DictReader(f)
            hostclass_dicts = [line for line in reader]
        aws.spinup(hostclass_dicts,
                   stage=args.stage,
                   no_smoke=args.no_smoke,
                   testing=args.testing)
    elif args.mode == "spindown":
        with open(args.pipeline_definition_file, "r") as f:
            reader = csv.DictReader(f)
            hostclasses = [line["hostclass"] for line in reader]
        aws.spindown(hostclasses)
    elif args.mode == "spindownandup":
        with open(args.pipeline_definition_file, "r") as f:
            reader = csv.DictReader(f)
            hostclass_dicts = [line for line in reader]
            hostclasses = [d["hostclass"] for d in hostclass_dicts]
        aws.spindown(hostclasses)
        aws.spinup(hostclass_dicts)
    elif args.mode == "gethostclassoption":
        try:
            print(aws.hostclass_option(args.hostclass, args.option))
        except NoOptionError:
            print("Hostclass %s doesn't have option %s." %
                  (args.hostclass, args.option))
    elif args.mode == "promoterunning":
        aws.promote_running_instances_to_prod(args.hours * 60 * 60)
Example #8
0
def run():
    """Parses command line and dispatches the commands"""
    config = read_config()

    parser = get_parser()
    args = parser.parse_args()
    configure_logging(args.debug)

    environment_name = args.env or config.get("disco_aws", "default_environment")

    aws = DiscoAWS(config, environment_name=environment_name)
    if args.mode == "provision":
        hostclass_dicts = [{
            "sequence": 1,
            "hostclass": args.hostclass,
            "instance_type": args.instance_type,
            "extra_space": args.extra_space,
            "extra_disk": args.extra_disk,
            "iops": args.iops,
            "smoke_test": "no" if args.no_smoke else "yes",
            "ami": args.ami,
            "min_size": args.min_size,
            "desired_size": args.desired_size,
            "max_size": args.max_size,
            "chaos": "no" if args.no_chaos else None,
            "spotinst": args.spotinst,
            "spotinst_reserve": args.spotinst_reserve
        }]
        aws.spinup(hostclass_dicts, testing=args.testing)
    elif args.mode == "listhosts":
        instances = aws.instances_from_hostclass(args.hostclass) if args.hostclass else aws.instances()
        instances_filtered = [i for i in instances if i.state != u"terminated"]
        instances_sorted = sorted(instances_filtered, key=lambda i: (i.state, i.tags.get("hostclass", "-"),
                                                                     i.tags.get("hostname", "-")))
        instance_to_private_ip = {i.id: get_preferred_private_ip(i) for i in instances_sorted}
        most = args.all or args.most

        if args.ami_age or args.uptime or most:
            bake = DiscoBake(config, aws.connection)
            ami_dict = bake.list_amis_by_instance(instances)
            now = datetime.utcnow()

        for instance in instances_sorted:
            line = u"{0} {1:<30} {2:<15}".format(
                instance.id, instance.tags.get("hostclass", "-"),
                instance.ip_address or instance_to_private_ip[instance.id])
            if args.state or most:
                line += u" {0:<10}".format(instance.state)
            if args.hostname or most:
                line += u" {0:<1}".format("-" if instance.tags.get("hostname") is None else "y")
            if args.owner or most:
                line += u" {0:<11}".format(instance.tags.get("owner", u"-"))
            if args.instance_type or most:
                line += u" {0:<10}".format(instance.instance_type)
            if args.ami or most:
                line += u" {0:<12}".format(instance.image_id)
            if args.smoke or most:
                line += u" {0:<1}".format("-" if instance.tags.get("smoketest") is None else "y")
            if args.ami_age or most:
                creation_time = bake.get_ami_creation_time(ami_dict.get(instance.id))
                line += u" {0:<4}".format(DiscoBake.time_diff_in_hours(now, creation_time))
            if args.uptime or most:
                launch_time = dateutil_parser.parse(instance.launch_time)
                now_with_tz = now.replace(tzinfo=launch_time.tzinfo)  # use a timezone-aware `now`
                line += u" {0:<3}".format(DiscoBake.time_diff_in_hours(now_with_tz, launch_time))
            if args.private_ip or args.all:
                line += u" {0:<16}".format(instance_to_private_ip[instance.id])
            if args.availability_zone or args.all:
                line += u" {0:<12}".format(instance.placement)
            if args.productline or args.all:
                productline = instance.tags.get("productline", u"unknown")
                line += u" {0:<15}".format(productline if productline != u"unknown" else u"-")
            if args.securitygroup or args.all:
                line += u" {0:15}".format(instance.groups[0].name)
            print(line)

    elif args.mode == "terminate":
        instances = instances_from_args(aws, args)
        terminated_instances = aws.terminate(instances)
        print("Terminated: {0}".format(",".join([str(inst) for inst in terminated_instances])))
    elif args.mode == "stop":
        instances = instances_from_args(aws, args)
        stopped_instances = aws.stop(instances)
        print("Stopped: {0}".format(",".join([str(inst) for inst in stopped_instances])))
    elif args.mode == "exec":
        instances = instances_from_args(aws, args)
        exit_code = 0
        for instance in instances:
            _code, _stdout = aws.remotecmd(instance, [args.command], user=args.user, nothrow=True)
            sys.stdout.write(_stdout)
            exit_code = _code if _code else exit_code
        sys.exit(exit_code)
    elif args.mode == "exec-ssm":
        ssm = DiscoSSM(environment_name)
        if args.parameters:
            parsed_parameters = parse_ssm_parameters(args.parameters)
        else:
            parsed_parameters = None
        instances = [instance.id for instance in instances_from_args(aws, args)]
        if ssm.execute(instances, args.document, parameters=parsed_parameters, comment=args.comment):
            sys.exit(0)
        else:
            sys.exit(1)
    elif args.mode == "isready":
        instances = instances_from_args(aws, args)
        if not instances:
            print("No instances found")
        ready_count = 0
        for instance in instances:
            name = "{0} {1}".format(instance.tags.get("hostname"), instance.id)
            print("Checking {0}...".format(name))
            try:
                aws.smoketest_once(instance)
                print("...{0} is ready".format(name))
                ready_count += 1
            except SmokeTestError:
                print("..{0} failed smoke test".format(name))
            except TimeoutError:
                print("...{0} is NOT ready".format(name))
        sys.exit(0 if ready_count == len(instances) else 1)
    elif args.mode == "tag":
        for instance in aws.instances(instance_ids=args.instances):
            instance.remove_tag(args.key)
            if args.value:
                instance.add_tag(args.key, args.value)
    elif args.mode == "spinup":
        hostclass_dicts = read_pipeline_file(args.pipeline_definition_file)
        aws.spinup(hostclass_dicts, stage=args.stage, no_smoke=args.no_smoke, testing=args.testing)
    elif args.mode == "spindown":
        hostclasses = [line["hostclass"] for line in read_pipeline_file(args.pipeline_definition_file)]
        aws.spindown(hostclasses)
    elif args.mode == "spindownandup":
        hostclass_dicts = read_pipeline_file(args.pipeline_definition_file)
        hostclasses = [d["hostclass"] for d in hostclass_dicts]
        aws.spindown(hostclasses)
        aws.spinup(hostclass_dicts)
    elif args.mode == "gethostclassoption":
        try:
            print(aws.hostclass_option(args.hostclass, args.option))
        except NoOptionError:
            print("Hostclass %s doesn't have option %s." % (args.hostclass, args.option))
    elif args.mode == "promoterunning":
        aws.promote_running_instances_to_prod(args.hours * 60 * 60)