def get_clean_steps(self, node, ports): """Get the list of clean steps supported for the node and ports :param node: A dict representation of a node :param ports: A dict representation of ports attached to node :returns: A list of clean steps with keys step, priority, and reboot_requested """ LOG.debug( 'Getting clean steps, called with node: %(node)s, ' 'ports: %(ports)s', { 'node': node, 'ports': ports }) hardware.cache_node(node) # Results should be a dict, not a list candidate_steps = hardware.dispatch_to_all_managers( 'get_clean_steps', node, ports) LOG.debug('Clean steps before deduplication: %s', candidate_steps) clean_steps = hardware.deduplicate_steps(candidate_steps) LOG.debug('Returning clean steps: %s', clean_steps) return { 'clean_steps': clean_steps, 'hardware_manager_version': hardware.get_current_versions(), }
def run(self): """Run the Ironic Python Agent.""" # Get the UUID so we can heartbeat to Ironic. Raises LookupNodeError # if there is an issue (uncaught, restart agent) self.started_at = _time() # Cached hw managers at runtime, not load time. See bug 1490008. hardware.load_managers() # Operator-settable delay before hardware actually comes up. # Helps with slow RAID drivers - see bug 1582797. if self.hardware_initialization_delay > 0: LOG.info('Waiting %d seconds before proceeding', self.hardware_initialization_delay) time.sleep(self.hardware_initialization_delay) if not self.standalone: # Inspection should be started before call to lookup, otherwise # lookup will fail due to unknown MAC. uuid = inspector.inspect() self._wait_for_interface() content = self.api_client.lookup_node( hardware_info=hardware.dispatch_to_managers( 'list_hardware_info'), timeout=self.lookup_timeout, starting_interval=self.lookup_interval, node_uuid=uuid) LOG.debug('Received lookup results: %s', content) self.node = content['node'] LOG.info('Lookup succeeded, node UUID is %s', self.node['uuid']) hardware.cache_node(self.node) self.heartbeat_timeout = content['config']['heartbeat_timeout'] # Update config with values from Ironic config = content.get('config', {}) if config.get('metrics'): for opt, val in config.items(): setattr(cfg.CONF.metrics, opt, val) if config.get('metrics_statsd'): for opt, val in config.items(): setattr(cfg.CONF.metrics_statsd, opt, val) wsgi = simple_server.make_server(self.listen_address.hostname, self.listen_address.port, self.api, server_class=simple_server.WSGIServer) if not self.standalone: # Don't start heartbeating until the server is listening self.heartbeater.start() try: wsgi.serve_forever() except BaseException: LOG.exception('shutting down') if not self.standalone: self.heartbeater.stop()
def run(self): """Run the Ironic Python Agent.""" # Get the UUID so we can heartbeat to Ironic. Raises LookupNodeError # if there is an issue (uncaught, restart agent) self.started_at = _time() # Cached hw managers at runtime, not load time. See bug 1490008. hardware.load_managers() # Operator-settable delay before hardware actually comes up. # Helps with slow RAID drivers - see bug 1582797. if self.hardware_initialization_delay > 0: LOG.info('Waiting %d seconds before proceeding', self.hardware_initialization_delay) time.sleep(self.hardware_initialization_delay) if not self.standalone: # Inspection should be started before call to lookup, otherwise # lookup will fail due to unknown MAC. uuid = None if cfg.CONF.inspection_callback_url: uuid = inspector.inspect() if self.api_url: self._wait_for_interface() content = self.api_client.lookup_node( hardware_info=hardware.dispatch_to_managers( 'list_hardware_info'), timeout=self.lookup_timeout, starting_interval=self.lookup_interval, node_uuid=uuid) LOG.debug('Received lookup results: %s', content) self.node = content['node'] LOG.info('Lookup succeeded, node UUID is %s', self.node['uuid']) hardware.cache_node(self.node) self.heartbeat_timeout = content['config']['heartbeat_timeout'] # Update config with values from Ironic config = content.get('config', {}) if config.get('metrics'): for opt, val in config.items(): setattr(cfg.CONF.metrics, opt, val) if config.get('metrics_statsd'): for opt, val in config.items(): setattr(cfg.CONF.metrics_statsd, opt, val) elif cfg.CONF.inspection_callback_url: LOG.info('No ipa-api-url configured, Heartbeat and lookup ' 'skipped for inspector.') else: LOG.error('Neither ipa-api-url nor inspection_callback_url' 'found, please check your pxe append parameters.') self.serve_ipa_api() if not self.standalone and self.api_url: self.heartbeater.stop()
def run(self): """Run the Ironic Python Agent.""" # Get the UUID so we can heartbeat to Ironic. Raises LookupNodeError # if there is an issue (uncaught, restart agent) self.started_at = _time() # Cached hw managers at runtime, not load time. See bug 1490008. hardware.load_managers() # Operator-settable delay before hardware actually comes up. # Helps with slow RAID drivers - see bug 1582797. if self.hardware_initialization_delay > 0: LOG.info('Waiting %d seconds before proceeding', self.hardware_initialization_delay) time.sleep(self.hardware_initialization_delay) if not self.standalone: # Inspection should be started before call to lookup, otherwise # lookup will fail due to unknown MAC. uuid = None if cfg.CONF.inspection_callback_url: uuid = inspector.inspect() if self.api_url: self._wait_for_interface() content = self.api_client.lookup_node( hardware_info=hardware.dispatch_to_managers( 'list_hardware_info'), timeout=self.lookup_timeout, starting_interval=self.lookup_interval, node_uuid=uuid) LOG.debug('Received lookup results: %s', content) self.node = content['node'] LOG.info('Lookup succeeded, node UUID is %s', self.node['uuid']) hardware.cache_node(self.node) self.heartbeat_timeout = content['config']['heartbeat_timeout'] # Update config with values from Ironic config = content.get('config', {}) if config.get('metrics'): for opt, val in config.items(): setattr(cfg.CONF.metrics, opt, val) if config.get('metrics_statsd'): for opt, val in config.items(): setattr(cfg.CONF.metrics_statsd, opt, val) elif cfg.CONF.inspection_callback_url: LOG.info('No ipa-api-url configured, Heartbeat and lookup ' 'skipped for inspector.') else: LOG.error('Neither ipa-api-url nor inspection_callback_url' 'found, please check your pxe append parameters.') self.serve_ipa_api() if not self.standalone and self.api_url: self.heartbeater.stop()
def execute_deploy_step(self, step, node, ports, deploy_version=None, **kwargs): """Execute a deploy step. :param step: A deploy step with 'step', 'priority' and 'interface' keys :param node: A dict representation of a node :param ports: A dict representation of ports attached to node :param deploy_version: The deploy version as returned by hardware.get_current_versions() at the beginning of deploying. :param kwargs: The remaining arguments are passed to the step. :returns: a CommandResult object with command_result set to whatever the step returns. """ # Ensure the agent is still the same version, or raise an exception LOG.debug('Executing deploy step %s', step) hardware.cache_node(node) hardware.check_versions(deploy_version) if 'step' not in step: msg = 'Malformed deploy_step, no "step" key: %s' % step LOG.error(msg) raise ValueError(msg) kwargs.update(step.get('args') or {}) try: result = hardware.dispatch_to_managers(step['step'], node, ports, **kwargs) except Exception as e: msg = ('Error performing deploy_step %(step)s: %(err)s' % { 'step': step['step'], 'err': e }) LOG.exception(msg) raise errors.DeploymentError(msg) LOG.info('Deploy step completed: %(step)s, result: %(result)s', { 'step': step, 'result': result }) # Cast result tuples (like output of utils.execute) as lists, or # API throws errors if isinstance(result, tuple): result = list(result) # Return the step that was executed so we can dispatch # to the appropriate Ironic interface return {'deploy_result': result, 'deploy_step': step}
def execute_clean_step(self, step, node, ports, clean_version=None, **kwargs): """Execute a clean step. :param step: A clean step with 'step', 'priority' and 'interface' keys :param node: A dict representation of a node :param ports: A dict representation of ports attached to node :param clean_version: The clean version as returned by _get_current_clean_version() at the beginning of cleaning/zapping :returns: a CommandResult object with command_result set to whatever the step returns. """ # Ensure the agent is still the same version, or raise an exception LOG.debug('Executing clean step %s', step) hardware.cache_node(node) _check_clean_version(clean_version) if 'step' not in step: msg = 'Malformed clean_step, no "step" key: %s' % step LOG.error(msg) raise ValueError(msg) try: result = hardware.dispatch_to_managers(step['step'], node, ports) except Exception as e: msg = ('Error performing clean_step %(step)s: %(err)s' % { 'step': step['step'], 'err': e }) LOG.exception(msg) raise errors.CleaningError(msg) LOG.info('Clean step completed: %(step)s, result: %(result)s', { 'step': step, 'result': result }) # Cast result tuples (like output of utils.execute) as lists, or # WSME throws errors if isinstance(result, tuple): result = list(result) # Return the step that was executed so we can dispatch # to the appropriate Ironic interface return {'clean_result': result, 'clean_step': step}
def run(self): """Run the Ironic Python Agent.""" # Get the UUID so we can heartbeat to Ironic. Raises LookupNodeError # if there is an issue (uncaught, restart agent) self.started_at = _time() # Cached hw managers at runtime, not load time. See bug 1490008. hardware.load_managers() # Operator-settable delay before hardware actually comes up. # Helps with slow RAID drivers - see bug 1582797. if self.hardware_initialization_delay > 0: LOG.info('Waiting %d seconds before proceeding', self.hardware_initialization_delay) time.sleep(self.hardware_initialization_delay) if not self.standalone: # Inspection should be started before call to lookup, otherwise # lookup will fail due to unknown MAC. uuid = inspector.inspect() content = self.api_client.lookup_node( hardware_info=hardware.dispatch_to_managers( 'list_hardware_info'), timeout=self.lookup_timeout, starting_interval=self.lookup_interval, node_uuid=uuid) self.node = content['node'] hardware.cache_node(self.node) self.heartbeat_timeout = content['heartbeat_timeout'] wsgi = simple_server.make_server( self.listen_address[0], self.listen_address[1], self.api, server_class=simple_server.WSGIServer) if not self.standalone: # Don't start heartbeating until the server is listening self.heartbeater.start() try: wsgi.serve_forever() except BaseException: LOG.exception('shutting down') if not self.standalone: self.heartbeater.stop()
def run(self): """Run the Ironic Python Agent.""" # Get the UUID so we can heartbeat to Ironic. Raises LookupNodeError # if there is an issue (uncaught, restart agent) self.started_at = _time() # Cached hw managers at runtime, not load time. See bug 1490008. hardware.load_managers() # Operator-settable delay before hardware actually comes up. # Helps with slow RAID drivers - see bug 1582797. if self.hardware_initialization_delay > 0: LOG.info('Waiting %d seconds before proceeding', self.hardware_initialization_delay) time.sleep(self.hardware_initialization_delay) if not self.standalone: # Inspection should be started before call to lookup, otherwise # lookup will fail due to unknown MAC. uuid = inspector.inspect() content = self.api_client.lookup_node( hardware_info=hardware.dispatch_to_managers( 'list_hardware_info'), timeout=self.lookup_timeout, starting_interval=self.lookup_interval, node_uuid=uuid) self.node = content['node'] hardware.cache_node(self.node) self.heartbeat_timeout = content['heartbeat_timeout'] wsgi = simple_server.make_server(self.listen_address[0], self.listen_address[1], self.api, server_class=simple_server.WSGIServer) if not self.standalone: # Don't start heartbeating until the server is listening self.heartbeater.start() try: wsgi.serve_forever() except BaseException: LOG.exception('shutting down') if not self.standalone: self.heartbeater.stop()
def process_lookup_data(self, content): """Update agent configuration from lookup data.""" self.node = content['node'] LOG.info('Lookup succeeded, node UUID is %s', self.node['uuid']) hardware.cache_node(self.node) self.heartbeat_timeout = content['config']['heartbeat_timeout'] # Update config with values from Ironic config = content.get('config', {}) if config.get('metrics'): for opt, val in config.items(): setattr(cfg.CONF.metrics, opt, val) if config.get('metrics_statsd'): for opt, val in config.items(): setattr(cfg.CONF.metrics_statsd, opt, val) if config.get('agent_token_required'): self.agent_token_required = True token = config.get('agent_token') if token: if len(token) >= 32: LOG.debug('Agent token recorded as designated by ' 'the ironic installation.') self.agent_token = token # set with-in the API client. if not self.standalone: self.api_client.agent_token = token elif token == '******': LOG.warning('The agent token has already been ' 'retrieved. IPA may not operate as ' 'intended and the deployment may fail ' 'depending on settings in the ironic ' 'deployment.') if not self.agent_token and self.agent_token_required: LOG.error('Ironic is signaling that agent tokens ' 'are required, however we do not have ' 'a token on file. ' 'This is likely **FATAL**.') else: LOG.info('An invalid token was received.') if self.agent_token and not self.standalone: # Explicitly set the token in our API client before # starting heartbeat operations. self.api_client.agent_token = self.agent_token
def execute_clean_step(self, step, node, ports, clean_version=None, **kwargs): """Execute a clean step. :param step: A clean step with 'step', 'priority' and 'interface' keys :param node: A dict representation of a node :param ports: A dict representation of ports attached to node :param clean_version: The clean version as returned by _get_current_clean_version() at the beginning of cleaning/zapping :returns: a CommandResult object with command_result set to whatever the step returns. """ # Ensure the agent is still the same version, or raise an exception LOG.debug('Executing clean step %s', step) hardware.cache_node(node) _check_clean_version(clean_version) if 'step' not in step: msg = 'Malformed clean_step, no "step" key: %s' % step LOG.error(msg) raise ValueError(msg) try: result = hardware.dispatch_to_managers(step['step'], node, ports) except Exception as e: msg = ('Error performing clean_step %(step)s: %(err)s' % {'step': step['step'], 'err': e}) LOG.exception(msg) raise errors.CleaningError(msg) LOG.info('Clean step completed: %(step)s, result: %(result)s', {'step': step, 'result': result}) # Cast result tuples (like output of utils.execute) as lists, or # WSME throws errors if isinstance(result, tuple): result = list(result) # Return the step that was executed so we can dispatch # to the appropriate Ironic interface return { 'clean_result': result, 'clean_step': step }
def get_clean_steps(self, node, ports): """Get the list of clean steps supported for the node and ports :param node: A dict representation of a node :param ports: A dict representation of ports attached to node :returns: A list of clean steps with keys step, priority, and reboot_requested """ LOG.debug('Getting clean steps, called with node: %(node)s, ' 'ports: %(ports)s', {'node': node, 'ports': ports}) hardware.cache_node(node) # Results should be a dict, not a list candidate_steps = hardware.dispatch_to_all_managers('get_clean_steps', node, ports) LOG.debug('Clean steps before deduplication: %s', candidate_steps) clean_steps = _deduplicate_steps(candidate_steps) LOG.debug('Returning clean steps: %s', clean_steps) return { 'clean_steps': clean_steps, 'hardware_manager_version': _get_current_clean_version() }
def run(self): """Run the Ironic Python Agent.""" # Get the UUID so we can heartbeat to Ironic. Raises LookupNodeError # if there is an issue (uncaught, restart agent) self.started_at = _time() # Cached hw managers at runtime, not load time. See bug 1490008. hardware.load_managers() # Operator-settable delay before hardware actually comes up. # Helps with slow RAID drivers - see bug 1582797. if self.hardware_initialization_delay > 0: LOG.info('Waiting %d seconds before proceeding', self.hardware_initialization_delay) time.sleep(self.hardware_initialization_delay) if not self.standalone: # Inspection should be started before call to lookup, otherwise # lookup will fail due to unknown MAC. uuid = None if cfg.CONF.inspection_callback_url: uuid = inspector.inspect() if self.api_url: self._wait_for_interface() content = self.api_client.lookup_node( hardware_info=hardware.dispatch_to_managers( 'list_hardware_info'), timeout=self.lookup_timeout, starting_interval=self.lookup_interval, node_uuid=uuid) LOG.debug('Received lookup results: %s', content) self.node = content['node'] LOG.info('Lookup succeeded, node UUID is %s', self.node['uuid']) hardware.cache_node(self.node) self.heartbeat_timeout = content['config']['heartbeat_timeout'] # Update config with values from Ironic config = content.get('config', {}) if config.get('metrics'): for opt, val in config.items(): setattr(cfg.CONF.metrics, opt, val) if config.get('metrics_statsd'): for opt, val in config.items(): setattr(cfg.CONF.metrics_statsd, opt, val) elif cfg.CONF.inspection_callback_url: LOG.info('No ipa-api-url configured, Heartbeat and lookup ' 'skipped for inspector.') else: LOG.error('Neither ipa-api-url nor inspection_callback_url' 'found, please check your pxe append parameters.') if netutils.is_ipv6_enabled(): # Listens to both IP versions, assuming IPV6_V6ONLY isn't enabled, # (the default behaviour in linux) simple_server.WSGIServer.address_family = socket.AF_INET6 wsgi = simple_server.make_server( self.listen_address.hostname, self.listen_address.port, self.api, server_class=simple_server.WSGIServer) if not self.standalone and self.api_url: # Don't start heartbeating until the server is listening self.heartbeater.start() try: wsgi.serve_forever() except BaseException: LOG.exception('shutting down') if not self.standalone and self.api_url: self.heartbeater.stop()
def run(self): """Run the Ironic Python Agent.""" LOG.info('Starting ironic-python-agent version: %s', self.version) # Get the UUID so we can heartbeat to Ironic. Raises LookupNodeError # if there is an issue (uncaught, restart agent) self.started_at = _time() # Attempt to sync the software clock utils.sync_clock(ignore_errors=True) # Cached hw managers at runtime, not load time. See bug 1490008. hardware.get_managers() # Operator-settable delay before hardware actually comes up. # Helps with slow RAID drivers - see bug 1582797. if self.hardware_initialization_delay > 0: LOG.info('Waiting %d seconds before proceeding', self.hardware_initialization_delay) time.sleep(self.hardware_initialization_delay) if not self.standalone: # Inspection should be started before call to lookup, otherwise # lookup will fail due to unknown MAC. uuid = None if cfg.CONF.inspection_callback_url: try: # Attempt inspection. This may fail, and previously # an error would be logged. uuid = inspector.inspect() except errors.InspectionError as e: LOG.error('Failed to perform inspection: %s', e) if self.api_url: self._wait_for_interface() content = self.api_client.lookup_node( hardware_info=hardware.dispatch_to_managers( 'list_hardware_info'), timeout=self.lookup_timeout, starting_interval=self.lookup_interval, node_uuid=uuid) LOG.debug('Received lookup results: %s', content) self.node = content['node'] LOG.info('Lookup succeeded, node UUID is %s', self.node['uuid']) hardware.cache_node(self.node) self.heartbeat_timeout = content['config']['heartbeat_timeout'] # Update config with values from Ironic config = content.get('config', {}) if config.get('metrics'): for opt, val in config.items(): setattr(cfg.CONF.metrics, opt, val) if config.get('metrics_statsd'): for opt, val in config.items(): setattr(cfg.CONF.metrics_statsd, opt, val) if config.get('agent_token_required'): self.agent_token_required = True token = config.get('agent_token') if token: if len(token) >= 32: LOG.debug('Agent token recorded as designated by ' 'the ironic installation.') self.agent_token = token # set with-in the API client. self.api_client.agent_token = token elif token == '******': LOG.warning('The agent token has already been ' 'retrieved. IPA may not operate as ' 'intended and the deployment may fail ' 'depending on settings in the ironic ' 'deployment.') if not self.agent_token and self.agent_token_required: LOG.error('Ironic is signaling that agent tokens ' 'are required, however we do not have ' 'a token on file. ' 'This is likely **FATAL**.') else: LOG.info('An invalid token was received.') if self.agent_token: # Explicitly set the token in our API client before # starting heartbeat operations. self.api_client.agent_token = self.agent_token elif cfg.CONF.inspection_callback_url: LOG.info('No ipa-api-url configured, Heartbeat and lookup ' 'skipped for inspector.') else: LOG.error('Neither ipa-api-url nor inspection_callback_url' 'found, please check your pxe append parameters.') self.serve_ipa_api() if not self.standalone and self.api_url: self.heartbeater.stop()
def run(self): """Run the Ironic Python Agent.""" # Get the UUID so we can heartbeat to Ironic. Raises LookupNodeError # if there is an issue (uncaught, restart agent) self.started_at = _time() # Cached hw managers at runtime, not load time. See bug 1490008. hardware.load_managers() # Operator-settable delay before hardware actually comes up. # Helps with slow RAID drivers - see bug 1582797. if self.hardware_initialization_delay > 0: LOG.info('Waiting %d seconds before proceeding', self.hardware_initialization_delay) time.sleep(self.hardware_initialization_delay) if not self.standalone: # Inspection should be started before call to lookup, otherwise # lookup will fail due to unknown MAC. uuid = None if cfg.CONF.inspection_callback_url: uuid = inspector.inspect() if self.api_url: self._wait_for_interface() content = self.api_client.lookup_node( hardware_info=hardware.dispatch_to_managers( 'list_hardware_info'), timeout=self.lookup_timeout, starting_interval=self.lookup_interval, node_uuid=uuid) LOG.debug('Received lookup results: %s', content) self.node = content['node'] LOG.info('Lookup succeeded, node UUID is %s', self.node['uuid']) hardware.cache_node(self.node) self.heartbeat_timeout = content['config']['heartbeat_timeout'] # Update config with values from Ironic config = content.get('config', {}) if config.get('metrics'): for opt, val in config.items(): setattr(cfg.CONF.metrics, opt, val) if config.get('metrics_statsd'): for opt, val in config.items(): setattr(cfg.CONF.metrics_statsd, opt, val) elif cfg.CONF.inspection_callback_url: LOG.info('No ipa-api-url configured, Heartbeat and lookup ' 'skipped for inspector.') else: LOG.error('Neither ipa-api-url nor inspection_callback_url' 'found, please check your pxe append parameters.') if netutils.is_ipv6_enabled(): # Listens to both IP versions, assuming IPV6_V6ONLY isn't enabled, # (the default behaviour in linux) simple_server.WSGIServer.address_family = socket.AF_INET6 wsgi = simple_server.make_server( self.listen_address.hostname, self.listen_address.port, self.api, server_class=simple_server.WSGIServer) if not self.standalone and self.api_url: # Don't start heartbeating until the server is listening self.heartbeater.start() try: wsgi.serve_forever() except BaseException: LOG.exception('shutting down') if not self.standalone and self.api_url: self.heartbeater.stop()
def run(self): """Run the Ironic Python Agent.""" # Get the UUID so we can heartbeat to Ironic. Raises LookupNodeError # if there is an issue (uncaught, restart agent) self.started_at = _time() # Cached hw managers at runtime, not load time. See bug 1490008. hardware.load_managers() # Operator-settable delay before hardware actually comes up. # Helps with slow RAID drivers - see bug 1582797. if self.hardware_initialization_delay > 0: LOG.info('Waiting %d seconds before proceeding', self.hardware_initialization_delay) time.sleep(self.hardware_initialization_delay) if not self.standalone: # Inspection should be started before call to lookup, otherwise # lookup will fail due to unknown MAC. uuid = None # We can't try to inspect or heartbeat until we have valid # interfaces to perform those actions over. self._wait_for_interface() if cfg.CONF.inspection_callback_url: try: # Attempt inspection. This may fail, and previously # an error would be logged. uuid = inspector.inspect() except errors.InspectionError as e: LOG.error('Failed to perform inspection: %s', e) if self.api_url: content = self.api_client.lookup_node( hardware_info=hardware.list_hardware_info(use_cache=True), timeout=self.lookup_timeout, starting_interval=self.lookup_interval, node_uuid=uuid) LOG.debug('Received lookup results: %s', content) self.node = content['node'] LOG.info('Lookup succeeded, node UUID is %s', self.node['uuid']) hardware.cache_node(self.node) self.heartbeat_timeout = content['config']['heartbeat_timeout'] # Update config with values from Ironic config = content.get('config', {}) if config.get('metrics'): for opt, val in config.items(): setattr(cfg.CONF.metrics, opt, val) if config.get('metrics_statsd'): for opt, val in config.items(): setattr(cfg.CONF.metrics_statsd, opt, val) elif cfg.CONF.inspection_callback_url: LOG.info('No ipa-api-url configured, Heartbeat and lookup ' 'skipped for inspector.') else: # NOTE(TheJulia): Once communication flow capability is # able to be driven solely from the conductor, this is no # longer a major issue. LOG.error('Neither ipa-api-url nor inspection_callback_url' 'found, please check your pxe append parameters.') self.serve_ipa_api() if not self.standalone and self.api_url: self.heartbeater.stop()