~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/devscripts/ec2test/builtins.py

  • Committer: Steve Kowalik
  • Date: 2011-08-07 04:05:52 UTC
  • mto: This revision was merged to the branch mainline in revision 13626.
  • Revision ID: stevenk@ubuntu.com-20110807040552-mwnxo0flmhvl35e8
Correct the notification based on review comments, and remove request{,ed}
from the function names, switching to create{,d}.

Show diffs side-by-side

added added

removed removed

Lines of Context:
6
6
__metaclass__ = type
7
7
__all__ = []
8
8
 
9
 
from datetime import (
10
 
    datetime,
11
 
    timedelta,
12
 
    )
 
9
from datetime import datetime
13
10
import os
14
11
import pdb
15
12
import socket
26
23
    ListOption,
27
24
    Option,
28
25
    )
29
 
from bzrlib.trace import is_verbose
30
26
from bzrlib.transport import get_transport
31
27
from pytz import UTC
32
28
import simplejson
37
33
from devscripts.ec2test.instance import (
38
34
    AVAILABLE_INSTANCE_TYPES,
39
35
    DEFAULT_INSTANCE_TYPE,
40
 
    DEFAULT_REGION,
41
36
    EC2Instance,
42
37
    )
43
38
from devscripts.ec2test.session import EC2SessionName
85
80
          'recent one with an approved owner.'))
86
81
 
87
82
 
 
83
def _convert_instance_type(arg):
 
84
    """Ensure that `arg` is acceptable as an instance type."""
 
85
    if arg not in AVAILABLE_INSTANCE_TYPES:
 
86
        raise BzrCommandError('Unknown instance type %r' % arg)
 
87
    return arg
 
88
 
 
89
 
88
90
instance_type_option = Option(
89
 
    'instance', short_name='i',
90
 
    type=str,
 
91
    'instance', short_name='i', type=_convert_instance_type,
91
92
    param_name='instance_type',
92
93
    help=('The AWS instance type on which to base this run. '
93
94
          'Available options are %r. Defaults to `%s`.' %
128
129
          "and --file."))
129
130
 
130
131
 
131
 
region_option = Option(
132
 
    'region',
133
 
    type=str,
134
 
    help=("Name of the AWS region in which to run the instance.  "
135
 
        "Must be the same as the region holding the image file. "
136
 
        "For example, 'us-west-1'."))
