def list_nodes(self): """ Retrieves the list of nodes that have been defined across blueprints for this facility :return: names of nodes defined for this facility :rtype: ``list`` of ``str`` or ``[]`` Nodes are defined in blueprints. """ labels = [] for blueprint in self.blueprints: name = list(blueprint)[0] if 'nodes' in blueprint[name]: for item in blueprint[name]['nodes']: if type(item) is dict: label = list(item)[0] else: label = item for label in PlumberyNodes.expand_labels(label): if label in labels: plogging.warning("Duplicate node name '{}'" .format(label)) else: labels.append(label) return labels
def upgrade_vmware_tools(self, node): """ Upgrade VMware tools on target node :param node: the node to be polished :type node: :class:`libcloud.compute.base.Node` """ if self.engine.safeMode: return True while True: try: self.region.ex_update_vm_tools(node=node) plogging.info("- upgrading vmware tools") return True except Exception as feedback: if 'RESOURCE_BUSY' in str(feedback): time.sleep(10) continue if 'Please try again later' in str(feedback): time.sleep(10) continue if 'NO_CHANGE' in str(feedback): plogging.debug("- vmware tools is already up-to-date") return True plogging.warning("- unable to upgrade vmware tools") plogging.warning(str(feedback)) return False
def list_nodes(self): """ Retrieves the list of nodes that have been defined across blueprints for this facility :return: names of nodes defined for this facility :rtype: ``list`` of ``str`` or ``[]`` Nodes are defined in blueprints. """ labels = [] for blueprint in self.blueprints: name = list(blueprint)[0] if 'nodes' in blueprint[name]: for item in blueprint[name]['nodes']: if type(item) is dict: label = list(item)[0] else: label = item for label in PlumberyNodes.expand_labels(label): if label in labels: plogging.warning( "Duplicate node name '{}'".format(label)) else: labels.append(label) return labels
def test_direct(self): plogging.setLevel(logging.DEBUG) self.assertEqual(plogging.getEffectiveLevel(), logging.DEBUG) plogging.debug("hello world -- debug") plogging.info("hello world -- info") plogging.warning("hello world -- warning") plogging.error("hello world -- error") plogging.critical("hello world -- critical") self.assertEqual(plogging.foundErrors(), True) plogging.reset() self.assertEqual(plogging.foundErrors(), False)
def test_direct(self): class DullHandler(logging.NullHandler): level = logging.DEBUG def emit(self, record): log_entry = self.format(record) plogging.addHandler(DullHandler()) plogging.setLevel(logging.DEBUG) self.assertEqual(plogging.getEffectiveLevel(), logging.DEBUG) plogging.debug("hello world -- debug") plogging.info("hello world -- info") plogging.warning("hello world -- warning") plogging.error("hello world -- error") plogging.critical("hello world -- critical") self.assertEqual(plogging.foundErrors(), True) plogging.reset() self.assertEqual(plogging.foundErrors(), False)
def expand_labels(self, label): """ Designates multiple nodes with a simple label :param label: the label to be expanded, e.g., ``server[1..2]_eu`` :type label: ``str`` :return: a list of names, e.g., ``['server1_eu', 'server2_eu']`` :rtype: ``list`` of ``str`` This function creates multiple names where applicable:: >>>nodes.expand_labels('mongodb') ['mongodb'] >>>nodes.expand_labels('mongodb[1..3]_eu') ['mongodb1_eu', 'mongodb2_eu', 'mongodb3_eu'] """ matches = re.match(r'(.*)\[([0-9]+)..([0-9]+)\](.*)', label) if matches is None: if re.match("^[0-9a-zA-Z]([0-9a-zA-Z\-]{0,61}[0-9a-zA-Z])?$", label) is None: plogging.warning( "Warning: '{}' is not a valid hostname".format(label)) return [label] labels = [] for index in range(int(matches.group(2)), int(matches.group(3)) + 1): label = matches.group(1) + str(index) + matches.group(4) if re.match("^[0-9a-zA-Z]([0-9a-zA-Z\-]{0,61}[0-9a-zA-Z])?$", label) is None: plogging.warning( "Warning: '{}' is not a valid hostname".format(label)) labels.append(label) return labels
def focus(self): """ Where are we plumbing? """ self.power_on() plogging.info("Plumbing at '{}' {} ({})".format( self.location.id, self.location.name, self.location.country)) blueprints = self.list_blueprints() if len(blueprints) < 1: plogging.warning("- no blueprint has been found") else: plogging.debug("- available blueprints: {}".format( "'"+"', '".join(blueprints)+"'")) basement = self.list_basement() if len(basement) > 0: plogging.debug("- basement: {}".format( "'"+"', '".join(basement)+"'"))
def focus(self): """ Where are we plumbing? """ self.power_on() plogging.info("Plumbing at '{}' {} ({})".format( self.location.id, self.location.name, self.location.country)) blueprints = self.list_blueprints() if len(blueprints) < 1: plogging.warning("- no blueprint has been found") else: plogging.debug( "- available blueprints: {}".format("'" + "', '".join(blueprints) + "'")) basement = self.list_basement() if len(basement) > 0: plogging.debug( "- basement: {}".format("'" + "', '".join(basement) + "'"))
def expand_labels(self, label): """ Designates multiple nodes with a simple label :param label: the label to be expanded, e.g., ``server[1..2]_eu`` :type label: ``str`` :return: a list of names, e.g., ``['server1_eu', 'server2_eu']`` :rtype: ``list`` of ``str`` This function creates multiple names where applicable:: >>>nodes.expand_labels('mongodb') ['mongodb'] >>>nodes.expand_labels('mongodb[1..3]_eu') ['mongodb1_eu', 'mongodb2_eu', 'mongodb3_eu'] """ matches = re.match(r'(.*)\[([0-9]+)..([0-9]+)\](.*)', label) if matches is None: if re.match("^[0-9a-zA-Z]([0-9a-zA-Z\-]{0,61}[0-9a-zA-Z])?$", label) is None: plogging.warning("Warning: '{}' is not a valid hostname" .format(label)) return [label] labels = [] for index in range(int(matches.group(2)), int(matches.group(3))+1): label = matches.group(1)+str(index)+matches.group(4) if re.match("^[0-9a-zA-Z]([0-9a-zA-Z\-]{0,61}[0-9a-zA-Z])?$", label) is None: plogging.warning("Warning: '{}' is not a valid hostname" .format(label)) labels.append(label) return labels
def get_node(self, path): """ Retrieves a node by name :param path: the name of the target node, or its location :type path: ``str`` or ``list``of ``str`` :return: the target node, or None :rtype: :class:`libcloud.compute.base.Node` This function always make a real API call to get fresh state of the target node. Therefore, it can be used in loops where you monitor the evolution of the node during build or other change operation. This function searches firstly at the current facility. If the name is a complete path to a remote node, then plumbery looks there. If a different region is provided, then authentication is done against the related endpoint. For example if ``MyServer`` has been defined in a data centre in Europe:: >>>infrastructure.get_ethernet('MyServer') >>>infrastructure.get_ethernet(['EU6', 'MyServer']) Looking for remote node 'EU6::MyServer' - found it >>>infrastructure.get_ethernet(['dd-eu', 'EU6', 'MyServer']) Looking for offshore node 'dd-eu::EU6::MyServer' - found it """ if isinstance(path, str): path = path.split('::') node = None if len(path) == 2: # force offshore lookup if needed target_region = self.facility.get_region(path[0]) if target_region != self.facility.get_region(): path.insert(0, target_region) if len(path) == 1: # local name self.facility.power_on() for node in self.region.list_nodes(): if node.extra['datacenterId'] != self.facility.get_location_id( ): continue if node.name == path[0]: self._enrich_node(node) return node elif len(path) == 2: # different location, same region self.facility.power_on() try: self.region.ex_get_location_by_id(path[0]) except IndexError: plogging.warning("'{}' is unknown".format(path[0])) return None plogging.debug("Looking for remote node '{}'".format( '::'.join(path))) for node in self.region.list_nodes(): if node.extra['datacenterId'] != path[0]: continue if node.name == path[1]: plogging.debug("- found it") self._enrich_node(node) return node elif len(path) == 3: # other region offshore = self.plumbery.get_compute_driver(region=path[0]) try: remoteLocation = offshore.ex_get_location_by_id(path[1]) except IndexError: plogging.warning("'{}' is unknown".format(path[1])) return None plogging.debug("Looking for offshore node '{}'".format( '::'.join(path))) for node in offshore.list_nodes(): if node.extra['datacenterId'] != path[1]: continue if node.name == path[2]: plogging.debug("- found it") self._enrich_node(node, region=offshore) return node return None
def _apply_prepares(self, node, steps): """ Does the actual job over SSH :param node: the node to be polished :type node: :class:`libcloud.compute.base.Node` :param steps: the various steps of the preparing :type steps: :class:`libcloud.compute.deployment.MultiStepDeployment` :return: ``True`` if everything went fine, ``False`` otherwise :rtype: ``bool`` """ if node is None or node.state != NodeState.RUNNING: plogging.warning("- skipped - node is not running") return False # select the address to use if len(node.public_ips) > 0: target_ip = node.public_ips[0] elif node.extra['ipv6']: target_ip = node.extra['ipv6'] else: target_ip = node.private_ips[0] # guess location of user key path = os.path.expanduser('~/.ssh/id_rsa') # use libcloud to communicate with remote nodes session = SSHClient(hostname=target_ip, port=22, username=self.user, password=self.secret, key_files=path, timeout=9) try: session.connect() except Exception as feedback: plogging.error("Error: unable to prepare '{}' at '{}'!".format( node.name, target_ip)) plogging.error(str(feedback)) plogging.error("- failed") return False while True: try: if self.engine.safeMode: plogging.info("- skipped - no ssh interaction in safe mode") else: node = steps.run(node, session) except Exception as feedback: if 'RESOURCE_BUSY' in str(feedback): time.sleep(10) continue plogging.error("Error: unable to prepare '{}' at '{}'!".format( node.name, target_ip)) plogging.error(str(feedback)) plogging.error("- failed") result = False else: result = True break try: session.close() except: pass return result
def _apply_prepares(self, node, steps): """ Does the actual job over SSH :param node: the node to be polished :type node: :class:`libcloud.compute.base.Node` :param steps: the various steps of the preparing :type steps: ``list`` of ``dict`` :return: ``True`` if everything went fine, ``False`` otherwise :rtype: ``bool`` """ if node is None or node.state != NodeState.RUNNING: plogging.warning("- skipped - node is not running") return False # select the address to use if len(node.public_ips) > 0: target_ip = node.public_ips[0] elif node.extra['ipv6']: target_ip = node.extra['ipv6'] else: target_ip = node.private_ips[0] # use libcloud to communicate with remote nodes session = SSHClient(hostname=target_ip, port=22, username=self.user, password=self.secret, key_files=self.key_files, timeout=10) repeats = 0 while True: try: session.connect() break except Exception as feedback: repeats += 1 if repeats > 5: plogging.error("Error: can not connect to '{}'!".format( target_ip)) plogging.error("- failed to connect") return False plogging.debug(str(feedback)) plogging.debug("- connection {} failed, retrying".format(repeats)) time.sleep(10) continue while True: try: if self.engine.safeMode: plogging.info("- skipped - no ssh interaction in safe mode") else: for step in steps: plogging.info('- {}'.format(step['description'])) step['genius'].run(node, session) except Exception as feedback: if 'RESOURCE_BUSY' in str(feedback): time.sleep(10) continue plogging.error("Error: unable to prepare '{}' at '{}'!".format( node.name, target_ip)) plogging.error(str(feedback)) plogging.error("- failed") result = False else: result = True break try: session.close() except: pass return result
def _get_prepares(self, node, settings, container): """ Defines the set of actions to be done on a node :param node: the node to be polished :type node: :class:`libcloud.compute.base.Node` :param settings: the fittings plan for this node :type settings: ``dict`` :param container: the container of this node :type container: :class:`plumbery.PlumberyInfrastructure` :return: a list of actions to be performed, and related descriptions :rtype: a ``list`` of `{ 'description': ..., 'genius': ... }`` """ if not isinstance(settings, dict): return [] environment = PlumberyNodeContext(node=node, container=container, context=self.facility) prepares = [] for key_file in self.key_files: try: path = os.path.expanduser(key_file) with open(path) as stream: key = stream.read() stream.close() prepares.append({ 'description': 'deploy SSH public key', 'genius': SSHKeyDeployment(key=key)}) except IOError: plogging.warning("no ssh key in {}".format(key_file)) if ('prepare' in settings and isinstance(settings['prepare'], list) and len(settings['prepare']) > 0): plogging.info('- using prepare commands') for script in settings['prepare']: tokens = script.split(' ') if len(tokens) == 1: tokens.insert(0, 'run') if tokens[0] in ['run', 'run_raw']: # send and run a script script = tokens[1] if len(tokens) > 2: args = tokens[2:] else: args = [] plogging.debug("- {} {} {}".format( tokens[0], script, ' '.join(args))) try: with open(script) as stream: text = stream.read() if(tokens[0] == 'run' and PlumberyText.could_expand(text)): plogging.debug("- expanding script '{}'" .format(script)) text = PlumberyText.expand_string( text, environment) if len(text) > 0: plogging.info("- running '{}'" .format(script)) prepares.append({ 'description': ' '.join(tokens), 'genius': ScriptDeployment( script=text, args=args, name=script)}) else: plogging.error("- script '{}' is empty" .format(script)) except IOError: plogging.error("- unable to read script '{}'" .format(script)) elif tokens[0] in ['put', 'put_raw']: # send a file file = tokens[1] if len(tokens) > 2: destination = tokens[2] else: destination = './'+file plogging.debug("- {} {} {}".format( tokens[0], file, destination)) try: with open(file) as stream: content = stream.read() if(tokens[0] == 'put' and PlumberyText.could_expand(content)): plogging.debug("- expanding file '{}'" .format(file)) content = PlumberyText.expand_string( content, environment) plogging.info("- putting file '{}'" .format(file)) prepares.append({ 'description': ' '.join(tokens), 'genius': FileContentDeployment( content=content, target=destination)}) except IOError: plogging.error("- unable to read file '{}'" .format(file)) else: # echo a sensible message eventually if tokens[0] == 'echo': tokens.pop(0) message = ' '.join(tokens) message = PlumberyText.expand_string( message, environment) plogging.info("- {}".format(message)) if ('cloud-config' in settings and isinstance(settings['cloud-config'], dict) and len(settings['cloud-config']) > 0): plogging.info('- using cloud-config') # mandatory, else cloud-init will not consider user-data plogging.debug('- preparing meta-data') meta_data = 'instance_id: dummy\n' destination = '/var/lib/cloud/seed/nocloud-net/meta-data' prepares.append({ 'description': 'put meta-data', 'genius': FileContentDeployment( content=meta_data, target=destination)}) plogging.debug('- preparing user-data') expanded = PlumberyText.expand_string( settings['cloud-config'], environment) user_data = '#cloud-config\n'+expanded plogging.debug(user_data) destination = '/var/lib/cloud/seed/nocloud-net/user-data' prepares.append({ 'description': 'put user-data', 'genius': FileContentDeployment( content=user_data, target=destination)}) plogging.debug('- preparing remote install of cloud-init') script = 'prepare.cloud-init.sh' try: path = os.path.dirname(__file__)+'/'+script with open(path) as stream: text = stream.read() if text: prepares.append({ 'description': 'run '+script, 'genius': ScriptDeployment( script=text, name=script)}) except IOError: raise PlumberyException("Error: cannot read '{}'" .format(script)) plogging.debug('- preparing reboot to trigger cloud-init') prepares.append({ 'description': 'reboot node', 'genius': RebootDeployment( container=container)}) return prepares
def get_node(self, path): """ Retrieves a node by name :param path: the name of the target node, or its location :type path: ``str`` or ``list``of ``str`` :return: the target node, or None :rtype: :class:`libcloud.compute.base.Node` This function always make a real API call to get fresh state of the target node. Therefore, it can be used in loops where you monitor the evolution of the node during build or other change operation. This function searches firstly at the current facility. If the name is a complete path to a remote node, then plumbery looks there. If a different region is provided, then authentication is done against the related endpoint. For example if ``MyServer`` has been defined in a data centre in Europe:: >>>infrastructure.get_ethernet('MyServer') >>>infrastructure.get_ethernet(['EU6', 'MyServer']) Looking for remote node 'EU6::MyServer' - found it >>>infrastructure.get_ethernet(['dd-eu', 'EU6', 'MyServer']) Looking for offshore node 'dd-eu::EU6::MyServer' - found it """ if isinstance(path, str): path = path.split('::') node = None if len(path) == 2: # force offshore lookup if needed target_region = self.facility.get_region(path[0]) if target_region != self.facility.get_region(): path.insert(0, target_region) if len(path) == 1: # local name self.facility.power_on() for node in self.region.list_nodes(): if node.extra['datacenterId'] != self.facility.get_location_id(): continue if node.name == path[0]: self._enrich_node(node) return node elif len(path) == 2: # different location, same region self.facility.power_on() try: self.region.ex_get_location_by_id(path[0]) except IndexError: plogging.warning("'{}' is unknown".format(path[0])) return None plogging.debug("Looking for remote node '{}'" .format('::'.join(path))) for node in self.region.list_nodes(): if node.extra['datacenterId'] != path[0]: continue if node.name == path[1]: plogging.debug("- found it") self._enrich_node(node) return node elif len(path) == 3: # other region offshore = self.plumbery.get_compute_driver(region=path[0]) try: remoteLocation = offshore.ex_get_location_by_id(path[1]) except IndexError: plogging.warning("'{}' is unknown".format(path[1])) return None plogging.debug("Looking for offshore node '{}'" .format('::'.join(path))) for node in offshore.list_nodes(): if node.extra['datacenterId'] != path[1]: continue if node.name == path[2]: plogging.debug("- found it") self._enrich_node(node, region=offshore) return node return None
def _get_prepares(self, node, settings, container): """ Defines the set of actions to be done on a node :param node: the node to be polished :type node: :class:`libcloud.compute.base.Node` :param settings: the fittings plan for this node :type settings: ``dict`` :param container: the container of this node :type container: :class:`plumbery.PlumberyInfrastructure` :return: a list of actions to be performed, and related descriptions :rtype: a ``list`` of `{ 'description': ..., 'genius': ... }`` """ if not isinstance(settings, dict): return [] environment = PlumberyNodeContext(node=node, container=container, context=self.facility) prepares = [] for key_file in self.key_files: try: path = os.path.expanduser(key_file) with open(path) as stream: key = stream.read() stream.close() prepares.append({ 'description': 'deploy SSH public key', 'genius': SSHKeyDeployment(key=key) }) except IOError: plogging.warning("no ssh key in {}".format(key_file)) if ('prepare' in settings and isinstance(settings['prepare'], list) and len(settings['prepare']) > 0): plogging.info('- using prepare commands') for script in settings['prepare']: tokens = script.split(' ') if len(tokens) == 1: tokens.insert(0, 'run') if tokens[0] in ['run', 'run_raw']: # send and run a script script = tokens[1] if len(tokens) > 2: args = tokens[2:] else: args = [] plogging.debug("- {} {} {}".format(tokens[0], script, ' '.join(args))) try: with open(script) as stream: text = stream.read() if (tokens[0] == 'run' and PlumberyText.could_expand(text)): plogging.debug( "- expanding script '{}'".format(script)) text = PlumberyText.expand_string( text, environment) if len(text) > 0: plogging.info("- running '{}'".format(script)) prepares.append({ 'description': ' '.join(tokens), 'genius': ScriptDeployment(script=text, args=args, name=script) }) else: plogging.error( "- script '{}' is empty".format(script)) except IOError: plogging.error( "- unable to read script '{}'".format(script)) elif tokens[0] in ['put', 'put_raw']: # send a file file = tokens[1] if len(tokens) > 2: destination = tokens[2] else: destination = './' + file plogging.debug("- {} {} {}".format(tokens[0], file, destination)) try: with open(file) as stream: content = stream.read() if (tokens[0] == 'put' and PlumberyText.could_expand(content)): plogging.debug( "- expanding file '{}'".format(file)) content = PlumberyText.expand_string( content, environment) plogging.info("- putting file '{}'".format(file)) prepares.append({ 'description': ' '.join(tokens), 'genius': FileContentDeployment(content=content, target=destination) }) except IOError: plogging.error( "- unable to read file '{}'".format(file)) else: # echo a sensible message eventually if tokens[0] == 'echo': tokens.pop(0) message = ' '.join(tokens) message = PlumberyText.expand_string(message, environment) plogging.info("- {}".format(message)) if ('cloud-config' in settings and isinstance(settings['cloud-config'], dict) and len(settings['cloud-config']) > 0): plogging.info('- using cloud-config') # mandatory, else cloud-init will not consider user-data plogging.debug('- preparing meta-data') meta_data = 'instance_id: dummy\n' destination = '/var/lib/cloud/seed/nocloud-net/meta-data' prepares.append({ 'description': 'put meta-data', 'genius': FileContentDeployment(content=meta_data, target=destination) }) plogging.debug('- preparing user-data') expanded = PlumberyText.expand_string(settings['cloud-config'], environment) user_data = '#cloud-config\n' + expanded plogging.debug(user_data) destination = '/var/lib/cloud/seed/nocloud-net/user-data' prepares.append({ 'description': 'put user-data', 'genius': FileContentDeployment(content=user_data, target=destination) }) plogging.debug('- preparing remote install of cloud-init') script = 'prepare.cloud-init.sh' try: path = os.path.dirname(__file__) + '/' + script with open(path) as stream: text = stream.read() if text: prepares.append({ 'description': 'run ' + script, 'genius': ScriptDeployment(script=text, name=script) }) except IOError: raise PlumberyException( "Error: cannot read '{}'".format(script)) plogging.debug('- preparing reboot to trigger cloud-init') prepares.append({ 'description': 'reboot node', 'genius': RebootDeployment(container=container) }) return prepares
def _apply_prepares(self, node, steps): """ Does the actual job over SSH :param node: the node to be polished :type node: :class:`libcloud.compute.base.Node` :param steps: the various steps of the preparing :type steps: ``list`` of ``dict`` :return: ``True`` if everything went fine, ``False`` otherwise :rtype: ``bool`` """ if node is None or node.state != NodeState.RUNNING: plogging.warning("- skipped - node is not running") return False # select the address to use if len(node.public_ips) > 0: target_ip = node.public_ips[0] elif node.extra['ipv6']: target_ip = node.extra['ipv6'] else: target_ip = node.private_ips[0] # use libcloud to communicate with remote nodes session = SSHClient(hostname=target_ip, port=22, username=self.user, password=self.secret, key_files=self.key_files, timeout=10) repeats = 0 while True: try: session.connect() break except Exception as feedback: repeats += 1 if repeats > 5: plogging.error( "Error: can not connect to '{}'!".format(target_ip)) plogging.error("- failed to connect") return False plogging.debug(str(feedback)) plogging.debug( "- connection {} failed, retrying".format(repeats)) time.sleep(10) continue while True: try: if self.engine.safeMode: plogging.info( "- skipped - no ssh interaction in safe mode") else: for step in steps: plogging.info('- {}'.format(step['description'])) step['genius'].run(node, session) except Exception as feedback: if 'RESOURCE_BUSY' in str(feedback): time.sleep(10) continue plogging.error("Error: unable to prepare '{}' at '{}'!".format( node.name, target_ip)) plogging.error(str(feedback)) plogging.error("- failed") result = False else: result = True break try: session.close() except: pass return result
def _apply_prepares(self, node, steps): """ Does the actual job over SSH :param node: the node to be polished :type node: :class:`libcloud.compute.base.Node` :param steps: the various steps of the preparing :type steps: :class:`libcloud.compute.deployment.MultiStepDeployment` :return: ``True`` if everything went fine, ``False`` otherwise :rtype: ``bool`` """ if node is None or node.state != NodeState.RUNNING: plogging.warning("- skipped - node is not running") return False # select the address to use if len(node.public_ips) > 0: target_ip = node.public_ips[0] elif node.extra['ipv6']: target_ip = node.extra['ipv6'] else: target_ip = node.private_ips[0] # guess location of user key path = os.path.expanduser('~/.ssh/id_rsa') # use libcloud to communicate with remote nodes session = SSHClient(hostname=target_ip, port=22, username=self.user, password=self.secret, key_files=path, timeout=9) try: session.connect() except Exception as feedback: plogging.error("Error: unable to prepare '{}' at '{}'!".format( node.name, target_ip)) plogging.error(str(feedback)) plogging.error("- failed") return False while True: try: if self.engine.safeMode: plogging.info( "- skipped - no ssh interaction in safe mode") else: node = steps.run(node, session) except Exception as feedback: if 'RESOURCE_BUSY' in str(feedback): time.sleep(10) continue plogging.error("Error: unable to prepare '{}' at '{}'!".format( node.name, target_ip)) plogging.error(str(feedback)) plogging.error("- failed") result = False else: result = True break try: session.close() except: pass return result
def configure(self, node, settings): """ prepares a node :param node: the node to be polished :type node: :class:`libcloud.compute.base.Node` :param settings: the fittings plan for this node :type settings: ``dict`` :param container: the container of this node :type container: :class:`plumbery.PlumberyInfrastructure` """ if self._element_name_ in settings: plogging.info("preparing node '{}'".format(settings['name'])) if node is None: plogging.info("- not found") return timeout = 300 tick = 6 while node.extra['status'].action == 'START_SERVER': time.sleep(tick) node = self.nodes.get_node(node.name) timeout -= tick if timeout < 0: break if node.state != NodeState.RUNNING: plogging.info("- skipped - node is not running") return ipv6 = node.extra['ipv6'] ip = node.private_ips[0] if ipv6 is None: plogging.error('No ipv6 address for node, cannot configure') return # Check to see if WinRM works.. try: self._try_winrm(node) except winrm.exceptions.InvalidCredentialsError: plogging.warn('initial login to %s failed, trying to setup winrm remotely', ip) self._setup_winrm(node) self._try_winrm(node) except requests.exceptions.ConnectionError: plogging.warn('initial connection to %s failed, trying to setup winrm remotely', ip) self._setup_winrm(node) self._try_winrm(node) # OK, we're all ready. Let's look at the node config and start commands cmds = [] hostname = settings[self._element_name_].get('hostname', None) if hostname is not None and isinstance(hostname, str): cmds.append(('powershell.exe', ['Rename-Computer', '-NewName', hostname])) extra_cmds = settings[self._element_name_].get('cmds', []) for command in extra_cmds: command = command.rstrip() command_parts = command.split(' ') cmds.append((command_parts[0], command_parts[1:])) out, err = self._winrm_commands(node, cmds) plogging.info(out) plogging.warning(err) plogging.debug('locking down winrm') self._lockdown_winrm(node) else: return False