Break out ec2 create() into smaller functions

This commit is contained in:
Joseph Hall 2014-05-06 11:21:12 -06:00
parent 03cc44cde4
commit f0b1a01126
2 changed files with 177 additions and 190 deletions

View File

@ -1055,49 +1055,21 @@ def _param_from_config(key, data):
return param
def create(vm_=None, call=None):
def request_instance(vm_=None, call=None):
'''
Create a single VM from a data dict
Put together all of the information necessary to request an instance on EC2,
and then fire off the request the instance.
Returns data about the instance
'''
if call:
if call == 'function':
# Technically this function may be called other ways too, but it
# definitely cannot be called with --function.
raise SaltCloudSystemExit(
'You cannot create an instance with -a or -f.'
'The request_instance action must be called with -a or --action.'
)
salt.utils.cloud.fire_event(
'event',
'starting create',
'salt/cloud/{0}/creating'.format(vm_['name']),
{
'name': vm_['name'],
'profile': vm_['profile'],
'provider': vm_['provider'],
},
transport=__opts__['transport']
)
key_filename = config.get_cloud_config_value(
'private_key', vm_, __opts__, search_global=False, default=None
)
if key_filename is not None and not os.path.isfile(key_filename):
raise SaltCloudConfigError(
'The defined key_filename {0!r} does not exist'.format(
key_filename
)
)
# Get SSH Gateway config early to verify the private_key,
# if used, exists or not. We don't want to deploy an instance
# and not be able to access it via the gateway.
ssh_gateway_config = get_ssh_gateway_config(vm_)
location = get_location(vm_)
log.info('Creating Cloud VM {0} in {1}'.format(vm_['name'], location))
usernames = salt.utils.cloud.ssh_usernames(
vm_,
__opts__,
default_users=('ec2-user', 'ubuntu', 'admin', 'bitnami', 'root')
)
location = vm_.get('location', get_location(vm_))
# do we launch a regular vm or a spot instance?
# see http://goo.gl/hYZ13f for more information on EC2 API
@ -1309,25 +1281,6 @@ def create(vm_=None, call=None):
'\'del_all_vols_on_destroy\' should be a boolean value.'
)
tags = config.get_cloud_config_value('tag',
vm_,
__opts__,
{},
search_global=False)
if not isinstance(tags, dict):
raise SaltCloudConfigError(
'\'tag\' should be a dict.'
)
for value in tags.values():
if not isinstance(value, str):
raise SaltCloudConfigError(
'\'tag\' values must be strings. Try quoting the values. '
'e.g. "2013-09-19T20:09:46Z".'
)
tags['Name'] = vm_['name']
salt.utils.cloud.fire_event(
'event',
'requesting instance',
@ -1439,9 +1392,22 @@ def create(vm_=None, call=None):
finally:
raise SaltCloudSystemExit(exc.message)
# Pull the instance ID, valid for both spot and normal instances
instance_id = data[0]['instanceId']
return data
def query_instance(vm_=None, call=None):
'''
Query an instance upon creation from the EC2 API
'''
if call == 'function':
# Technically this function may be called other ways too, but it
# definitely cannot be called with --function.
raise SaltCloudSystemExit(
'The query_instance action must be called with -a or --action.'
)
instance_id = vm_['instance_id']
location = vm_.get('location', get_location(vm_))
salt.utils.cloud.fire_event(
'event',
'querying instance',
@ -1530,29 +1496,34 @@ def create(vm_=None, call=None):
finally:
raise SaltCloudSystemExit(exc.message)
salt.utils.cloud.fire_event(
'event',
'setting tags',
'salt/cloud/{0}/tagging'.format(vm_['name']),
{'tags': tags},
transport=__opts__['transport']
)
return data
set_tags(
vm_['name'], tags,
instance_id=instance_id, call='action', location=location
)
log.info('Created node {0}'.format(vm_['name']))
if ssh_interface(vm_) == 'private_ips':
ip_address = data[0]['instancesSet']['item']['privateIpAddress']
log.info('Salt node data. Private_ip: {0}'.format(ip_address))
else:
ip_address = data[0]['instancesSet']['item']['ipAddress']
log.info('Salt node data. Public_ip: {0}'.format(ip_address))
def wait_for_instance(
vm_=None,
data=None,
ip_address=None,
display_ssh_output=True,
call=None,
):
'''
Wait for an instance upon creation from the EC2 API, to become available
'''
if call == 'function':
# Technically this function may be called other ways too, but it
# definitely cannot be called with --function.
raise SaltCloudSystemExit(
'The wait_for_instance action must be called with -a or --action.'
)
display_ssh_output = config.get_cloud_config_value(
'display_ssh_output', vm_, __opts__, default=True
if vm_ is None:
vm_ = {}
if data is None:
data = {}
ssh_gateway_config = vm_.get(
'ssh_gateway_config', get_ssh_gateway_config(vm_)
)
salt.utils.cloud.fire_event(
@ -1590,13 +1561,13 @@ def create(vm_=None, call=None):
timeout=ssh_connect_timeout,
gateway=ssh_gateway_config
):
for user in usernames:
for user in vm_['usernames']:
if salt.utils.cloud.wait_for_passwd(
host=ip_address,
username=user,
ssh_timeout=config.get_cloud_config_value(
'wait_for_passwd_timeout', vm_, __opts__, default=1 * 60),
key_filename=key_filename,
key_filename=vm_['key_filename'],
display_ssh_output=display_ssh_output,
gateway=ssh_gateway_config
):
@ -1613,119 +1584,135 @@ def create(vm_=None, call=None):
'Failed to connect to remote ssh'
)
ret = {}
ssh_username = config.get_cloud_config_value(
'ssh_username', vm_, __opts__
)
if config.get_cloud_config_value('deploy', vm_, __opts__) is True:
deploy_script = script(vm_)
deploy_kwargs = {
'opts': __opts__,
'host': ip_address,
'username': ssh_username,
'key_filename': key_filename,
'tmp_dir': config.get_cloud_config_value(
'tmp_dir', vm_, __opts__, default='/tmp/.saltcloud'
),
'deploy_command': config.get_cloud_config_value(
'deploy_command', vm_, __opts__,
default='/tmp/.saltcloud/deploy.sh',
),
'tty': config.get_cloud_config_value(
'tty', vm_, __opts__, default=True
),
'script': deploy_script,
'name': vm_['name'],
'sudo': config.get_cloud_config_value(
'sudo', vm_, __opts__, default=(ssh_username != 'root')
),
'sudo_password': config.get_cloud_config_value(
'sudo_password', vm_, __opts__, default=None
),
'start_action': __opts__['start_action'],
'parallel': __opts__['parallel'],
'conf_file': __opts__['conf_file'],
'sock_dir': __opts__['sock_dir'],
'minion_pem': vm_['priv_key'],
'minion_pub': vm_['pub_key'],
'keep_tmp': __opts__['keep_tmp'],
'preseed_minion_keys': vm_.get('preseed_minion_keys', None),
'display_ssh_output': display_ssh_output,
'minion_conf': salt.utils.cloud.minion_config(__opts__, vm_),
'script_args': config.get_cloud_config_value(
'script_args', vm_, __opts__
),
'script_env': config.get_cloud_config_value(
'script_env', vm_, __opts__
)
}
# Deploy salt-master files, if necessary
if config.get_cloud_config_value('make_master', vm_, __opts__) is True:
deploy_kwargs['make_master'] = True
deploy_kwargs['master_pub'] = vm_['master_pub']
deploy_kwargs['master_pem'] = vm_['master_pem']
master_conf = salt.utils.cloud.master_config(__opts__, vm_)
deploy_kwargs['master_conf'] = master_conf
if master_conf.get('syndic_master', None):
deploy_kwargs['make_syndic'] = True
deploy_kwargs['make_minion'] = config.get_cloud_config_value(
'make_minion', vm_, __opts__, default=True
)
# Check for Windows install params
win_installer = config.get_cloud_config_value('win_installer',
vm_,
__opts__)
if win_installer:
deploy_kwargs['win_installer'] = win_installer
minion = salt.utils.cloud.minion_config(__opts__, vm_)
deploy_kwargs['master'] = minion['master']
deploy_kwargs['username'] = config.get_cloud_config_value(
'win_username', vm_, __opts__, default='Administrator'
)
deploy_kwargs['password'] = config.get_cloud_config_value(
'win_password', vm_, __opts__, default=''
)
# Copy ssh_gateway_config into deploy scripts
if ssh_gateway_config:
deploy_kwargs['gateway'] = ssh_gateway_config
# Store what was used to the deploy the VM
event_kwargs = copy.deepcopy(deploy_kwargs)
del event_kwargs['minion_pem']
del event_kwargs['minion_pub']
del event_kwargs['sudo_password']
if 'password' in event_kwargs:
del event_kwargs['password']
if 'gateway' in event_kwargs:
if 'ssh_gateway_password' in event_kwargs['gateway']:
del event_kwargs['gateway']['ssh_gateway_password']
ret['deploy_kwargs'] = event_kwargs
if 'reactor' in vm_ and vm_['reactor'] is True:
salt.utils.cloud.fire_event(
'event',
'executing deploy script',
'salt/cloud/{0}/deploying'.format(vm_['name']),
{'kwargs': event_kwargs},
'ssh is available',
'salt/cloud/{0}/ssh_ready_reactor'.format(vm_['name']),
{'ip_address': ip_address},
transport=__opts__['transport']
)
deployed = False
if win_installer:
deployed = salt.utils.cloud.deploy_windows(**deploy_kwargs)
else:
deployed = salt.utils.cloud.deploy_script(**deploy_kwargs)
if deployed:
log.info('Salt installed on {name}'.format(**vm_))
else:
log.error('Failed to start Salt on Cloud VM {name}'.format(**vm_))
def create(vm_=None, call=None):
'''
Create a single VM from a data dict
'''
if call:
raise SaltCloudSystemExit(
'You cannot create an instance with -a or -f.'
)
salt.utils.cloud.fire_event(
'event',
'starting create',
'salt/cloud/{0}/creating'.format(vm_['name']),
{
'name': vm_['name'],
'profile': vm_['profile'],
'provider': vm_['provider'],
},
transport=__opts__['transport']
)
key_filename = config.get_cloud_config_value(
'private_key', vm_, __opts__, search_global=False, default=None
)
if key_filename is not None and not os.path.isfile(key_filename):
raise SaltCloudConfigError(
'The defined key_filename {0!r} does not exist'.format(
key_filename
)
)
vm_['key_filename'] = key_filename
# Get SSH Gateway config early to verify the private_key,
# if used, exists or not. We don't want to deploy an instance
# and not be able to access it via the gateway.
ssh_gateway_config = get_ssh_gateway_config(vm_)
vm_['ssh_gateway_config'] = ssh_gateway_config
location = get_location(vm_)
vm_['location'] = location
log.info('Creating Cloud VM {0} in {1}'.format(vm_['name'], location))
vm_['usernames'] = salt.utils.cloud.ssh_usernames(
vm_,
__opts__,
default_users=(
'ec2-user', 'ubuntu', 'fedora', 'admin', 'bitnami', 'root'
)
)
# Put together all of the information required to request the instance, and
# then fire off the request for it
data = request_instance(vm_, location)
# Pull the instance ID, valid for both spot and normal instances
instance_id = data[0]['instanceId']
vm_['instance_id'] = instance_id
# Wait for vital information, such as IP addresses, to be available
# for the new instance
data = query_instance(vm_)
# Now that the instance is available, tag it appropriately. Should
# mitigate race conditions with tags
tags = config.get_cloud_config_value('tag',
vm_,
__opts__,
{},
search_global=False)
if not isinstance(tags, dict):
raise SaltCloudConfigError(
'\'tag\' should be a dict.'
)
for value in tags.values():
if not isinstance(value, str):
raise SaltCloudConfigError(
'\'tag\' values must be strings. Try quoting the values. '
'e.g. "2013-09-19T20:09:46Z".'
)
tags['Name'] = vm_['name']
salt.utils.cloud.fire_event(
'event',
'setting tags',
'salt/cloud/{0}/tagging'.format(vm_['name']),
{'tags': tags},
transport=__opts__['transport']
)
set_tags(
vm_['name'], tags,
instance_id=instance_id, call='action', location=location
)
# At this point, the node is created and tagged, and now needs to be
# bootstrapped, once the necessary port is available.
log.info('Created node {0}'.format(vm_['name']))
# Wait for the necessary port to become available to bootstrap
if ssh_interface(vm_) == 'private_ips':
ip_address = data[0]['instancesSet']['item']['privateIpAddress']
log.info('Salt node data. Private_ip: {0}'.format(ip_address))
else:
ip_address = data[0]['instancesSet']['item']['ipAddress']
log.info('Salt node data. Public_ip: {0}'.format(ip_address))
vm_['ssh_host'] = ip_address
display_ssh_output = config.get_cloud_config_value(
'display_ssh_output', vm_, __opts__, default=True
)
wait_for_instance(
vm_, data, ip_address, display_ssh_output
)
# The instance is booted and accessable, let's Salt it!
ret = salt.utils.cloud.bootstrap(vm_, __opts__)
log.info('Created Cloud VM {0[name]!r}'.format(vm_))
log.debug(

View File

@ -293,10 +293,10 @@ def bootstrap(vm_, opts):
ret = {}
deploy_script_code = os_script(vm_)
deploy_script_code = os_script('script', vm_, opts)
ssh_username = salt.config.get_cloud_config_value(
'ssh_username', vm_, __opts__, default='root'
'ssh_username', vm_, opts, default='root'
),
deploy_kwargs = {