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 127 128 129 130 131 132
|
# 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:
# OutputBytes comes from platform._decode_console_output_as_bytes
response = self.instance.console_output()
return response['OutputBytes']
except KeyError:
if 'Output' in response:
msg = ("'OutputBytes' did not exist in console_output() but "
"'Output' did: %s..." % response['Output'][0:128])
raise util.PlatformError('console_log', msg)
return ('No Console Output [%s]' % self.instance).encode()
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
|