137
 
 
138
 
 
139
132
def filename_type(filename):
140
133
    """An option validator for filenames.
141
134
 
226
219
        trunk_option,
227
220
        machine_id_option,
228
221
        instance_type_option,
229
 
        region_option,
230
222
        Option(
231
223
            'file', short_name='f', type=filename_type,
232
224
            help=('Store abridged test results in FILE.')),
293
285
            noemail=False, submit_pqm_message=None, pqm_public_location=None,
294
286
            pqm_submit_location=None, pqm_email=None, postmortem=False,
295
287
            attached=False, debug=False, open_browser=False,
296
 
            region=None,
297
288
            include_download_cache_changes=False):
298
289
        set_trace_if(debug)
299
290
        if branch is None:
322
313
                "supported")
323
314
 
324
315
        session_name = EC2SessionName.make(EC2TestRunner.name)
325
 
        instance = EC2Instance.make(session_name, instance_type, machine,
326
 
            region=region)
 
316
        instance = EC2Instance.make(session_name, instance_type, machine)
327
317
 
328
318
        runner = EC2TestRunner(
329
319
            test_branch, email=email, file=file,
344
334
 
345
335
    takes_options = [
346
336
        debug_option,
347
 
        instance_type_option,
348
 
        region_option,
349
 
        machine_id_option,
350
337
        Option('dry-run', help="Just print the equivalent ec2 test command."),
351
338
        Option('print-commit', help="Print the full commit message."),
352
339
        Option(
397
384
            instance_type=DEFAULT_INSTANCE_TYPE, postmortem=False,
398
385
            debug=False, commit_text=None, dry_run=False, testfix=False,
399
386
            no_qa=False, incremental=False, rollback=None, print_commit=False,
400
 
            force=False, attached=False,
401
 
            region=DEFAULT_REGION,
402
 
            ):
 
387
            force=False, attached=False):
403
388
        try:
404
389
            from devscripts.autoland import (
405
390
                LaunchpadBranchLander, MissingReviewError, MissingBugsError,
488
473
 
489
474
        session_name = EC2SessionName.make(EC2TestRunner.name)
490
475
        instance = EC2Instance.make(
491
 
            session_name, instance_type, machine, region=region)
 
476
            session_name, instance_type, machine)
492
477
 
493
478
        runner = EC2TestRunner(
494
479
            mp.source_branch, email=emails,
516
501
        postmortem_option,
517
502
        debug_option,
518
503
        include_download_cache_changes_option,
519
 
        region_option,
520
504
        ListOption(
521
505
            'demo', type=str,
522
506
            help="Allow this netmask to connect to the instance."),
585
569
        instance_type_option,
586
570
        postmortem_option,
587
571
        debug_option,
588
 
        region_option,
589
572
        ListOption(
590
573
            'extra-update-image-command', type=str,
591
574
            help=('Run this command (with an ssh agent) on the image before '
602
585
 
603
586
    def run(self, ami_name, machine=None, instance_type='m1.large',
604
587
            debug=False, postmortem=False, extra_update_image_command=None,
605
 
            region=None,
606
588
            public=False):
607
589
        set_trace_if(debug)
608
590
 
616
598
        for variable in ['LANG', 'LC_ALL', 'LC_TIME']:
617
599
            os.environ.pop(variable, None)
618
600
 
 
601
        credentials = EC2Credentials.load_from_file()
 
602
 
619
603
        session_name = EC2SessionName.make(EC2TestRunner.name)
620
604
        instance = EC2Instance.make(
621
605
            session_name, instance_type, machine,
622
 
            region=region)
623
 
        instance.check_bundling_prerequisites(ami_name)
 
606
            credentials=credentials)
 
607
        instance.check_bundling_prerequisites(
 
608
            ami_name, credentials)
624
609
        instance.set_up_and_run(
625
610
            postmortem, True, self.update_image, instance,
626
 
            extra_update_image_command, ami_name, instance._credentials,
627
 
            public)
 
611
            extra_update_image_command, ami_name, credentials, public)
628
612
 
629
613
    def update_image(self, instance, extra_update_image_command, ami_name,
630
614
                     credentials, public):
684
668
    The first in the list is the default image.
685
669
    """
686
670
 
687
 
    takes_options = [
688
 
        region_option,
689
 
        ]
690
 
 
691
 
    def run(self, region=None):
 
671
    def run(self):
 
672
        credentials = EC2Credentials.load_from_file()
692
673
        session_name = EC2SessionName.make(EC2TestRunner.name)
693
 
        credentials = EC2Credentials.load_from_file(region_name=region)
694
674
        account = credentials.connect(session_name)
695
 
        format = "%5s  %-12s  %-12s  %-12s %s\n"
696
 
        self.outf.write(
697
 
            format % ("Rev", "AMI", "Owner ID", "Owner", "Description"))
 
675
        format = "%5s  %-12s  %-12s  %s\n"
 
676
        self.outf.write(format % ("Rev", "AMI", "Owner ID", "Owner"))
698
677
        for revision, images in account.find_images():
699
678
            for image in images:
700
679
                self.outf.write(format % (
701
 
                    revision, image.id, image.ownerId,
702
 
                    VALID_AMI_OWNERS.get(image.ownerId, "unknown"),
703
 
                    image.description or ''))
704
 
 
705
 
 
706
 
class cmd_kill(EC2Command):
707
 
    """Kill one or more running EC2 instances.
708
 
 
709
 
    You can get the instance id from 'ec2 list'.
710
 
    """
711
 
 
712
 
    takes_options = [
713
 
        region_option,
714
 
        ]
