2012-04-29 22:27:49 +00:00
|
|
|
'''
|
|
|
|
Primary interfaces for the salt-cloud system
|
|
|
|
'''
|
2012-05-01 19:15:24 +00:00
|
|
|
# Need to get data from 4 sources!
|
|
|
|
# CLI options
|
|
|
|
# salt cloud config - /etc/salt/cloud
|
|
|
|
# salt master config (for master integration)
|
2012-12-03 22:42:12 +00:00
|
|
|
# salt VM config, where VMs are defined - /etc/salt/cloud.profiles
|
2012-05-01 19:15:24 +00:00
|
|
|
#
|
|
|
|
# The cli, master and cloud configs will merge for opts
|
2012-12-03 22:42:12 +00:00
|
|
|
# the VM data will be in opts['vm']
|
2012-11-15 18:04:23 +00:00
|
|
|
|
2012-04-29 22:27:49 +00:00
|
|
|
# Import python libs
|
2012-05-01 19:15:24 +00:00
|
|
|
import os
|
2013-01-31 00:42:52 +00:00
|
|
|
import logging
|
2012-04-29 22:27:49 +00:00
|
|
|
|
|
|
|
# Import salt libs
|
|
|
|
import saltcloud.config
|
2012-07-31 05:21:09 +00:00
|
|
|
import saltcloud.output
|
2012-05-02 04:21:35 +00:00
|
|
|
import salt.config
|
2012-09-10 01:52:00 +00:00
|
|
|
import salt.output
|
2013-01-31 08:28:45 +00:00
|
|
|
import salt.utils
|
2012-04-29 22:27:49 +00:00
|
|
|
|
2012-11-15 18:04:23 +00:00
|
|
|
# Import saltcloud libs
|
|
|
|
from saltcloud.utils import parsers
|
2012-11-22 15:10:55 +00:00
|
|
|
from saltcloud.libcloudfuncs import libcloud_version
|
2012-04-29 22:27:49 +00:00
|
|
|
|
2012-05-01 19:15:24 +00:00
|
|
|
|
2013-01-31 00:42:52 +00:00
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2012-11-15 18:04:23 +00:00
|
|
|
class SaltCloud(parsers.SaltCloudParser):
|
|
|
|
def run(self):
|
2012-05-01 19:15:24 +00:00
|
|
|
'''
|
2012-11-15 18:04:23 +00:00
|
|
|
Execute the salt-cloud command line
|
2012-05-01 19:15:24 +00:00
|
|
|
'''
|
2012-11-22 15:10:55 +00:00
|
|
|
libcloud_version()
|
|
|
|
|
2012-11-15 18:04:23 +00:00
|
|
|
# Parse shell arguments
|
|
|
|
self.parse_args()
|
2012-09-10 01:52:00 +00:00
|
|
|
|
2012-11-15 18:04:23 +00:00
|
|
|
# Setup log file logging
|
|
|
|
self.setup_logfile_logger()
|
2012-09-10 01:52:00 +00:00
|
|
|
|
2012-11-15 18:04:23 +00:00
|
|
|
# Late imports so logging works as expected
|
2013-01-31 00:42:52 +00:00
|
|
|
log.info('salt-cloud starting')
|
2012-06-26 02:35:26 +00:00
|
|
|
import saltcloud.cloud
|
2012-11-15 18:10:21 +00:00
|
|
|
mapper = saltcloud.cloud.Map(self.config)
|
2012-09-10 01:52:00 +00:00
|
|
|
|
2013-01-23 21:13:28 +00:00
|
|
|
if self.options.update_bootstrap:
|
2013-01-23 16:55:52 +00:00
|
|
|
import urllib
|
2013-02-11 05:47:42 +00:00
|
|
|
url = 'http://bootstrap.saltstack.org'
|
2013-01-23 16:55:52 +00:00
|
|
|
req = urllib.urlopen(url)
|
|
|
|
deploy_path = os.path.join(
|
2013-01-31 08:28:45 +00:00
|
|
|
os.path.dirname(os.path.dirname(__file__)),
|
2013-02-11 05:47:42 +00:00
|
|
|
'saltcloud', 'deploy', 'bootstrap-salt.sh'
|
2013-01-31 08:28:45 +00:00
|
|
|
)
|
2013-02-11 05:47:42 +00:00
|
|
|
print('Updating bootstrap-salt.sh.'
|
2013-01-23 16:55:52 +00:00
|
|
|
'\n\tSource: {0}'
|
|
|
|
'\n\tDestination: {1}'.format(url, deploy_path))
|
2013-01-31 08:28:45 +00:00
|
|
|
with salt.utils.fopen(deploy_path, 'w') as fp_:
|
|
|
|
fp_.write(req.read())
|
2013-01-23 16:55:52 +00:00
|
|
|
|
2012-11-15 18:04:23 +00:00
|
|
|
if self.selected_query_option is not None:
|
2013-02-13 20:34:41 +00:00
|
|
|
if self.config.get('map', None):
|
2013-02-13 22:01:29 +00:00
|
|
|
log.info('Applying map from {0!r}.'.format(self.config['map']))
|
2013-01-16 22:57:17 +00:00
|
|
|
try:
|
|
|
|
query_map = mapper.interpolated_map(
|
|
|
|
query=self.selected_query_option
|
|
|
|
)
|
|
|
|
except Exception as exc:
|
2013-01-31 14:26:51 +00:00
|
|
|
log.debug(
|
|
|
|
'There was an error with a custom map.', exc_info=True
|
|
|
|
)
|
2013-01-31 13:55:46 +00:00
|
|
|
self.error(
|
2013-01-31 08:28:45 +00:00
|
|
|
'There was an error with a custom map: {0}'.format(
|
|
|
|
exc
|
|
|
|
)
|
|
|
|
)
|
2012-10-11 16:27:35 +00:00
|
|
|
else:
|
2013-01-16 22:57:17 +00:00
|
|
|
try:
|
|
|
|
query_map = mapper.map_providers(
|
|
|
|
query=self.selected_query_option
|
|
|
|
)
|
|
|
|
except Exception as exc:
|
2013-01-31 14:26:51 +00:00
|
|
|
log.debug('There was an error with a map.', exc_info=True)
|
2013-01-31 13:55:46 +00:00
|
|
|
self.error(
|
2013-01-31 13:42:38 +00:00
|
|
|
'There was an error with a map: {0}'.format(exc)
|
|
|
|
)
|
2012-11-15 18:10:21 +00:00
|
|
|
salt.output.display_output(query_map, '', self.config)
|
2013-01-31 13:55:46 +00:00
|
|
|
|
2012-09-10 01:52:00 +00:00
|
|
|
|
2012-11-15 18:04:23 +00:00
|
|
|
if self.options.list_locations is not None:
|
2013-01-16 22:57:17 +00:00
|
|
|
try:
|
|
|
|
saltcloud.output.double_layer(
|
|
|
|
mapper.location_list(self.options.list_locations)
|
|
|
|
)
|
|
|
|
except Exception as exc:
|
2013-01-31 14:26:51 +00:00
|
|
|
log.debug(
|
|
|
|
'There was an error listing locations.', exc_info=True
|
|
|
|
)
|
2013-01-31 13:42:38 +00:00
|
|
|
self.error(
|
|
|
|
'There was an error listing locations: {0}'.format(exc)
|
|
|
|
)
|
2012-11-15 18:04:23 +00:00
|
|
|
self.exit(0)
|
|
|
|
|
|
|
|
if self.options.list_images is not None:
|
2013-01-16 22:57:17 +00:00
|
|
|
try:
|
|
|
|
saltcloud.output.double_layer(
|
|
|
|
mapper.image_list(self.options.list_images)
|
|
|
|
)
|
|
|
|
except Exception as exc:
|
2013-01-31 14:26:51 +00:00
|
|
|
log.debug('There was an error listing images.', exc_info=True)
|
2013-01-31 13:42:38 +00:00
|
|
|
self.error(
|
|
|
|
'There was an error listing images: {0}'.format(exc)
|
|
|
|
)
|
2012-11-15 18:04:23 +00:00
|
|
|
self.exit(0)
|
|
|
|
|
|
|
|
if self.options.list_sizes is not None:
|
2013-01-16 22:57:17 +00:00
|
|
|
try:
|
|
|
|
saltcloud.output.double_layer(
|
|
|
|
mapper.size_list(self.options.list_sizes)
|
|
|
|
)
|
|
|
|
except Exception as exc:
|
2013-01-31 14:26:51 +00:00
|
|
|
log.debug('There was an error listing sizes.', exc_info=True)
|
2013-01-31 13:42:38 +00:00
|
|
|
self.error(
|
|
|
|
'There was an error listing sizes: {0}'.format(exc)
|
|
|
|
)
|
2012-11-15 18:04:23 +00:00
|
|
|
self.exit(0)
|
|
|
|
|
|
|
|
if self.options.destroy and (self.config.get('names', None) or
|
2013-02-13 20:34:41 +00:00
|
|
|
self.config.get('map', None)):
|
|
|
|
if self.config.get('map', None):
|
2013-02-13 22:01:29 +00:00
|
|
|
log.info('Applying map from {0!r}.'.format(self.config['map']))
|
2012-10-11 16:45:37 +00:00
|
|
|
names = mapper.delete_map(query='list_nodes')
|
|
|
|
else:
|
2012-11-15 18:04:23 +00:00
|
|
|
names = self.config.get('names', None)
|
2013-01-16 22:57:17 +00:00
|
|
|
|
2013-01-21 22:42:20 +00:00
|
|
|
msg = 'The following virtual machines are set to be destroyed:\n'
|
|
|
|
for name in names:
|
|
|
|
msg += ' {0}\n'.format(name)
|
|
|
|
|
2013-01-16 22:57:17 +00:00
|
|
|
try:
|
2013-01-21 23:29:19 +00:00
|
|
|
if self.print_confirm(msg):
|
|
|
|
mapper.destroy(names)
|
2013-01-16 22:57:17 +00:00
|
|
|
except Exception as exc:
|
2013-01-31 14:26:51 +00:00
|
|
|
log.debug(
|
|
|
|
'There was an error destroying machines.', exc_info=True
|
|
|
|
)
|
2013-01-31 13:42:38 +00:00
|
|
|
self.error(
|
|
|
|
'There was an error destroy machines: {0}'.format(exc)
|
|
|
|
)
|
2012-11-15 18:04:23 +00:00
|
|
|
self.exit(0)
|
|
|
|
|
2012-11-26 19:10:34 +00:00
|
|
|
if self.options.action and (self.config.get('names', None) or
|
2013-02-13 20:34:41 +00:00
|
|
|
self.config.get('map', None)):
|
|
|
|
if self.config.get('map', None):
|
2013-02-13 22:01:29 +00:00
|
|
|
log.info('Applying map from {0!r}.'.format(self.config['map']))
|
2012-11-26 19:10:34 +00:00
|
|
|
names = mapper.delete_map(query='list_nodes')
|
|
|
|
else:
|
|
|
|
names = self.config.get('names', None)
|
2013-01-16 22:57:17 +00:00
|
|
|
|
2013-01-23 21:34:38 +00:00
|
|
|
kwargs = {}
|
|
|
|
machines = []
|
2013-01-31 08:28:45 +00:00
|
|
|
msg = (
|
|
|
|
'The following virtual machines are set to be actioned with '
|
|
|
|
'"{0}":\n'.format(
|
|
|
|
self.options.action
|
|
|
|
)
|
|
|
|
)
|
2013-01-21 23:29:19 +00:00
|
|
|
for name in names:
|
2013-01-23 21:34:38 +00:00
|
|
|
if '=' in name:
|
|
|
|
# This is obviously not a machine name, treat it as a kwarg
|
|
|
|
comps = name.split('=')
|
|
|
|
kwargs[comps[0]] = comps[1]
|
|
|
|
else:
|
|
|
|
msg += ' {0}\n'.format(name)
|
|
|
|
machines.append(name)
|
|
|
|
names = machines
|
2013-01-21 23:29:19 +00:00
|
|
|
|
2013-01-16 22:57:17 +00:00
|
|
|
try:
|
2013-01-21 23:29:19 +00:00
|
|
|
if self.print_confirm(msg):
|
2013-01-23 21:34:38 +00:00
|
|
|
mapper.do_action(names, kwargs)
|
2013-01-16 22:57:17 +00:00
|
|
|
except Exception as exc:
|
2013-01-31 14:26:51 +00:00
|
|
|
log.debug(
|
|
|
|
'There was a error actioning machines.', exc_info=True
|
|
|
|
)
|
2013-01-31 13:42:38 +00:00
|
|
|
self.error(
|
|
|
|
'There was an error actioning machines: {0}'.format(exc)
|
|
|
|
)
|
2012-11-26 19:10:34 +00:00
|
|
|
self.exit(0)
|
|
|
|
|
2012-11-15 18:04:23 +00:00
|
|
|
if self.options.profile and self.config.get('names', False):
|
2013-01-16 22:57:17 +00:00
|
|
|
try:
|
|
|
|
mapper.run_profile()
|
|
|
|
except Exception as exc:
|
2013-01-31 14:26:51 +00:00
|
|
|
log.debug('There was a profile error.', exc_info=True)
|
2013-01-31 13:42:38 +00:00
|
|
|
self.error('There was a profile error: {0}'.format(exc))
|
2012-11-15 18:04:23 +00:00
|
|
|
self.exit(0)
|
|
|
|
|
2013-02-13 20:34:41 +00:00
|
|
|
if self.config.get('map', None) and self.selected_query_option is None:
|
2013-01-17 03:33:46 +00:00
|
|
|
if len(mapper.map) == 0:
|
|
|
|
print('Nothing to do')
|
|
|
|
self.exit(0)
|
2013-01-16 22:57:17 +00:00
|
|
|
try:
|
2013-01-31 13:42:38 +00:00
|
|
|
dmap = mapper.map_data()
|
2013-02-13 22:01:29 +00:00
|
|
|
log.info('Applying map from {0!r}.'.format(self.config['map']))
|
2013-01-21 23:30:39 +00:00
|
|
|
|
|
|
|
msg = 'The following virtual machines are set to be created:\n'
|
|
|
|
for name in dmap['create']:
|
|
|
|
msg += ' {0}\n'.format(name)
|
|
|
|
if 'destroy' in dmap:
|
2013-01-31 08:28:45 +00:00
|
|
|
msg += ('The following virtual machines are set to be '
|
|
|
|
'destroyed:\n')
|
2013-01-21 23:30:39 +00:00
|
|
|
for name in dmap['destroy']:
|
|
|
|
msg += ' {0}\n'.format(name)
|
|
|
|
|
|
|
|
if self.print_confirm(msg):
|
|
|
|
mapper.run_map(dmap)
|
2013-01-16 22:57:17 +00:00
|
|
|
except Exception as exc:
|
2013-01-31 14:26:51 +00:00
|
|
|
log.debug('There was a query error.', exc_info=True)
|
2013-01-31 13:42:38 +00:00
|
|
|
self.error('There was a query error: {0}'.format(exc))
|
2012-11-15 18:04:23 +00:00
|
|
|
self.exit(0)
|
2013-01-21 23:29:19 +00:00
|
|
|
|
|
|
|
def print_confirm(self, msg):
|
2013-01-26 04:25:39 +00:00
|
|
|
if self.options.assume_yes:
|
|
|
|
return True
|
2013-01-21 23:29:19 +00:00
|
|
|
print(msg)
|
2013-01-31 13:42:38 +00:00
|
|
|
res = raw_input('Proceed? [N/y] ')
|
2013-01-21 23:29:19 +00:00
|
|
|
if not res.lower().startswith('y'):
|
|
|
|
return False
|
2013-01-31 13:42:38 +00:00
|
|
|
print('... proceeding')
|
2013-01-21 23:29:19 +00:00
|
|
|
return True
|