def _assign_floating_ips(vm_, conn, kwargs): floating = [] nets = config.get_cloud_config_value('networks', vm_, __opts__, search_global=False) if HAS014: if nets is not None: for net in nets: if 'fixed' in net: kwargs['networks'] = [ OpenStackNetwork(n, None, None, None) for n in net['fixed'] ] elif 'floating' in net: pool = OpenStack_1_1_FloatingIpPool( net['floating'], conn.connection) try: floating.append(pool.create_floating_ip()) except Exception as e: log.debug( 'Cannot allocate IP from floating pool \'%s\'. Checking for unassociated ips.', net['floating']) for idx in pool.list_floating_ips(): if idx.node_id is None: floating.append(idx) break if not floating: raise SaltCloudSystemExit( 'There are no more floating IP addresses ' 'available, please create some more') # otherwise, attempt to obtain list without specifying pool # this is the same as 'nova floating-ip-list' elif ssh_interface(vm_) != 'private_ips': try: # This try/except is here because it appears some # OpenStack providers return a 404 Not Found for the # floating ip pool URL if there are no pools setup pool = OpenStack_1_1_FloatingIpPool('', conn.connection) try: floating.append(pool.create_floating_ip()) except Exception as e: log.debug( 'Cannot allocate IP from the default floating pool. Checking for unassociated ips.' ) for idx in pool.list_floating_ips(): if idx.node_id is None: floating.append(idx) break if not floating: log.warning( 'There are no more floating IP addresses ' 'available, please create some more if necessary') except Exception as e: if str(e).startswith('404'): pass else: raise return floating
def _to_lc_network(self, net): from libcloud.compute.drivers.openstack import OpenStackNetwork return OpenStackNetwork(id=net['id'], name=net['name'], cidr=net.get('cidr', None), extra=net, driver=self)
def create_node(self, image, flavor, name, public_key_file, networks=None, progress=None): create_kwargs = {} if networks: fake_networks = [OpenStackNetwork(n, None, None, self) for n in networks] create_kwargs['networks'] = fake_networks conn = self._get_conn() fake_image = NodeImage(id=image, name=None, driver=conn) fake_flavor = NodeSize(id=flavor, name=None, ram=None, disk=None, bandwidth=None, price=None, driver=conn) if progress: progress.write("Creating node {0} (image: {1}, flavor: {2})...\n" .format(name, image, flavor)) node = conn.create_node(name=name, image=fake_image, size=fake_flavor, ex_files={ "/root/.ssh/authorized_keys": public_key_file.read() }, **create_kwargs) password = node.extra.get("password") if progress: progress.write("Created node {0} (id: {1}, password: {2})\n" .format(name, node.id, password)) return self._wait_for_node_to_become_active_host(conn, node, progress=progress)
def networks(vm_, kwargs=None): conn = get_conn() if kwargs is None: kwargs = {} networks = config.get_cloud_config_value('networks', vm_, __opts__, search_global=False) floating = [] if HAS014: if networks is not None: for net in networks: if 'fixed' in net: kwargs['networks'] = [ OpenStackNetwork(n, None, None, None) for n in net['fixed'] ] elif 'floating' in net: pool = OpenStack_1_1_FloatingIpPool( net['floating'], conn.connection) for idx in pool.list_floating_ips(): if idx.node_id is None: floating.append(idx) if not floating: # Note(pabelanger): We have no available floating IPs. # For now, we raise an exception and exit. # A future enhancement might be to allow salt-cloud # to dynamically allocate new address but that might raise SaltCloudSystemExit( 'Floating pool {0!r} does not have any more ' 'please create some more or use a different ' 'pool.'.format(net['floating'])) # otherwise, attempt to obtain list without specifying pool # this is the same as 'nova floating-ip-list' elif ssh_interface(vm_) != 'private_ips': try: # This try/except is here because it appears some # *cough* Rackspace *cough* # OpenStack providers return a 404 Not Found for the # floating ip pool URL if there are no pools setup pool = OpenStack_1_1_FloatingIpPool('', conn.connection) for idx in pool.list_floating_ips(): if idx.node_id is None: floating.append(idx) if not floating: # Note(pabelanger): We have no available floating IPs. # For now, we raise an exception and exit. # A future enhancement might be to allow salt-cloud to # dynamically allocate new address but that might be # tricky to manage. raise SaltCloudSystemExit( 'There are no more floating IP addresses ' 'available, please create some more') except Exception as e: if not str(e).startswith('404'): raise vm_['floating'] = floating
def _to_lc_network(driver, network, subnet): from libcloud.compute.drivers.openstack import OpenStackNetwork lc_network = OpenStackNetwork(network['id'], network['name'], subnet['cidr'], driver, { "network": network, "subnet": subnet }) return lc_network
def _assign_floating_ips(vm_, conn, kwargs): floating = [] nets = config.get_cloud_config_value( 'networks', vm_, __opts__, search_global=False ) if HAS014: if nets is not None: for net in nets: if 'fixed' in net: kwargs['networks'] = [ OpenStackNetwork(n, None, None, None) for n in net['fixed'] ] elif 'floating' in net: pool = OpenStack_1_1_FloatingIpPool( net['floating'], conn.connection ) for idx in pool.list_floating_ips(): if idx.node_id is None: floating.append(idx) if not floating: try: floating.append(pool.create_floating_ip()) except Exception as e: raise SaltCloudSystemExit( 'Floating pool \'{0}\' does not have any more ' 'please create some more or use a different ' 'pool.'.format(net['floating']) ) # otherwise, attempt to obtain list without specifying pool # this is the same as 'nova floating-ip-list' elif ssh_interface(vm_) != 'private_ips': try: # This try/except is here because it appears some # *cough* Rackspace *cough* # OpenStack providers return a 404 Not Found for the # floating ip pool URL if there are no pools setup pool = OpenStack_1_1_FloatingIpPool( '', conn.connection ) for idx in pool.list_floating_ips(): if idx.node_id is None: floating.append(idx) if not floating: try: floating.append(pool.create_floating_ip()) except Exception as e: raise SaltCloudSystemExit( 'There are no more floating IP addresses ' 'available, please create some more' ) except Exception as e: if str(e).startswith('404'): pass else: raise return floating
def test_list_networks_returns_network_information(self): conn = mock.Mock() api = self._get_api_with_mocked_conn(conn) network1 = OpenStackNetwork(id="abcdef", cidr="192.168.0.0/16", name="awesome network", driver=None) conn.ex_list_networks.return_value = [network1] self.assertEquals([{ 'id': network1.id, 'name': network1.name, 'cidr': network1.cidr }], api.list_networks())
def request_instance(vm_=None, call=None): ''' Put together all of the information necessary to request an instance on Openstack and then fire off the request the instance. Returns data about the instance ''' if call == 'function': # Technically this function may be called other ways too, but it # definitely cannot be called with --function. raise SaltCloudSystemExit( 'The request_instance action must be called with -a or --action.') salt.utils.cloud.check_name(vm_['name'], 'a-zA-Z0-9._-') conn = get_conn() kwargs = {'name': vm_['name']} try: kwargs['image'] = get_image(conn, vm_) except Exception as exc: raise SaltCloudSystemExit('Error creating {0} on OPENSTACK\n\n' 'Could not find image {1}: {2}\n'.format( vm_['name'], vm_['image'], exc)) try: kwargs['size'] = get_size(conn, vm_) except Exception as exc: raise SaltCloudSystemExit('Error creating {0} on OPENSTACK\n\n' 'Could not find size {1}: {2}\n'.format( vm_['name'], vm_['size'], exc)) # Note: This currently requires libcloud trunk avz = config.get_cloud_config_value('availability_zone', vm_, __opts__, default=None, search_global=False) if avz is not None: kwargs['ex_availability_zone'] = avz kwargs['ex_keyname'] = config.get_cloud_config_value('ssh_key_name', vm_, __opts__, search_global=False) security_groups = config.get_cloud_config_value('security_groups', vm_, __opts__, search_global=False) if security_groups is not None: vm_groups = security_groups.split(',') avail_groups = conn.ex_list_security_groups() group_list = [] for vmg in vm_groups: if vmg in [ag.name for ag in avail_groups]: group_list.append(vmg) else: raise SaltCloudNotFound( 'No such security group: \'{0}\''.format(vmg)) kwargs['ex_security_groups'] = [ g for g in avail_groups if g.name in group_list ] networks = config.get_cloud_config_value('networks', vm_, __opts__, search_global=False) floating = [] if HAS014: if networks is not None: for net in networks: if 'fixed' in net: kwargs['networks'] = [ OpenStackNetwork(n, None, None, None) for n in net['fixed'] ] elif 'floating' in net: pool = OpenStack_1_1_FloatingIpPool( net['floating'], conn.connection) for idx in pool.list_floating_ips(): if idx.node_id is None: floating.append(idx) if not floating: # Note(pabelanger): We have no available floating IPs. # For now, we raise an exception and exit. # A future enhancement might be to allow salt-cloud # to dynamically allocate new address but that might raise SaltCloudSystemExit( 'Floating pool {0!r} does not have any more ' 'please create some more or use a different ' 'pool.'.format(net['floating'])) # otherwise, attempt to obtain list without specifying pool # this is the same as 'nova floating-ip-list' elif ssh_interface(vm_) != 'private_ips': try: # This try/except is here because it appears some # *cough* Rackspace *cough* # OpenStack providers return a 404 Not Found for the # floating ip pool URL if there are no pools setup pool = OpenStack_1_1_FloatingIpPool('', conn.connection) for idx in pool.list_floating_ips(): if idx.node_id is None: floating.append(idx) if not floating: # Note(pabelanger): We have no available floating IPs. # For now, we raise an exception and exit. # A future enhancement might be to allow salt-cloud to # dynamically allocate new address but that might be # tricky to manage. raise SaltCloudSystemExit( 'There are no more floating IP addresses ' 'available, please create some more') except Exception as e: if str(e).startswith('404'): pass else: raise vm_['floating'] = floating files = config.get_cloud_config_value('files', vm_, __opts__, search_global=False) if files: kwargs['ex_files'] = {} for src_path in files: with salt.utils.fopen(files[src_path], 'r') as fp_: kwargs['ex_files'][src_path] = fp_.read() userdata_file = config.get_cloud_config_value('userdata_file', vm_, __opts__, search_global=False) if userdata_file is not None: with salt.utils.fopen(userdata_file, 'r') as fp: kwargs['ex_userdata'] = fp.read() salt.utils.cloud.fire_event('event', 'requesting instance', 'salt/cloud/{0}/requesting'.format( vm_['name']), { 'kwargs': { 'name': kwargs['name'], 'image': kwargs['image'].name, 'size': kwargs['size'].name, 'profile': vm_['profile'] } }, transport=__opts__['transport']) default_profile = {} if 'profile' in vm_ and vm_['profile'] is not None: default_profile = {'profile': vm_['profile']} kwargs['ex_metadata'] = config.get_cloud_config_value( 'metadata', vm_, __opts__, default=default_profile, search_global=False) if not isinstance(kwargs['ex_metadata'], dict): raise SaltCloudConfigError('\'metadata\' should be a dict.') try: data = conn.create_node(**kwargs) except Exception as exc: raise SaltCloudSystemExit( 'Error creating {0} on OpenStack\n\n' 'The following exception was thrown by libcloud when trying to ' 'run the initial deployment: {1}\n'.format(vm_['name'], exc)) vm_['password'] = data.extra.get('password', None) return data, vm_
def create(vm_): ''' Create a single VM from a data dict ''' deploy = config.get_cloud_config_value('deploy', vm_, __opts__) key_filename = config.get_cloud_config_value('ssh_key_file', vm_, __opts__, search_global=False, default=None) if key_filename is not None and not os.path.isfile(key_filename): raise SaltCloudConfigError( 'The defined ssh_key_file {0!r} does not exist'.format( key_filename)) if deploy is True and key_filename is None and \ salt.utils.which('sshpass') is None: raise SaltCloudSystemExit( 'Cannot deploy salt in a VM if the \'ssh_key_file\' setting ' 'is not set and \'sshpass\' binary is not present on the ' 'system for the password.') salt.utils.cloud.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['provider'], }, ) log.info('Creating Cloud VM {0}'.format(vm_['name'])) salt.utils.cloud.check_name(vm_['name'], 'a-zA-Z0-9._-') conn = get_conn() kwargs = {'name': vm_['name']} try: kwargs['image'] = get_image(conn, vm_) except Exception as exc: log.error( 'Error creating {0} on OPENSTACK\n\n' 'Could not find image {1}: {2}\n'.format(vm_['name'], vm_['image'], exc), # Show the traceback if the debug logging level is enabled exc_info=log.isEnabledFor(logging.DEBUG)) return False try: kwargs['size'] = get_size(conn, vm_) except Exception as exc: log.error( 'Error creating {0} on OPENSTACK\n\n' 'Could not find size {1}: {2}\n'.format(vm_['name'], vm_['size'], exc), # Show the traceback if the debug logging level is enabled exc_info=log.isEnabledFor(logging.DEBUG)) return False kwargs['ex_keyname'] = config.get_cloud_config_value('ssh_key_name', vm_, __opts__, search_global=False) security_groups = config.get_cloud_config_value('security_groups', vm_, __opts__, search_global=False) if security_groups is not None: vm_groups = security_groups.split(',') avail_groups = conn.ex_list_security_groups() group_list = [] for vmg in vm_groups: if vmg in [ag.name for ag in avail_groups]: group_list.append(vmg) else: raise SaltCloudNotFound( 'No such security group: \'{0}\''.format(vmg)) kwargs['ex_security_groups'] = [ g for g in avail_groups if g.name in group_list ] networks = config.get_cloud_config_value('networks', vm_, __opts__, search_global=False) floating = [] if HAS014 and networks is not None: for net in networks: if 'fixed' in net: kwargs['networks'] = [ OpenStackNetwork(n, None, None, None) for n in net['fixed'] ] elif 'floating' in net: pool = OpenStack_1_1_FloatingIpPool(net['floating'], conn.connection) for idx in pool.list_floating_ips(): if idx.node_id is None: floating.append(idx) if not floating: # Note(pabelanger): We have no available floating IPs. For # now, we raise an execption and exit. A future enhancement # might be to allow salt-cloud to dynamically allociate new # address but that might be tricky to manage. raise SaltCloudSystemExit( "Floating pool '%s' has not more address available, " "please create some more or use a different pool." % net['floating']) userdata_file = config.get_cloud_config_value('userdata_file', vm_, __opts__, search_global=False) if userdata_file is not None: with salt.utils.fopen(userdata_file, 'r') as fp: kwargs['ex_userdata'] = fp.read() salt.utils.cloud.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), { 'kwargs': { 'name': kwargs['name'], 'image': kwargs['image'].name, 'size': kwargs['size'].name } }, ) try: data = conn.create_node(**kwargs) except Exception as exc: log.error( 'Error creating {0} on OPENSTACK\n\n' 'The following exception was thrown by libcloud when trying to ' 'run the initial deployment: {1}\n'.format(vm_['name'], exc), # Show the traceback if the debug logging level is enabled exc_info=log.isEnabledFor(logging.DEBUG)) return False def __query_node_data(vm_, data, floating): try: nodelist = list_nodes() log.debug('Loaded node data for {0}:\n{1}'.format( vm_['name'], pprint.pformat(nodelist[vm_['name']]))) except Exception as err: log.error( 'Failed to get nodes list: {0}'.format(err), # Show the traceback if the debug logging level is enabled exc_info=log.isEnabledFor(logging.DEBUG)) # Trigger a failure in the wait for IP function return False running = nodelist[vm_['name']]['state'] == node_state( NodeState.RUNNING) if not running: # Still not running, trigger another iteration return if rackconnect(vm_) is True: extra = nodelist[vm_['name']].get('extra') rc_status = extra.get('metadata').get( 'rackconnect_automation_status') access_ip = extra.get('access_ip') if rc_status != 'DEPLOYED': log.debug('Waiting for Rackconnect automation to complete') return if managedcloud(vm_) is True: extra = nodelist[vm_['name']].get('extra') mc_status = extra.get('metadata').get( 'rax_service_level_automation') if mc_status != 'Complete': log.debug('Waiting for managed cloud automation to complete') return if floating: try: name = data.name ip = floating[0].ip_address conn.ex_attach_floating_ip_to_node(data, ip) log.info('Attaching floating IP "{0}" to node "{1}"'.format( ip, name)) except Exception as e: # Note(pabelanger): Because we loop, we only want to attach the # floating IP address one. So, expect failures if the IP is # already attached. pass result = [] private = nodelist[vm_['name']]['private_ips'] public = nodelist[vm_['name']]['public_ips'] if private and not public: log.warn('Private IPs returned, but not public... Checking for ' 'misidentified IPs') for private_ip in private: private_ip = preferred_ip(vm_, [private_ip]) if salt.utils.cloud.is_public_ip(private_ip): log.warn('{0} is a public IP'.format(private_ip)) data.public_ips.append(private_ip) log.warn( 'Public IP address was not ready when we last checked. Appending public IP address now.' ) public = data.public_ips else: log.warn('{0} is a private IP'.format(private_ip)) ignore_ip = ignore_cidr(vm_, private_ip) if private_ip not in data.private_ips and not ignore_ip: result.append(private_ip) if rackconnect(vm_) is True: if ssh_interface(vm_) != 'private_ips': data.public_ips = access_ip return data if result: log.debug('result = {0}'.format(result)) data.private_ips = result if ssh_interface(vm_) == 'private_ips': return data if public: data.public_ips = public if ssh_interface(vm_) != 'private_ips': return data try: data = salt.utils.cloud.wait_for_ip( __query_node_data, update_args=(vm_, data, floating), timeout=config.get_cloud_config_value('wait_for_ip_timeout', vm_, __opts__, default=10 * 60), interval=config.get_cloud_config_value('wait_for_ip_interval', vm_, __opts__, default=10), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_['name']) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(exc.message) log.debug('VM is now running') if ssh_interface(vm_) == 'private_ips': ip_address = preferred_ip(vm_, data.private_ips) elif rackconnect(vm_) is True and ssh_interface(vm_) != 'private_ips': ip_address = data.public_ips else: ip_address = preferred_ip(vm_, data.public_ips) log.debug('Using IP address {0}'.format(ip_address)) if not ip_address: raise SaltCloudSystemExit('A valid IP address was not found') ssh_username = config.get_cloud_config_value('ssh_username', vm_, __opts__, default='root') deploy_kwargs = { 'host': ip_address, 'name': vm_['name'], 'sock_dir': __opts__['sock_dir'], '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', ), 'start_action': __opts__['start_action'], 'parallel': __opts__['parallel'], 'minion_pem': vm_['priv_key'], 'minion_pub': vm_['pub_key'], 'keep_tmp': __opts__['keep_tmp'], 'preseed_minion_keys': vm_.get('preseed_minion_keys', None), '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), 'tty': config.get_cloud_config_value('tty', vm_, __opts__, default=False), 'display_ssh_output': config.get_cloud_config_value('display_ssh_output', vm_, __opts__, default=True), 'script_args': config.get_cloud_config_value('script_args', vm_, __opts__), 'script_env': config.get_cloud_config_value('script_env', vm_, __opts__), 'minion_conf': salt.utils.cloud.minion_config(__opts__, vm_) } if ssh_username != 'root': deploy_kwargs['username'] = ssh_username deploy_kwargs['tty'] = True log.debug('Using {0} as SSH username'.format(ssh_username)) if key_filename is not None: deploy_kwargs['key_filename'] = key_filename log.debug('Using {0} as SSH key file'.format(key_filename)) elif 'password' in data.extra: deploy_kwargs['password'] = data.extra['password'] log.debug('Logging into SSH using password') ret = {} if config.get_cloud_config_value('deploy', vm_, __opts__) is True: deploy_script = script(vm_) deploy_kwargs['script'] = deploy_script.script # 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='') # 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'] ret['deploy_kwargs'] = event_kwargs salt.utils.cloud.fire_event( 'event', 'executing deploy script', 'salt/cloud/{0}/deploying'.format(vm_['name']), {'kwargs': event_kwargs}, ) 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 {0}'.format(vm_['name'])) else: log.error('Failed to deploy and start Salt on Cloud VM {0}'.format( vm_['name'])) ret.update(data.__dict__) if 'password' in data.extra: del data.extra['password'] log.info('Created Cloud VM {0[name]!r}'.format(vm_)) log.debug('{0[name]!r} VM creation details:\n{1}'.format( vm_, pprint.pformat(data.__dict__))) salt.utils.cloud.fire_event( 'event', 'created instance', 'salt/cloud/{0}/created'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['provider'], }, ) return ret
def create(vm_): ''' Create a single VM from a data dict ''' deploy = config.get_config_value('deploy', vm_, __opts__) key_filename = config.get_config_value( 'ssh_key_file', vm_, __opts__, search_global=False, default=None ) if key_filename is not None and not os.path.isfile(key_filename): raise SaltCloudConfigError( 'The defined ssh_key_file {0!r} does not exist'.format( key_filename ) ) if deploy is True and key_filename is None and \ salt.utils.which('sshpass') is None: raise SaltCloudSystemExit( 'Cannot deploy salt in a VM if the \'ssh_key_file\' setting ' 'is not set and \'sshpass\' binary is not present on the ' 'system for the password.' ) salt.cloud.utils.fire_event( 'event', 'starting create', 'salt/cloud/{0}/creating'.format(vm_['name']), { 'name': vm_['name'], 'profile': vm_['profile'], 'provider': vm_['provider'], }, ) log.info('Creating Cloud VM {0}'.format(vm_['name'])) salt.cloud.utils.check_name(vm_['name'], 'a-zA-Z0-9._-') conn = get_conn() kwargs = { 'name': vm_['name'] } try: kwargs['image'] = get_image(conn, vm_) except Exception as exc: log.error( 'Error creating {0} on OPENSTACK\n\n' 'Could not find image {1}: {2}\n'.format( vm_['name'], vm_['image'], exc ), # Show the traceback if the debug logging level is enabled exc_info=log.isEnabledFor(logging.DEBUG) ) return False try: kwargs['size'] = get_size(conn, vm_) except Exception as exc: log.error( 'Error creating {0} on OPENSTACK\n\n' 'Could not find size {1}: {2}\n'.format( vm_['name'], vm_['size'], exc ), # Show the traceback if the debug logging level is enabled exc_info=log.isEnabledFor(logging.DEBUG) ) return False kwargs['ex_keyname'] = config.get_config_value( 'ssh_key_name', vm_, __opts__, search_global=False ) security_groups = config.get_config_value( 'security_groups', vm_, __opts__, search_global=False ) if security_groups is not None: vm_groups = security_groups.split(',') avail_groups = conn.ex_list_security_groups() group_list = [] for vmg in vm_groups: if vmg in [ag.name for ag in avail_groups]: group_list.append(vmg) else: raise SaltCloudNotFound( 'No such security group: \'{0}\''.format(vmg) ) kwargs['ex_security_groups'] = [ g for g in avail_groups if g.name in group_list ] networks = config.get_config_value( 'networks', vm_, __opts__, search_global=False ) floating = [] if HAS014 and networks is not None: for net in networks: if 'fixed' in net: kwargs['networks'] = [ OpenStackNetwork(n, None, None, None) for n in net['fixed'] ] elif 'floating' in net: pool = OpenStack_1_1_FloatingIpPool( net['floating'], conn.connection ) for idx in pool.list_floating_ips(): if idx.node_id is None: floating.append(idx) if not floating: # Note(pabelanger): We have no available floating IPs. For # now, we raise an execption and exit. A future enhancement # might be to allow salt-cloud to dynamically allociate new # address but that might be tricky to manage. raise SaltCloudSystemExit( "Floating pool '%s' has not more address available, " "please create some more or use a different pool." % net['floating'] ) files = config.get_config_value( 'files', vm_, __opts__, search_global=False ) if files: kwargs['ex_files'] = {} for src_path in files: with salt.utils.fopen(files[src_path], 'r') as fp_: kwargs['ex_files'][src_path] = fp_.read() userdata_file = config.get_config_value( 'userdata_file', vm_, __opts__, search_global=False ) if userdata_file is not None: with salt.utils.fopen(userdata_file, 'r') as fp: kwargs['ex_userdata'] = fp.read() salt.cloud.utils.fire_event( 'event', 'requesting instance', 'salt/cloud/{0}/requesting'.format(vm_['name']), {'kwargs': {'name': kwargs['name'], 'image': kwargs['image'].name, 'size': kwargs['size'].name}}, ) kwargs['ex_metadata'] = config.get_config_value( 'metadata', vm_, __opts__, default={}, search_global=False ) if not isinstance(kwargs['ex_metadata'], dict): raise SaltCloudConfigError( '\'metadata\' should be a dict.' ) try: data = conn.create_node(**kwargs) except Exception as exc: log.error( 'Error creating {0} on OpenStack\n\n' 'The following exception was thrown by libcloud when trying to ' 'run the initial deployment: {1}\n'.format( vm_['name'], exc ), # Show the traceback if the debug logging level is enabled exc_info=log.isEnabledFor(logging.DEBUG) ) return False def __query_node_data(vm_, data, floating): try: nodelist = list_nodes() log.debug( 'Loaded node data for {0}:\n{1}'.format( vm_['name'], pprint.pformat( nodelist[vm_['name']] ) ) ) except Exception, err: log.error( 'Failed to get nodes list: {0}'.format( err ), # Show the traceback if the debug logging level is enabled exc_info=log.isEnabledFor(logging.DEBUG) ) # Trigger a failure in the wait for IP function return False running = nodelist[vm_['name']]['state'] == node_state( NodeState.RUNNING ) if not running: # Still not running, trigger another iteration return if rackconnect(vm_) is True: extra = nodelist[vm_['name']].get('extra') rc_status = extra.get('metadata').get('rackconnect_automation_status') access_ip = extra.get('access_ip') if rc_status != 'DEPLOYED': log.debug('Waiting for Rackconnect automation to complete') return if managedcloud(vm_) is True: extra = nodelist[vm_['name']].get('extra') mc_status = extra.get('metadata').get('rax_service_level_automation') if mc_status != 'Complete': log.debug('Waiting for managed cloud automation to complete') return if floating: try: name = data.name ip = floating[0].ip_address conn.ex_attach_floating_ip_to_node(data, ip) log.info( 'Attaching floating IP "{0}" to node "{1}"'.format(ip, name) ) except Exception: # Note(pabelanger): Because we loop, we only want to attach the # floating IP address one. So, expect failures if the IP is # already attached. pass result = [] private = nodelist[vm_['name']]['private_ips'] public = nodelist[vm_['name']]['public_ips'] if private and not public: log.warn( 'Private IPs returned, but not public... Checking for ' 'misidentified IPs' ) for private_ip in private: private_ip = preferred_ip(vm_, [private_ip]) if salt.cloud.utils.is_public_ip(private_ip): log.warn('{0} is a public IP'.format(private_ip)) data.public_ips.append(private_ip) log.warn( 'Public IP address was not ready when we last checked. Appending public IP address now.' ) public = data.public_ips else: log.warn('{0} is a private IP'.format(private_ip)) ignore_ip = ignore_cidr(vm_, private_ip) if private_ip not in data.private_ips and not ignore_ip: result.append(private_ip) if rackconnect(vm_) is True: if ssh_interface(vm_) != 'private_ips': data.public_ips = access_ip return data if result: log.debug('result = {0}'.format(result)) data.private_ips = result if ssh_interface(vm_) == 'private_ips': return data if public: data.public_ips = public if ssh_interface(vm_) != 'private_ips': return data