715
 
    takes_args = ['instance_id*']
716
 
 
717
 
    def run(self, instance_id_list, region=None):
718
 
        credentials = EC2Credentials.load_from_file(region_name=region)
719
 
        account = credentials.connect('ec2 kill')
720
 
        self.outf.write("killing %d instances: " % len(instance_id_list,))
721
 
        account.conn.terminate_instances(instance_id_list)
722
 
        self.outf.write("done\n")
 
680
                        revision, image.id, image.ownerId,
 
681
                        VALID_AMI_OWNERS.get(image.ownerId, "unknown")))
723
682
 
724
683
 
725
684
class cmd_list(EC2Command):
736
695
    aliases = ["ls"]
737
696
 
738
697
    takes_options = [
739
 
        region_option,
740
698
        Option('show-urls',
741
699
               help="Include more information about each instance"),
742
700
        Option('all', short_name='a',
753
711
        """How long has 'instance' been running?"""
754
712
        expected_format = '%Y-%m-%dT%H:%M:%S.000Z'
755
713
        launch_time = datetime.strptime(instance.launch_time, expected_format)
756
 
        delta = (
 
714
        return (
757
715
            datetime.utcnow().replace(tzinfo=UTC)
758
716
            - launch_time.replace(tzinfo=UTC))
759
 
        return timedelta(delta.days, delta.seconds)  # Round it.
760
717
 
761
718
    def get_http_url(self, instance):
762
719
        hostname = instance.public_dns_name
783
740
        :param data: Launchpad-specific data.
784
741
        :param verbose: Whether we want verbose output.
785
742
        """
786
 
        description = instance.id
787
743
        uptime = self.get_uptime(instance)
788
 
        if instance.state != 'running':
789
 
            current_status = instance.state
 
744
        if data is None:
 
745
            description = instance.id
 
746
            current_status =     'unknown '
790
747
        else:
791
 
            if data is None:
792
 
                current_status = 'unknown '
 
748
            description = data['description']
 
749
            if data['failed-yet']:
 
750
                current_status = '[FAILED]'
793
751
            else:
794
 
                description = data['description']
795
 
                if data['failed-yet']:
796
 
                    current_status = '[FAILED]'
797
 
                else:
798
 
                    current_status = '[OK]    '
799
 
        output = (
800
 
            '%-40s  %-10s (up for %s) %10s'
801
 
            % (description, current_status, uptime, instance.id))
 
752
                current_status = '[OK]    '
 
753
        output = '%s  %s (up for %s)' % (description, current_status, uptime)
802
754
        if verbose:
803
755
            url = self.get_http_url(instance)
804
756
            if url is None:
805
757
                url = "No web service"
806
758
            output += '\n  %s' % (url,)
807
 
            if instance.state_reason:
808
 
                output += (
809
 
                    '\n  transition reason: %s'
810
 
                    % instance.state_reason.get('message', ''))
811
759
        return output
812
760
 
813
761
    def format_summary(self, by_state):
815
763
            ': '.join((state, str(num)))
816
764
            for (state, num) in sorted(list(by_state.items())))
817
765
 
818
 
    def run(self, show_urls=False, all=False, region=None):
 
766
    def run(self, show_urls=False, all=False):
 
767
        credentials = EC2Credentials.load_from_file()
819
768
        session_name = EC2SessionName.make(EC2TestRunner.name)
820
 
        credentials = EC2Credentials.load_from_file(region_name=region)
821
769
        account = credentials.connect(session_name)
822
770
        instances = list(self.iter_instances(account))
823
771
        if len(instances) == 0:
830
778
            data = self.get_ec2test_info(instance)
831
779
            if data is None and not all:
832
780
                continue
833
 
            print self.format_instance(
834
 
                instance, data, verbose=(show_urls or is_verbose()))
 
781
            print self.format_instance(instance, data, show_urls)
835
782
        print 'Summary: %s' % (self.format_summary(by_state),)
836
783
 
837
784