summaryrefslogtreecommitdiff
path: root/tests/cloud_tests/platforms/ec2/instance.py
blob: 4ba737abaf6ba8b9e7ce1a17b2873d886ac6e9eb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# This file is part of cloud-init. See LICENSE file for license information.

"""Base EC2 instance."""
import os

import botocore

from ..instances import Instance
from tests.cloud_tests import LOG, util


class EC2Instance(Instance):
    """EC2 backed instance."""

    platform_name = "ec2"
    _ssh_client = None

    def __init__(self, platform, properties, config, features,
                 image_ami, user_data=None):
        """Set up instance.

        @param platform: platform object
        @param properties: dictionary of properties
        @param config: dictionary of configuration values
        @param features: dictionary of supported feature flags
        @param image_ami: AWS AMI ID for image to use
        @param user_data: test user-data to pass to instance
        """
        super(EC2Instance, self).__init__(
            platform, image_ami, properties, config, features)

        self.image_ami = image_ami
        self.instance = None
        self.user_data = user_data
        self.ssh_ip = None
        self.ssh_port = 22
        self.ssh_key_file = os.path.join(
            platform.config['data_dir'], platform.config['private_key'])
        self.ssh_pubkey_file = os.path.join(
            platform.config['data_dir'], platform.config['public_key'])

    def console_log(self):
        """Collect console log from instance.

        The console log is buffered and not always present, therefore
        may return empty string.
        """
        try:
            return self.instance.console_output()['Output'].encode()
        except KeyError:
            return b''

    def destroy(self):
        """Clean up instance."""
        if self.instance:
            LOG.debug('destroying instance %s', self.instance.id)
            self.instance.terminate()
            self.instance.wait_until_terminated()

        self._ssh_close()

        super(EC2Instance, self).destroy()

    def _execute(self, command, stdin=None, env=None):
        """Execute command on instance."""
        env_args = []
        if env:
            env_args = ['env'] + ["%s=%s" for k, v in env.items()]

        return self._ssh(['sudo'] + env_args + list(command), stdin=stdin)

    def start(self, wait=True, wait_for_cloud_init=False):
        """Start instance on EC2 with the platfrom's VPC."""
        if self.instance:
            if self.instance.state['Name'] == 'running':
                return

            LOG.debug('starting instance %s', self.instance.id)
            self.instance.start()
        else:
            LOG.debug('launching instance')

            args = {
                'ImageId': self.image_ami,
                'InstanceType': self.platform.instance_type,
                'KeyName': self.platform.key_name,
                'MaxCount': 1,
                'MinCount': 1,
                'SecurityGroupIds': [self.platform.security_group.id],
                'SubnetId': self.platform.subnet.id,
                'TagSpecifications': [{
                    'ResourceType': 'instance',
                    'Tags': [{
                        'Key': 'Name', 'Value': self.platform.tag
                    }]
                }],
            }

            if self.user_data:
                args['UserData'] = self.user_data

            try:
                instances = self.platform.ec2_resource.create_instances(**args)
            except botocore.exceptions.ClientError as error:
                error_msg = error.response['Error']['Message']
                raise util.PlatformError('start', error_msg)

            self.instance = instances[0]

        LOG.debug('instance id: %s', self.instance.id)
        if wait:
            self.instance.wait_until_running()
            self.instance.reload()
            self.ssh_ip = self.instance.public_ip_address
            self._wait_for_system(wait_for_cloud_init)

    def shutdown(self, wait=True):
        """Shutdown instance."""
        LOG.debug('stopping instance %s', self.instance.id)
        self.instance.stop()

        if wait:
            self.instance.wait_until_stopped()
            self.instance.reload()

# vi: ts=4 expandtab