def create_node(vm_): """ Build and submit the XML to create a node """ # Start the tree content = ET.Element("ve") # Name of the instance name = ET.SubElement(content, "name") name.text = vm_["name"] # Description, defaults to name desc = ET.SubElement(content, "description") desc.text = config.get_config_value("desc", vm_, __opts__, default=vm_["name"], search_global=False) # How many CPU cores, and how fast they are cpu = ET.SubElement(content, "cpu") cpu.attrib["number"] = config.get_config_value("cpu_number", vm_, __opts__, default="1", search_global=False) cpu.attrib["power"] = config.get_config_value("cpu_power", vm_, __opts__, default="1000", search_global=False) # How many megabytes of RAM ram = ET.SubElement(content, "ram-size") ram.text = config.get_config_value("ram", vm_, __opts__, default="256", search_global=False) # Bandwidth available, in kbps bandwidth = ET.SubElement(content, "bandwidth") bandwidth.text = config.get_config_value("bandwidth", vm_, __opts__, default="100", search_global=False) # How many public IPs will be assigned to this instance ip_num = ET.SubElement(content, "no-of-public-ip") ip_num.text = config.get_config_value("ip_num", vm_, __opts__, default="1", search_global=False) # Size of the instance disk disk = ET.SubElement(content, "ve-disk") disk.attrib["local"] = "true" disk.attrib["size"] = config.get_config_value("disk_size", vm_, __opts__, default="10", search_global=False) # Attributes for the image vm_image = config.get_config_value("image", vm_, __opts__, search_global=False) image = show_image({"image": vm_image}, call="function") platform = ET.SubElement(content, "platform") template = ET.SubElement(platform, "template-info") template.attrib["name"] = vm_image os_info = ET.SubElement(platform, "os-info") os_info.attrib["technology"] = image[vm_image]["technology"] os_info.attrib["type"] = image[vm_image]["osType"] # Username and password admin = ET.SubElement(content, "admin") admin.attrib["login"] = config.get_config_value("ssh_username", vm_, __opts__, default="root") admin.attrib["password"] = config.get_config_value("password", vm_, __opts__, search_global=False) data = ET.tostring(content, encoding="UTF-8") salt.cloud.utils.fire_event( "event", "requesting instance", "salt/cloud/{0}/requesting".format(vm_["name"]), {"kwargs": data} ) node = query(action="ve", method="POST", data=data) return node
def get_password(vm_): ''' Return the password to use ''' return config.get_config_value( 'password', vm_, __opts__, default=config.get_config_value( 'passwd', vm_, __opts__, search_global=False ), search_global=False )
def query(action=None, command=None, args=None, method="GET", data=None): """ Make a web call to a Parallels provider """ path = config.get_config_value("url", get_configured_provider(), __opts__, search_global=False) auth_handler = urllib2.HTTPBasicAuthHandler() auth_handler.add_password( realm="Parallels Instance Manager", uri=path, user=config.get_config_value("user", get_configured_provider(), __opts__, search_global=False), passwd=config.get_config_value("password", get_configured_provider(), __opts__, search_global=False), ) opener = urllib2.build_opener(auth_handler) urllib2.install_opener(opener) if action: path += action if command: path += "/{0}".format(command) if type(args) is not dict: args = {} kwargs = {"data": data} if type(data) is str and "<?xml" in data: kwargs["headers"] = {"Content-type": "application/xml"} if args: path += "?%s" params = urllib.urlencode(args) req = urllib2.Request(url=path % params, **kwargs) else: req = urllib2.Request(url=path, **kwargs) req.get_method = lambda: method log.debug("{0} {1}".format(method, req.get_full_url())) if data: log.debug(data) try: result = urllib2.urlopen(req) log.debug("PARALLELS Response Status Code: {0}".format(result.getcode())) if "content-length" in result.headers: content = result.read() result.close() items = ET.fromstring(content) return items return {} except urllib2.URLError as exc: log.error("PARALLELS Response Status Code: {0} {1}".format(exc.code, exc.msg)) root = ET.fromstring(exc.read()) log.error(root) return {"error": root}
def get_conn(): """ Return a conn object for the passed VM data """ driver = get_driver(Provider.GOGRID) vm_ = get_configured_provider() return driver( config.get_config_value("apikey", vm_, __opts__, search_global=False), config.get_config_value("sharedsecret", vm_, __opts__, search_global=False), )
def get_conn(): ''' Return a conn object for the passed VM data ''' vm_ = get_configured_provider() driver = get_driver(Provider.IBM) return driver( config.get_config_value('user', vm_, __opts__, search_global=False), config.get_config_value('password', vm_, __opts__, search_global=False) )
def get_conn(): ''' Return a conn object for the passed VM data ''' vm_ = get_configured_provider() driver = get_driver(Provider.OPENSTACK) authinfo = { 'ex_force_auth_url': config.get_config_value( 'identity_url', vm_, __opts__, search_global=False ), 'ex_force_service_name': config.get_config_value( 'compute_name', vm_, __opts__, search_global=False ), 'ex_force_service_region': config.get_config_value( 'compute_region', vm_, __opts__, search_global=False ), 'ex_tenant_name': config.get_config_value( 'tenant', vm_, __opts__, search_global=False ), } service_type = config.get_config_value( 'service_type', vm_, __opts__, search_global=False ) if service_type: authinfo['ex_force_service_type'] = service_type insecure = config.get_config_value( 'insecure', vm_, __opts__, search_global=False ) if insecure: import libcloud.security libcloud.security.VERIFY_SSL_CERT = False password = config.get_config_value( 'password', vm_, __opts__, search_global=False ) if password is not None: authinfo['ex_force_auth_version'] = '2.0_password' log.debug('OpenStack authenticating using password') return driver( config.get_config_value( 'user', vm_, __opts__, search_global=False ), password, **authinfo ) authinfo['ex_force_auth_version'] = '2.0_apikey' log.debug('OpenStack authenticating using apikey') return driver( config.get_config_value('user', vm_, __opts__, search_global=False), config.get_config_value('apikey', vm_, __opts__, search_global=False), **authinfo )
def get_password(vm_): """ Return the password to use """ return config.get_config_value( "password", vm_, __opts__, default=config.get_config_value("passwd", vm_, __opts__, search_global=False), search_global=False, )
def get_conn(): ''' Return a conn object for the passed VM data ''' driver = get_driver(Provider.GOGRID) vm_ = get_configured_provider() return driver( config.get_config_value('apikey', vm_, __opts__, search_global=False), config.get_config_value('sharedsecret', vm_, __opts__, search_global=False))
def get_conn(service='SoftLayer_Hardware'): ''' Return a conn object for the passed VM data ''' client = SoftLayer.Client( username=config.get_config_value( 'user', get_configured_provider(), __opts__, search_global=False ), api_key=config.get_config_value( 'apikey', get_configured_provider(), __opts__, search_global=False ), ) return client[service]
def get_conn(): ''' Return a conn object for the passed VM data ''' driver = get_driver(Provider.GOGRID) vm_ = get_configured_provider() return driver( config.get_config_value( 'apikey', vm_, __opts__, search_global=False ), config.get_config_value( 'sharedsecret', vm_, __opts__, search_global=False ) )
def query(method='droplets', droplet_id=None, command=None, args=None): ''' Make a web call to Digital Ocean ''' path = 'https://api.digitalocean.com/{0}/'.format(method) if droplet_id: path += '{0}/'.format(droplet_id) if command: path += command if type(args) is not dict: args = {} args['client_id'] = config.get_config_value( 'client_key', get_configured_provider(), __opts__, search_global=False ) args['api_key'] = config.get_config_value( 'api_key', get_configured_provider(), __opts__, search_global=False ) path += '?%s' params = urllib.urlencode(args) request = urllib2.urlopen(path % params) if request.getcode() != 200: raise SaltCloudSystemExit( 'An error occurred while querying Digital Ocean. HTTP Code: {0} ' 'Error: {1!r}'.format( request.getcode(), request.read() ) ) log.debug(request.geturl()) content = request.read() request.close() result = json.loads(content) if result.get('status', '').lower() == 'error': raise SaltCloudSystemExit( ''.join( '{0}: {1}\n'.format(k, '\n'.join(v)) for (k, v) in result.get('error_message', {}).items() ) ) return result
def get_conn(service='SoftLayer_Virtual_Guest'): ''' Return a conn object for the passed VM data ''' client = SoftLayer.Client( username=config.get_config_value('user', get_configured_provider(), __opts__, search_global=False), api_key=config.get_config_value('apikey', get_configured_provider(), __opts__, search_global=False), ) return client[service]
def _toggle_term_protect(name, enabled): ''' Toggle termination protection on a node ''' # region is required for all boto queries region = get_location(None) # init botocore vm_ = get_configured_provider() session = botocore.session.get_session() # pylint: disable=E0602 session.set_credentials( access_key=config.get_config_value( 'id', vm_, __opts__, search_global=False ), secret_key=config.get_config_value( 'key', vm_, __opts__, search_global=False ) ) service = session.get_service('ec2') endpoint = service.get_endpoint(region) # get the instance-id for the supplied node name conn = get_conn(location=region) node = get_node(conn, name) params = { 'instance_id': node.id, 'attribute': 'disableApiTermination', 'value': 'true' if enabled else 'false', } # get instance information operation = service.get_operation('modify-instance-attribute') http_response, response_data = operation.call(endpoint, **params) if http_response.status_code == 200: msg = 'Termination protection successfully {0} on {1}'.format( enabled and 'enabled' or 'disabled', name ) log.info(msg) return msg # No proper HTTP response!? msg = 'Bad response from AWS: {0}'.format(http_response.status_code) log.error(msg) return msg
def get_conn(): ''' Return a conn object for the passed VM data ''' force_first_gen = config.get_config_value( 'force_first_gen', get_configured_provider(), __opts__, search_global=False, default=False ) compute_region = config.get_config_value( 'compute_region', get_configured_provider(), __opts__, search_global=False, default='DFW' ).upper() if force_first_gen: log.info('Rackspace driver will only have access to first-gen images') driver = get_driver(Provider.RACKSPACE) else: computed_provider = 'RACKSPACE_NOVA_{0}'.format(compute_region) try: driver = get_driver(getattr(Provider, computed_provider)) except AttributeError: log.info( 'Rackspace driver will only have access to first-gen images ' 'since it was unable to load the driver as {0}'.format( computed_provider ) ) driver = get_driver(Provider.RACKSPACE) return driver( config.get_config_value( 'user', get_configured_provider(), __opts__, search_global=False ), config.get_config_value( 'apikey', get_configured_provider(), __opts__, search_global=False ) )
def get_key(): ''' Returns the ssk private key for VM access ''' return config.get_config_value( 'private_key', get_configured_provider(), __opts__, search_global=False )
def get_image(conn, vm_): ''' Return the image object to use ''' images = conn.list_images() vm_image = config.get_config_value('image', vm_, __opts__).encode( 'ascii', 'salt-cloud-force-ascii') for img in images: if isinstance(img.id, salt._compat.string_types): img_id = img.id.encode('ascii', 'salt-cloud-force-ascii') else: img_id = str(img.id) if isinstance(img.name, salt._compat.string_types): img_name = img.name.encode('ascii', 'salt-cloud-force-ascii') else: img_name = str(img.name) if vm_image and vm_image in (img_id, img_name): return img raise SaltCloudNotFound( 'The specified image, {0!r}, could not be found.'.format(vm_image))
def get_location(conn, vm_): ''' Return the location object to use ''' locations = conn.list_locations() vm_location = config.get_config_value('location', vm_, __opts__).encode( 'ascii', 'salt-cloud-force-ascii' ) for img in locations: if isinstance(img.id, salt._compat.string_types): img_id = img.id.encode('ascii', 'salt-cloud-force-ascii') else: img_id = str(img.id) if isinstance(img.name, salt._compat.string_types): img_name = img.name.encode('ascii', 'salt-cloud-force-ascii') else: img_name = str(img.name) if vm_location and vm_location in (img_id, img_name): return img raise SaltCloudNotFound( 'The specified location, {0!r}, could not be found.'.format( vm_location ) )
def ssh_username(vm_): ''' Return the ssh_username. Defaults to 'ec2-user'. ''' usernames = config.get_config_value( 'ssh_username', vm_, __opts__ ) if not isinstance(usernames, list): usernames = [usernames] # get rid of None's or empty names usernames = filter(lambda x: x, usernames) # Keep a copy of the usernames the user might have provided initial = usernames[:] # Add common usernames to the list to be tested for name in ('ec2-user', 'ubuntu', 'admin', 'bitnami', 'root'): if name not in usernames: usernames.append(name) # Add the user provided usernames to the end of the list since enough time # might need to pass before the remote service is available for logins and # the proper username might have passed it's iteration. # This has detected in a CentOS 5.7 EC2 image usernames.extend(initial) return usernames
def destroy(name): ''' Wrap core libcloudfuncs destroy method, adding check for termination protection ''' ret = {} newname = name if config.get_config_value('rename_on_destroy', get_configured_provider(), __opts__, search_global=False) is True: newname = '{0}-DEL{1}'.format(name, uuid.uuid4().hex) rename(name, kwargs={'newname': newname}, call='action') log.info( 'Machine will be identified as {0} until it has been ' 'cleaned up by AWS.'.format( newname ) ) ret['newname'] = newname try: result = libcloudfuncs_destroy(newname, get_conn()) ret.update({'Destroyed': result}) except Exception as exc: if not exc.message.startswith('OperationNotPermitted'): log.exception(exc) raise exc log.info( 'Failed: termination protection is enabled on {0}'.format( name ) ) return ret
def get_location(conn, vm_): ''' Return the location object to use ''' locations = conn.list_locations() vm_location = config.get_config_value('location', vm_, __opts__).encode( 'ascii', 'salt-cloud-force-ascii') for img in locations: if isinstance(img.id, salt._compat.string_types): img_id = img.id.encode('ascii', 'salt-cloud-force-ascii') else: img_id = str(img.id) if isinstance(img.name, salt._compat.string_types): img_name = img.name.encode('ascii', 'salt-cloud-force-ascii') else: img_name = str(img.name) if vm_location and vm_location in (img_id, img_name): return img raise SaltCloudNotFound( 'The specified location, {0!r}, could not be found.'.format( vm_location))
def get_image(conn, vm_): ''' Return the image object to use ''' images = conn.list_images() vm_image = config.get_config_value('image', vm_, __opts__).encode( 'ascii', 'salt-cloud-force-ascii' ) for img in images: if isinstance(img.id, salt._compat.string_types): img_id = img.id.encode('ascii', 'salt-cloud-force-ascii') else: img_id = str(img.id) if isinstance(img.name, salt._compat.string_types): img_name = img.name.encode('ascii', 'salt-cloud-force-ascii') else: img_name = str(img.name) if vm_image and vm_image in (img_id, img_name): return img raise SaltCloudNotFound( 'The specified image, {0!r}, could not be found.'.format(vm_image) )
def iam_profile(vm_): ''' Return the IAM role ''' return config.get_config_value( 'iam_profile', vm_, __opts__, search_global=False )
def securitygroup(vm_): ''' Return the security group ''' return config.get_config_value( 'securitygroup', vm_, __opts__, search_global=False )
def keyname(vm_): ''' Return the keyname ''' return config.get_config_value( 'keyname', vm_, __opts__, search_global=False )
def _toggle_term_protect(name, enabled): ''' Toggle termination protection on a node ''' # region is required for all boto queries region = get_location(None) # init botocore vm_ = get_configured_provider() session = botocore.session.get_session() # pylint: disable=E0602 session.set_credentials( access_key=config.get_config_value('id', vm_, __opts__, search_global=False), secret_key=config.get_config_value('key', vm_, __opts__, search_global=False)) service = session.get_service('ec2') endpoint = service.get_endpoint(region) # get the instance-id for the supplied node name conn = get_conn(location=region) node = get_node(conn, name) params = { 'instance_id': node.id, 'attribute': 'disableApiTermination', 'value': 'true' if enabled else 'false', } # get instance information operation = service.get_operation('modify-instance-attribute') http_response, response_data = operation.call(endpoint, **params) if http_response.status_code == 200: msg = 'Termination protection successfully {0} on {1}'.format( enabled and 'enabled' or 'disabled', name) log.info(msg) return msg # No proper HTTP response!? msg = 'Bad response from AWS: {0}'.format(http_response.status_code) log.error(msg) return msg
def get_conn(): ''' Return a conn object for the passed VM data ''' vm_ = get_configured_provider() auth_minion = config.get_config_value( 'auth_minion', vm_, __opts__, search_global=False ) config_profile = config.get_config_value( 'config_profile', vm_, __opts__, search_global=False ) if config_profile: return { 'auth_minion': auth_minion, 'profile': config_profile }
def script(vm_): ''' Return the script deployment object ''' return salt.cloud.utils.os_script( config.get_config_value('script', vm_, __opts__), vm_, __opts__, salt.cloud.utils.salt_config_to_yaml( salt.cloud.utils.minion_config(__opts__, vm_)))
def rackconnect(vm_): ''' Determine if we should wait for rackconnect automation before running. Either 'False' (default) or 'True'. ''' return config.get_config_value( 'rackconnect', vm_, __opts__, default='False', search_global=False )
def managedcloud(vm_): ''' Determine if we should wait for the managed cloud automation before running. Either 'False' (default) or 'True'. ''' return config.get_config_value( 'managedcloud', vm_, __opts__, default='False', search_global=False )
def ssh_interface(vm_): ''' Return the ssh_interface type to connect to. Either 'public_ips' (default) or 'private_ips'. ''' return config.get_config_value( 'ssh_interface', vm_, __opts__, default='public_ips', search_global=False )
def query(method='droplets', droplet_id=None, command=None, args=None): ''' Make a web call to Digital Ocean ''' path = 'https://api.digitalocean.com/{0}/'.format(method) if droplet_id: path += '{0}/'.format(droplet_id) if command: path += command if type(args) is not dict: args = {} args['client_id'] = config.get_config_value('client_key', get_configured_provider(), __opts__, search_global=False) args['api_key'] = config.get_config_value('api_key', get_configured_provider(), __opts__, search_global=False) path += '?%s' params = urllib.urlencode(args) request = urllib2.urlopen(path % params) if request.getcode() != 200: raise SaltCloudSystemExit( 'An error occurred while querying Digital Ocean. HTTP Code: {0} ' 'Error: {1!r}'.format(request.getcode(), request.read())) log.debug(request.geturl()) content = request.read() request.close() result = json.loads(content) if result.get('status', '').lower() == 'error': raise SaltCloudSystemExit(''.join( '{0}: {1}\n'.format(k, '\n'.join(v)) for (k, v) in result.get('error_message', {}).items())) return result
def get_keypair(vm_): ''' Return the keypair to use ''' keypair = config.get_config_value('keypair', vm_, __opts__) if keypair: return keypair else: return False
def get_networkid(vm_): ''' Return the networkid to use, only valid for Advanced Zone ''' networkid = config.get_config_value('networkid', vm_, __opts__) if networkid is not None: return networkid else: return False
def block_device_mappings(vm_): ''' Return the block device mapping:: [{'DeviceName': '/dev/sdb', 'VirtualName': 'ephemeral0'}, {'DeviceName': '/dev/sdc', 'VirtualName': 'ephemeral1'}] ''' return config.get_config_value( 'block_device_mappings', vm_, __opts__, search_global=False )
def get_image(vm_): """ Return the image object to use """ images = avail_images() vm_image = config.get_config_value("image", vm_, __opts__, search_global=False) for image in images: if str(vm_image) in (images[image]["name"], images[image]["id"]): return images[image]["id"] raise SaltCloudNotFound("The specified image could not be found.")
def script(vm_): """ Return the script deployment object """ return salt.cloud.utils.os_script( config.get_config_value("script", vm_, __opts__), vm_, __opts__, salt.cloud.utils.salt_config_to_yaml(salt.cloud.utils.minion_config(__opts__, vm_)), )
def get_conn(): ''' Return a conn object for the passed VM data ''' driver = get_driver(Provider.LINODE) return driver( config.get_config_value('apikey', get_configured_provider(), __opts__, search_global=False))
def get_location(conn, vm_): ''' Return the node location to use ''' locations = conn.list_locations() # Default to Dallas if not otherwise set loc = config.get_config_value('location', vm_, __opts__, default=2) for location in locations: if str(loc) in (str(location.id), str(location.name)): return location
def get_location(conn, vm_): """ Return the node location to use """ locations = conn.list_locations() # Default to Dallas if not otherwise set loc = config.get_config_value("location", vm_, __opts__, default=2) for location in locations: if str(loc) in (str(location.id), str(location.name)): return location
def get_size(vm_): ''' Return the VM's size. Used by create_node(). ''' sizes = avail_sizes() vm_size = str( config.get_config_value('size', vm_, __opts__, search_global=False)) for size in sizes: if vm_size in (sizes[size]['name'], sizes[size]['id']): return sizes[size]['id'] raise SaltCloudNotFound( 'The specified size, {0!r}, could not be found.'.format(vm_size))
def get_image(vm_): ''' Return the image object to use ''' images = avail_images() vm_image = str( config.get_config_value('image', vm_, __opts__, search_global=False)) for image in images: if vm_image in (images[image]['name'], images[image]['id']): return images[image]['id'] raise SaltCloudNotFound( 'The specified image, {0!r}, could not be found.'.format(vm_image))
def get_image(vm_): ''' Return the image object to use ''' images = avail_images() vm_image = config.get_config_value('image', vm_, __opts__) if vm_image and str(vm_image) in images.keys(): return images[vm_image] raise SaltCloudNotFound( 'The specified image, {0!r}, could not be found.'.format(vm_image))
def ssh_pub(vm_): ''' Deploy the primary ssh authentication key ''' ssh = config.get_config_value('ssh_auth', vm_, __opts__) if not ssh: return None ssh = os.path.expanduser(ssh) if os.path.isfile(ssh): return None return SSHKeyDeployment(open(ssh).read())
def get_size(vm_): ''' Return the VM's size object ''' sizes = avail_sizes() vm_size = config.get_config_value('size', vm_, __opts__) if not vm_size: raise SaltCloudNotFound('No size specified for this VM.') if vm_size and str(vm_size) in sizes.keys(): return sizes[vm_size] raise SaltCloudNotFound( 'The specified size, {0!r}, could not be found.'.format(vm_size))
def get_location(vm_=None): ''' Return the joyent datacenter to use, in this order: - CLI parameter - VM parameter - Cloud profile setting ''' return __opts__.get( 'location', config.get_config_value('location', vm_ or get_configured_provider(), __opts__, default=DEFAULT_LOCATION, search_global=False))
def get_size(conn, vm_): ''' Return the VM's size object ''' sizes = conn.list_sizes() vm_size = config.get_config_value('size', vm_, __opts__) if not vm_size: return sizes[0] for size in sizes: if vm_size and str(vm_size) in (str(size.id), str(size.name)): return size raise SaltCloudNotFound( 'The specified size, {0!r}, could not be found.'.format(vm_size))
def get_conn(): ''' Return a conn object for the passed VM data ''' force_first_gen = config.get_config_value('force_first_gen', get_configured_provider(), __opts__, search_global=False, default=False) compute_region = config.get_config_value('compute_region', get_configured_provider(), __opts__, search_global=False, default='DFW').upper() if force_first_gen: log.info('Rackspace driver will only have access to first-gen images') driver = get_driver(Provider.RACKSPACE) else: computed_provider = 'RACKSPACE_NOVA_{0}'.format(compute_region) try: driver = get_driver(getattr(Provider, computed_provider)) except AttributeError: log.info( 'Rackspace driver will only have access to first-gen images ' 'since it was unable to load the driver as {0}'.format( computed_provider)) driver = get_driver(Provider.RACKSPACE) return driver( config.get_config_value('user', get_configured_provider(), __opts__, search_global=False), config.get_config_value('apikey', get_configured_provider(), __opts__, search_global=False))
def get_location(vm_): ''' Return the VM's location ''' locations = avail_locations() vm_location = str( config.get_config_value('location', vm_, __opts__, search_global=False)) for location in locations: if vm_location in (locations[location]['name'], locations[location]['id']): return locations[location]['id'] raise SaltCloudNotFound( 'The specified location, {0!r}, could not be found.'.format( vm_location))
def ignore_cidr(vm_, ip): ''' Return True if we are to ignore the specified IP. Compatible with IPv4. ''' if HAS_NETADDR is False: log.error('Error: netaddr is not installed') return 'Error: netaddr is not installed' cidr = config.get_config_value( 'ignore_cidr', vm_, __opts__, default='', search_global=False ) if cidr != '' and all_matching_cidrs(ip, [cidr]): log.warning('IP "{0}" found within "{1}"; ignoring it.'.format(ip, cidr)) return True return False
def preferred_ip(vm_, ips): ''' Return the preferred Internet protocol. Either 'ipv4' (default) or 'ipv6'. ''' proto = config.get_config_value( 'protocol', vm_, __opts__, default='ipv4', search_global=False ) family = socket.AF_INET if proto == 'ipv6': family = socket.AF_INET6 for ip in ips: try: socket.inet_pton(family, ip) return ip except Exception: continue return False