def test_run_without_inspection_and_apiurl(self, mock_list_hardware, mock_make_server, mock_dispatch, mock_inspector, mock_wait): # If both api_url and inspection_callback_url are not configured when # the agent starts, ensure that the inspection will be skipped and wsgi # server will work as usual. Also, make sure api_client and heartbeater # will not be initialized in this case. CONF.set_override('inspection_callback_url', None, enforce_type=True) self.agent = agent.IronicPythonAgent(None, agent.Host('203.0.113.1', 9990), agent.Host('192.0.2.1', 9999), 3, 10, 'eth0', 300, 1, False) self.assertFalse(hasattr(self.agent, 'api_client')) self.assertFalse(hasattr(self.agent, 'heartbeater')) wsgi_server = mock_make_server.return_value wsgi_server.start.side_effect = KeyboardInterrupt() self.agent.run() listen_addr = agent.Host('192.0.2.1', 9999) mock_make_server.assert_called_once_with( listen_addr.hostname, listen_addr.port, self.agent.api, server_class=simple_server.WSGIServer) wsgi_server.serve_forever.assert_called_once_with() self.assertFalse(mock_inspector.called) self.assertFalse(mock_wait.called) self.assertFalse(mock_dispatch.called)
def setUp(self): super(TestAgentStandalone, self).setUp() self.agent = agent.IronicPythonAgent( 'https://fake_api.example.' 'org:8081/', agent.Host(hostname='203.0.113.1', port=9990), agent.Host(hostname='192.0.2.1', port=9999), 3, 10, 'eth0', 300, 1, 'agent_ipmitool', True)
def run(): """Entrypoint for IronicPythonAgent.""" # NOTE(dtantsur): this must happen very early of the files from # /etc/ironic-python-agent.d won't be loaded utils.copy_config_from_vmedia() log.register_options(CONF) CONF(args=sys.argv[1:]) # Debug option comes from oslo.log, allow overriding it via kernel cmdline ipa_debug = config.APARAMS.get('ipa-debug') if ipa_debug is not None: ipa_debug = strutils.bool_from_string(ipa_debug) CONF.set_override('debug', ipa_debug) log.setup(CONF, 'ironic-python-agent') # Used for TLS configuration sslutils.register_opts(CONF) logger = log.getLogger(__name__) logger.debug("Configuration:") CONF.log_opt_values(logger, log.DEBUG) utils.log_early_log_to_logger() agent.IronicPythonAgent( CONF.api_url, agent.Host(hostname=CONF.advertise_host, port=CONF.advertise_port), agent.Host(hostname=CONF.listen_host, port=CONF.listen_port), CONF.ip_lookup_attempts, CONF.ip_lookup_sleep, CONF.network_interface, CONF.lookup_timeout, CONF.lookup_interval, False, CONF.agent_token, CONF.hardware_initialization_delay, CONF.advertise_protocol).run()
def test_run_without_inspection_and_apiurl(self, mock_list_hardware, mock_wsgi, mock_dispatch, mock_inspector, mock_wait): # If both api_url and inspection_callback_url are not configured when # the agent starts, ensure that the inspection will be skipped and wsgi # server will work as usual. Also, make sure api_client and heartbeater # will not be initialized in this case. CONF.set_override('inspection_callback_url', None) self.agent = agent.IronicPythonAgent(None, agent.Host('203.0.113.1', 9990), agent.Host('192.0.2.1', 9999), 3, 10, 'eth0', 300, 1, False) self.assertFalse(hasattr(self.agent, 'api_client')) self.assertFalse(hasattr(self.agent, 'heartbeater')) def set_serve_api(): self.agent.serve_api = False wsgi_server = mock_wsgi.return_value wsgi_server.handle_request.side_effect = set_serve_api self.agent.run() listen_addr = agent.Host('192.0.2.1', 9999) mock_wsgi.assert_called_once_with( (listen_addr.hostname, listen_addr.port), simple_server.WSGIRequestHandler) self.assertTrue(wsgi_server.handle_request.called) self.assertFalse(mock_inspector.called) self.assertFalse(mock_wait.called) self.assertFalse(mock_dispatch.called)
def setUp(self): super(TestAdvertiseAddress, self).setUp() self.agent = agent.IronicPythonAgent( api_url='https://fake_api.example.org:8081/', advertise_address=agent.Host(None, 9990), listen_address=agent.Host('0.0.0.0', 9999), ip_lookup_attempts=5, ip_lookup_sleep=10, network_interface=None, lookup_timeout=300, lookup_interval=1, standalone=False)
def test_url_from_mdns_explicitly(self, mock_get_managers, mock_wsgi, mock_wait, mock_dispatch, mock_mdns): CONF.set_override('inspection_callback_url', '') CONF.set_override('disk_wait_attempts', 0) mock_mdns.return_value = 'https://example.com', { # configuration via mdns 'ipa_disk_wait_attempts': '42', } wsgi_server = mock_wsgi.return_value self.agent = agent.IronicPythonAgent('mdns', agent.Host('203.0.113.1', 9990), agent.Host('192.0.2.1', 9999), 3, 10, 'eth0', 300, 1, False, None) def set_serve_api(): self.agent.serve_api = False wsgi_server.start.side_effect = set_serve_api self.agent.heartbeater = mock.Mock() self.agent.api_client.lookup_node = mock.Mock() self.agent.api_client.lookup_node.return_value = { 'node': { 'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c' }, 'config': { 'heartbeat_timeout': 300 } } self.agent.run() mock_wsgi.assert_called_once_with(CONF, 'ironic-python-agent', app=self.agent.api, host=mock.ANY, port=9999, use_ssl=False) wsgi_server.start.assert_called_once_with() mock_wait.assert_called_once_with(mock.ANY) self.assertEqual([mock.call('list_hardware_info'), mock.call('wait_for_disks')], mock_dispatch.call_args_list) self.agent.heartbeater.start.assert_called_once_with() # changed via mdns self.assertEqual(42, CONF.disk_wait_attempts)
def setUp(self): super(TestBaseAgent, self).setUp() self.encoder = encoding.RESTJSONEncoder(indent=4) self.agent = agent.IronicPythonAgent( 'https://fake_api.example.' 'org:8081/', agent.Host('203.0.113.1', 9990), agent.Host('192.0.2.1', 9999), 3, 10, 'eth0', 300, 1, False) self.agent.ext_mgr = extension.ExtensionManager.\ make_test_instance([extension.Extension('fake', None, FakeExtension, FakeExtension())]) self.sample_nw_iface = hardware.NetworkInterface( "eth9", "AA:BB:CC:DD:EE:FF", "1.2.3.4", True)
def test_run_raise_exception(self, mock_load_managers, mock_wsgi, mock_dispatch, mock_wait): CONF.set_override('inspection_callback_url', '') wsgi_server = mock_wsgi.return_value wsgi_server.handle_request.side_effect = KeyboardInterrupt() self.agent.heartbeater = mock.Mock() self.agent.api_client.lookup_node = mock.Mock() self.agent.api_client.lookup_node.return_value = { 'node': { 'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c' }, 'config': { 'heartbeat_timeout': 300 } } self.assertRaisesRegex(errors.IronicAPIError, 'Failed due to an unknown exception.', self.agent.run) self.assertTrue(mock_wait.called) self.assertEqual( [mock.call('list_hardware_info'), mock.call('wait_for_disks')], mock_dispatch.call_args_list) listen_addr = agent.Host('192.0.2.1', 9999) mock_wsgi.assert_called_once_with( (listen_addr.hostname, listen_addr.port), simple_server.WSGIRequestHandler) wsgi_server.set_app.assert_called_once_with(self.agent.api) self.assertTrue(wsgi_server.handle_request.called) self.agent.heartbeater.start.assert_called_once_with() self.assertTrue(wsgi_server.handle_request.called)
def test_run_with_sleep(self, mock_make_server, mock_dispatch, mock_wait, mock_sleep, mock_load_managers): CONF.set_override('inspection_callback_url', '') def set_serve_api(): self.agent.serve_api = False wsgi_server = mock_make_server.return_value wsgi_server.handle_request.side_effect = set_serve_api self.agent.hardware_initialization_delay = 10 self.agent.heartbeater = mock.Mock() self.agent.api_client.lookup_node = mock.Mock() self.agent.api_client.lookup_node.return_value = { 'node': { 'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c' }, 'config': { 'heartbeat_timeout': 300 } } self.agent.run() listen_addr = agent.Host('192.0.2.1', 9999) mock_make_server.assert_called_once_with( (listen_addr.hostname, listen_addr.port), simple_server.WSGIRequestHandler) self.agent.heartbeater.start.assert_called_once_with() mock_sleep.assert_called_once_with(10) self.assertTrue(mock_load_managers.called) self.assertTrue(mock_wait.called) self.assertEqual( [mock.call('list_hardware_info'), mock.call('wait_for_disks')], mock_dispatch.call_args_list)
def test_run(self, mock_load_managers, mock_list_hardware, mock_wsgi, mock_make_server): wsgi_server = mock_make_server.return_value wsgi_server.start.side_effect = KeyboardInterrupt() wsgi_server_request = mock_wsgi.return_value def set_serve_api(): self.agent.serve_api = False wsgi_server_request.handle_request.side_effect = set_serve_api self.agent.heartbeater = mock.Mock() self.agent.api_client.lookup_node = mock.Mock() self.agent.run() self.assertTrue(mock_load_managers.called) listen_addr = agent.Host('192.0.2.1', 9999) mock_wsgi.assert_called_once_with( (listen_addr.hostname, listen_addr.port), simple_server.WSGIRequestHandler) wsgi_server_request.set_app.assert_called_once_with(self.agent.api) self.assertTrue(wsgi_server_request.handle_request.called) self.assertFalse(self.agent.heartbeater.called) self.assertFalse(self.agent.api_client.lookup_node.called)
def test_run(self, mock_list_hardware, mock_make_server): wsgi_server = mock_make_server.return_value wsgi_server.start.side_effect = KeyboardInterrupt() self.agent.heartbeater = mock.Mock() self.agent.api_client.lookup_node = mock.Mock() self.agent.api_client.lookup_node.return_value = { 'node': { 'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c' }, 'config': { 'heartbeat_timeout': 300 } } self.agent.run() listen_addr = agent.Host('192.0.2.1', 9999) mock_make_server.assert_called_once_with( listen_addr.hostname, listen_addr.port, self.agent.api, server_class=simple_server.WSGIServer) wsgi_server.serve_forever.assert_called_once_with() self.assertFalse(self.agent.heartbeater.called) self.assertFalse(self.agent.api_client.lookup_node.called)
def test_run_with_sleep(self, mock_make_server, mock_dispatch, mock_load_managers, mock_sleep, mock_wait): CONF.set_override('inspection_callback_url', '', enforce_type=True) wsgi_server = mock_make_server.return_value wsgi_server.start.side_effect = KeyboardInterrupt() self.agent.hardware_initialization_delay = 10 self.agent.heartbeater = mock.Mock() self.agent.api_client.lookup_node = mock.Mock() self.agent.api_client.lookup_node.return_value = { 'node': { 'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c' }, 'config': { 'heartbeat_timeout': 300 } } self.agent.run() listen_addr = agent.Host('192.0.2.1', 9999) mock_make_server.assert_called_once_with( listen_addr.hostname, listen_addr.port, self.agent.api, server_class=simple_server.WSGIServer) wsgi_server.serve_forever.assert_called_once_with() self.agent.heartbeater.start.assert_called_once_with() mock_sleep.assert_called_once_with(10) self.assertTrue(mock_load_managers.called) self.assertTrue(mock_wait.called) mock_dispatch.assert_called_once_with('list_hardware_info')
def run(): """Entrypoint for IronicPythonAgent.""" log.register_options(CONF) CONF(args=sys.argv[1:]) # Debug option comes from oslo.log, allow overriding it via kernel cmdline ipa_debug = config.APARAMS.get('ipa-debug') if ipa_debug is not None: ipa_debug = strutils.bool_from_string(ipa_debug) CONF.set_override('debug', ipa_debug) log.setup(CONF, 'ironic-python-agent') agent.IronicPythonAgent( CONF.api_url, agent.Host(hostname=CONF.advertise_host, port=CONF.advertise_port), agent.Host(hostname=CONF.listen_host, port=CONF.listen_port), CONF.ip_lookup_attempts, CONF.ip_lookup_sleep, CONF.network_interface, CONF.lookup_timeout, CONF.lookup_interval, CONF.driver_name, CONF.standalone, CONF.hardware_initialization_delay).run()
def test_advertise_address_provided(self, mock_exec, mock_gethostbyname): self.agent.advertise_address = agent.Host('1.2.3.4', 9990) self.agent.set_agent_advertise_addr() self.assertEqual(('1.2.3.4', 9990), self.agent.advertise_address) self.assertFalse(mock_exec.called) self.assertFalse(mock_gethostbyname.called)
def test_run_with_inspection_without_apiurl(self, mock_list_hardware, mock_wsgi, mock_dispatch, mock_inspector, mock_wait, mock_mdns): mock_mdns.side_effect = lib_exc.ServiceLookupFailure() # If inspection_callback_url is configured and api_url is not when the # agent starts, ensure that the inspection will be called and wsgi # server will work as usual. Also, make sure api_client and heartbeater # will not be initialized in this case. CONF.set_override('inspection_callback_url', 'http://foo/bar') self.agent = agent.IronicPythonAgent(None, agent.Host('203.0.113.1', 9990), agent.Host('192.0.2.1', 9999), 3, 10, 'eth0', 300, 1, False, None) self.assertFalse(hasattr(self.agent, 'api_client')) self.assertFalse(hasattr(self.agent, 'heartbeater')) def set_serve_api(): self.agent.serve_api = False wsgi_server = mock_wsgi.return_value wsgi_server.start.side_effect = set_serve_api self.agent.run() mock_wsgi.assert_called_once_with(CONF, 'ironic-python-agent', app=self.agent.api, host=mock.ANY, port=9999, use_ssl=False) wsgi_server.start.assert_called_once_with() mock_inspector.assert_called_once_with() self.assertTrue(mock_wait.called) self.assertFalse(mock_dispatch.called)
def test_with_network_interface(self, mock_get_ipv4, mock_exec, mock_gethostbyname): self.agent.network_interface = 'em1' mock_get_ipv4.return_value = '1.2.3.4' self.agent.set_agent_advertise_addr() self.assertEqual(agent.Host('1.2.3.4', 9990), self.agent.advertise_address) mock_get_ipv4.assert_called_once_with(mock.ANY, 'em1') self.assertFalse(mock_exec.called) self.assertFalse(mock_gethostbyname.called)
def test_url_from_mdns_by_default(self, mock_load_managers, mock_wsgi, mock_wait, mock_dispatch, mock_mdns): CONF.set_override('inspection_callback_url', '') mock_mdns.return_value = 'https://example.com', {} wsgi_server = mock_wsgi.return_value self.agent = agent.IronicPythonAgent(None, agent.Host('203.0.113.1', 9990), agent.Host('192.0.2.1', 9999), 3, 10, 'eth0', 300, 1, False) def set_serve_api(): self.agent.serve_api = False wsgi_server.handle_request.side_effect = set_serve_api self.agent.heartbeater = mock.Mock() self.agent.api_client.lookup_node = mock.Mock() self.agent.api_client.lookup_node.return_value = { 'node': { 'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c' }, 'config': { 'heartbeat_timeout': 300 } } self.agent.run() listen_addr = agent.Host('192.0.2.1', 9999) mock_wsgi.assert_called_once_with( (listen_addr.hostname, listen_addr.port), simple_server.WSGIRequestHandler) wsgi_server.set_app.assert_called_once_with(self.agent.api) self.assertTrue(wsgi_server.handle_request.called) mock_wait.assert_called_once_with(mock.ANY) self.assertEqual( [mock.call('list_hardware_info'), mock.call('wait_for_disks')], mock_dispatch.call_args_list) self.agent.heartbeater.start.assert_called_once_with()
def setUp(self): """Start the agent and wait for it to start""" super(FunctionalBase, self).setUp() mpl = multiprocessing.log_to_stderr() mpl.setLevel(logging.INFO) self.test_port = os.environ.get('TEST_PORT', '9999') # Build a basic standalone agent using the config option defaults. # 127.0.0.1:6835 is the fake Ironic client. self.agent = agent.IronicPythonAgent( api_url='http://127.0.0.1:6835', advertise_address=agent.Host('localhost', 9999), listen_address=agent.Host(netutils.get_wildcard_address(), int(self.test_port)), ip_lookup_attempts=3, ip_lookup_sleep=10, network_interface=None, lookup_timeout=300, lookup_interval=1, standalone=True, agent_token=None) self.process = multiprocessing.Process(target=self.agent.run) self.process.start() self.addCleanup(self.process.terminate) # Wait for process to start, otherwise we have a race for tests sleep_time = 0.1 tries = 0 max_tries = int(os.environ.get('IPA_WAIT_TRIES', '100')) while tries < max_tries: try: return self.request('get', 'commands') except requests.ConnectionError: time.sleep(sleep_time) tries += 1 raise IOError('Agent did not start after %s seconds.' % (max_tries * sleep_time))
def test_run_with_inspection(self, mock_list_hardware, mock_wsgi, mock_dispatch, mock_inspector, mock_wait): CONF.set_override('inspection_callback_url', 'http://foo/bar') def set_serve_api(): self.agent.serve_api = False wsgi_server = mock_wsgi.return_value wsgi_server.handle_request.side_effect = set_serve_api mock_inspector.return_value = 'uuid' self.agent.heartbeater = mock.Mock() self.agent.api_client.lookup_node = mock.Mock() self.agent.api_client.lookup_node.return_value = { 'node': { 'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c' }, 'config': { 'heartbeat_timeout': 300, } } self.agent.run() listen_addr = agent.Host('192.0.2.1', 9999) mock_wsgi.assert_called_once_with( (listen_addr.hostname, listen_addr.port), simple_server.WSGIRequestHandler) self.assertTrue(mock_wsgi.called) mock_inspector.assert_called_once_with() self.assertEqual(1, self.agent.api_client.lookup_node.call_count) self.assertEqual( 'uuid', self.agent.api_client.lookup_node.call_args[1]['node_uuid']) mock_wait.assert_called_once_with(mock.ANY) self.assertEqual( [mock.call('list_hardware_info'), mock.call('wait_for_disks')], mock_dispatch.call_args_list) self.agent.heartbeater.start.assert_called_once_with()
def test_run_with_inspection(self, mocked_list_hardware, wsgi_server_cls, mocked_dispatch, mocked_inspector, mocked_wait): CONF.set_override('inspection_callback_url', 'http://foo/bar', enforce_type=True) wsgi_server = wsgi_server_cls.return_value wsgi_server.start.side_effect = KeyboardInterrupt() mocked_inspector.return_value = 'uuid' self.agent.heartbeater = mock.Mock() self.agent.api_client.lookup_node = mock.Mock() self.agent.api_client.lookup_node.return_value = { 'node': { 'uuid': 'deadbeef-dabb-ad00-b105-f00d00bab10c' }, 'config': { 'heartbeat_timeout': 300, } } self.agent.run() listen_addr = agent.Host('192.0.2.1', 9999) wsgi_server_cls.assert_called_once_with( listen_addr.hostname, listen_addr.port, self.agent.api, server_class=simple_server.WSGIServer) wsgi_server.serve_forever.assert_called_once_with() mocked_inspector.assert_called_once_with() self.assertEqual(1, self.agent.api_client.lookup_node.call_count) self.assertEqual( 'uuid', self.agent.api_client.lookup_node.call_args[1]['node_uuid']) mocked_wait.assert_called_once_with() mocked_dispatch.assert_called_once_with("list_hardware_info") self.agent.heartbeater.start.assert_called_once_with()