def load_config(filename, path="calico/felix/test/data/", env_dict=None, host_dict=None, global_dict=None): if env_dict is None: env_dict = {} if host_dict is None: host_dict = {} if global_dict is None: global_dict = {} global_dict.setdefault("InterfacePrefix", "tap") with mock.patch.dict("os.environ", env_dict): with mock.patch('calico.common.complete_logging'): config = Config() combined_dict = global_dict.copy() combined_dict.update(host_dict) with mock.patch('calico.common.complete_logging'): config.update_from(combined_dict) return config
def test_default_config(self): """ Test various ways of defaulting config. """ files = [ "felix_missing.cfg", # does not exist "felix_empty.cfg", # empty file "felix_empty_section.cfg", # file with empty section "felix_extra.cfg", # extra config is just logged ] for filename in files: with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/%s" % filename) host_dict = {"InterfacePrefix": "blah", "MetadataPort": 123} global_dict = { "InterfacePrefix": "overridden", "MetadataAddr": "1.2.3.4" } with mock.patch('calico.common.complete_logging'): config.report_etcd_config(host_dict, global_dict) # Test defaulting. self.assertEqual(config.ETCD_ADDR, "localhost:4001") self.assertEqual(config.HOSTNAME, socket.gethostname()) self.assertEqual(config.IFACE_PREFIX, "blah") self.assertEqual(config.METADATA_PORT, 123) self.assertEqual(config.METADATA_IP, "1.2.3.4") self.assertEqual(config.REPORTING_INTERVAL_SECS, 30) self.assertEqual(config.REPORTING_TTL_SECS, 90)
def test_env_var_override(self): """ Test environment variables override config options, """ with mock.patch.dict("os.environ", {"FELIX_ETCDADDR": "9.9.9.9:1234", "FELIX_METADATAPORT": "999"}): config = Config("calico/felix/test/data/felix_section.cfg") host_dict = { "InterfacePrefix": "blah", "StartupCleanupDelay": "42", "MetadataAddr": "4.3.2.1", "MetadataPort": "123" } global_dict = { "InterfacePrefix": "blah", "StartupCleanupDelay": "99", "MetadataAddr": "5.4.3.2", "MetadataPort": "123" } with mock.patch('calico.common.complete_logging'): config.report_etcd_config(host_dict, global_dict) self.assertEqual(config.ETCD_ADDR, "9.9.9.9:1234") self.assertEqual(config.HOSTNAME, socket.gethostname()) self.assertEqual(config.LOGFILE, "/log/nowhere.log") self.assertEqual(config.IFACE_PREFIX, "whatever") self.assertEqual(config.METADATA_PORT, 999) self.assertEqual(config.METADATA_IP, "1.2.3.4") self.assertEqual(config.STARTUP_CLEANUP_DELAY, 42)
def test_ip_in_ip_enabled(self): test_values = [ ("true", True), ("t", True), ("True", True), ("1", True), (1, True), ("yes", True), ("y", True), ("false", False), ("f", False), ("False", False), ("0", False), (0, False), ("no", False), ("n", False), ] for value, expected in test_values: with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "IpInIpEnabled": value } config.report_etcd_config({}, cfg_dict) self.assertEqual(config.IP_IN_IP_ENABLED, expected, "%r was mis-interpreted as %r" % (value, config.IP_IN_IP_ENABLED))
def test_no_iface_prefix(self): with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = {} with self.assertRaisesRegexp(ConfigException, "Missing undefaulted value.*InterfacePrefix"): config.report_etcd_config({}, cfg_dict)
def test_default_config(self): """ Test various ways of defaulting config. """ files = [ "felix_missing.cfg", # does not exist "felix_empty.cfg", # empty file "felix_empty_section.cfg", # file with empty section "felix_extra.cfg", # extra config is just logged ] for filename in files: host = socket.gethostname() host_path = "/calico/host/%s/config/" % host config = Config("calico/felix/test/data/%s" % filename) cfg_dict = { "InterfacePrefix": "blah", "ExtraJunk": "whatever", #ignored "ResyncIntervalSecs": "123" } config.update_config(cfg_dict) # Test defaulting. self.assertEqual(config.ETCD_ADDR, "localhost:4001") self.assertEqual(config.HOSTNAME, host) self.assertEqual(config.IFACE_PREFIX, "blah") self.assertEqual(config.RESYNC_INT_SEC, 123)
def test_default_config(self): """ Test various ways of defaulting config. """ files = [ "felix_missing.cfg", # does not exist "felix_empty.cfg", # empty file "felix_empty_section.cfg", # file with empty section "felix_extra.cfg", # extra config is just logged ] for filename in files: config = Config("calico/felix/test/data/%s" % filename) host_dict = { "InterfacePrefix": "blah", "MetadataPort": 123 } global_dict = { "InterfacePrefix": "overridden", "MetadataAddr": "1.2.3.4" } with mock.patch('calico.common.complete_logging'): config.report_etcd_config(host_dict, global_dict) # Test defaulting. self.assertEqual(config.ETCD_ADDR, "localhost:4001") self.assertEqual(config.HOSTNAME, socket.gethostname()) self.assertEqual(config.IFACE_PREFIX, "blah") self.assertEqual(config.METADATA_PORT, 123) self.assertEqual(config.METADATA_IP, "1.2.3.4")
def test_env_var_override(self): """ Test environment variables override config options, """ with mock.patch.dict("os.environ", { "FELIX_ETCDADDR": "9.9.9.9:1234", "FELIX_METADATAPORT": "999" }): with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_section.cfg") host_dict = { "InterfacePrefix": "blah", "StartupCleanupDelay": "42", "MetadataAddr": "4.3.2.1", "MetadataPort": "123" } global_dict = { "InterfacePrefix": "blah", "StartupCleanupDelay": "99", "MetadataAddr": "5.4.3.2", "MetadataPort": "123" } with mock.patch('calico.common.complete_logging'): config.report_etcd_config(host_dict, global_dict) self.assertEqual(config.ETCD_ADDR, "9.9.9.9:1234") self.assertEqual(config.HOSTNAME, socket.gethostname()) self.assertEqual(config.LOGFILE, "/log/nowhere.log") self.assertEqual(config.IFACE_PREFIX, "whatever") self.assertEqual(config.METADATA_PORT, 999) self.assertEqual(config.METADATA_IP, "1.2.3.4") self.assertEqual(config.STARTUP_CLEANUP_DELAY, 42)
def test_no_iface_prefix(self): with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = {} with self.assertRaisesRegexp( ConfigException, "Missing undefaulted value.*InterfacePrefix"): config.report_etcd_config({}, cfg_dict)
def test_ip_in_ip_enabled(self): test_values = [ ("true", True), ("t", True), ("True", True), ("1", True), (1, True), ("yes", True), ("y", True), ("false", False), ("f", False), ("False", False), ("0", False), (0, False), ("no", False), ("n", False), ] for value, expected in test_values: with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = {"InterfacePrefix": "blah", "IpInIpEnabled": value} config.report_etcd_config({}, cfg_dict) self.assertEqual( config.IP_IN_IP_ENABLED, expected, "%r was mis-interpreted as %r" % (value, config.IP_IN_IP_ENABLED))
def test_blank_metadata_addr(self): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "MetadataAddr": "", "MetadataPort": "123" } with self.assertRaisesRegexp(ConfigException, "Blank value.*MetadataAddr"): config.report_etcd_config({}, cfg_dict)
def test_metadata_port_not_int(self): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "MetadataAddr": "127.0.0.1", "MetadataPort": "bloop" } with self.assertRaisesRegexp(ConfigException, "Field was not integer.*MetadataPort"): config.report_etcd_config({}, cfg_dict)
def test_ip_in_ip_enabled_bad(self): with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = {"InterfacePrefix": "blah", "IpInIpEnabled": "blah"} with self.assertRaisesRegexp( ConfigException, "Field was not a valid Boolean" ".*IpInIpEnabled"): config.report_etcd_config({}, cfg_dict)
def test_bad_log_level(self): for field in ("LogSeverityFile", "LogSeverityScreen", "LogSeveritySys"): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "LogInterfacePrefix": "blah", field: "bloop" } with self.assertRaisesRegexp(ConfigException, "Invalid log level.*%s" % field): config.report_etcd_config({}, cfg_dict)
def test_bad_metadata_addr(self): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "MetadataAddr": "bloop", "MetadataPort": "123" } with self.assertRaisesRegexp(ConfigException, "Invalid or unresolvable.*MetadataAddr"): config.report_etcd_config({}, cfg_dict) self.m_gethostbyname.assert_has_calls([mock.call("bloop")])
def test_no_logfile(self): # Logging to file can be excluded by explicitly saying "none" config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "LogFilePath": "None" } with mock.patch('calico.common.complete_logging'): config.report_etcd_config({}, cfg_dict) self.assertEqual(config.LOGFILE, None)
def test_ip_in_ip_enabled_bad(self): with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "IpInIpEnabled": "blah" } with self.assertRaisesRegexp(ConfigException, "Field was not a valid Boolean" ".*IpInIpEnabled"): config.report_etcd_config({}, cfg_dict)
def test_bad_log_level(self): for field in ("LogSeverityFile", "LogSeverityScreen", "LogSeveritySys"): with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = {"LogInterfacePrefix": "blah", field: "bloop"} with self.assertRaisesRegexp(ConfigException, "Invalid log level.*%s" % field): config.report_etcd_config({}, cfg_dict)
def test_metadata_port_not_valid_1(self): for i in (0, -1, 99999): log.debug("Test invalid metadata port %d", i) config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "MetadataAddr": "127.0.0.1", "MetadataPort": i } with self.assertRaisesRegexp(ConfigException, "Invalid field value.*MetadataPort"): config.report_etcd_config({}, cfg_dict)
def test_reporting_interval_not_int(self): """ Test exception is raised if status reporting interval is invalid. """ with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = {"InterfacePrefix": "blah", "ReportingIntervalSecs": "NaN"} with self.assertRaisesRegexp(ConfigException, "Field was not integer.*"): config.report_etcd_config({}, cfg_dict)
def test_metadata_port_not_int(self): with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "MetadataAddr": "127.0.0.1", "MetadataPort": "bloop" } with self.assertRaisesRegexp(ConfigException, "Field was not integer.*MetadataPort"): config.report_etcd_config({}, cfg_dict)
def test_reporting_interval_not_int(self): """ Test exception is raised if status reporting interval is invalid. """ with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "ReportingIntervalSecs": "NaN"} with self.assertRaisesRegexp(ConfigException, "Field was not integer.*"): config.report_etcd_config({}, cfg_dict)
def test_blank_metadata_addr(self): with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "MetadataAddr": "", "MetadataPort": "123" } with self.assertRaisesRegexp(ConfigException, "Blank value.*MetadataAddr"): config.report_etcd_config({}, cfg_dict)
def test_default_ipset_size(self): """ Test that ipset size is defaulted if out of range. """ with mock.patch("calico.common.complete_logging"): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = {"InterfacePrefix": "blah", "MaxIpsetSize": "0"} with mock.patch("calico.common.complete_logging"): config.report_etcd_config({}, cfg_dict) self.assertEqual(config.MAX_IPSET_SIZE, 2 ** 20)
def main(): common.default_logging(gevent_in_use=False) # The parent process sends us communication pipes as FD 3 and 4. Open # those as files. Wrap the resulting files in a FileObject to make # them cooperate with gevent. pipe_from_parent = os.fdopen(3, 'rb', -1) pipe_to_parent = os.fdopen(4, 'wb', -1) reader = MessageReader(pipe_from_parent) writer = MessageWriter(pipe_to_parent) config = Config() while True: for msg_type, msg, seq_no in reader.new_messages(): _log.info("New %s message (#%s)", msg_type, seq_no) if msg_type == MSG_TYPE_CONFIG_UPDATE: config.update_from(msg.config) elif msg_type == MSG_TYPE_IPSET_DELTA: _log.info("IP set delta message: %s", msg) elif msg_type == MSG_TYPE_IPSET_REMOVED: _log.info("IP set removed message: %s", msg) elif msg_type == MSG_TYPE_IPSET_UPDATE: _log.info("IP set added message: %s", msg) elif msg_type == MSG_TYPE_WL_EP_UPDATE: _log.info("Workload endpoint update message: %s", msg) elif msg_type == MSG_TYPE_WL_EP_REMOVE: _log.info("Workload endpoint remove message: %s", msg) elif msg_type == MSG_TYPE_HOST_EP_UPDATE: _log.info("Host endpoint update message: %s", msg) elif msg_type == MSG_TYPE_HOST_EP_REMOVE: _log.info("Host endpoint update remove: %s", msg) elif msg_type == MSG_TYPE_HOST_METADATA_UPDATE: _log.info("Host endpoint update message: %s", msg) elif msg_type == MSG_TYPE_HOST_METADATA_REMOVE: _log.info("Host endpoint remove message: %s", msg) elif msg_type == MSG_TYPE_IPAM_POOL_UPDATE: _log.info("IPAM pool update messages:%s", msg) elif msg_type == MSG_TYPE_IPAM_POOL_REMOVE: _log.info("IPAM pool remove message: %s", msg) elif msg_type == MSG_TYPE_POLICY_UPDATE: _log.info("Policy update message: %s", msg) elif msg_type == MSG_TYPE_POLICY_REMOVED: _log.info("Policy update message: %s", msg) elif msg_type == MSG_TYPE_PROFILE_UPDATE: _log.info("Profile update message: %s", msg) elif msg_type == MSG_TYPE_PROFILE_REMOVED: _log.info("Profile update message: %s", msg) elif msg_type == MSG_TYPE_IN_SYNC: _log.info("In sync message: %s", msg) else: _log.error("Unexpected message %r %s", msg_type, msg)
def test_bad_metadata_addr(self): with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "MetadataAddr": "bloop", "MetadataPort": "123" } with self.assertRaisesRegexp(ConfigException, "Invalid or unresolvable.*MetadataAddr"): config.report_etcd_config({}, cfg_dict) self.m_gethostbyname.assert_has_calls([mock.call("bloop")])
def test_metadata_port_not_valid_1(self): for i in (0, -1, 99999): log.debug("Test invalid metadata port %d", i) with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "MetadataAddr": "127.0.0.1", "MetadataPort": i } with self.assertRaisesRegexp(ConfigException, "Invalid field value.*MetadataPort"): config.report_etcd_config({}, cfg_dict)
def test_no_metadata(self): # Metadata can be excluded by explicitly saying "none" config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "MetadataAddr": "NoNe", "MetadataPort": 123 } with mock.patch('calico.common.complete_logging'): config.report_etcd_config({}, cfg_dict) # Test defaulting. self.assertEqual(config.METADATA_IP, None) self.assertEqual(config.METADATA_PORT, None)
def test_default_ipset_size(self): """ Test that ipset size is defaulted if out of range. """ with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "MaxIpsetSize": "0", } with mock.patch('calico.common.complete_logging'): config.update_from({}, cfg_dict) self.assertEqual(config.MAX_IPSET_SIZE, 2**20)
def test_negative_reporting_interval(self): """ Test that status reporting is disabled if interval time is negative. """ with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "ReportingIntervalSecs": -42, "ReportingTTLSecs": 7 } with mock.patch('calico.common.complete_logging'): config.report_etcd_config({}, cfg_dict) self.assertEqual(config.REPORTING_INTERVAL_SECS, 0) self.assertEqual(config.REPORTING_TTL_SECS, 0)
def test_valid_interval_and_ttl(self): """ Test valid reporting parameters are not changed. """ with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "ReportingIntervalSecs": 42, "ReportingTTLSecs": 47} with mock.patch('calico.common.complete_logging'): config.report_etcd_config({}, cfg_dict) self.assertEqual(config.REPORTING_INTERVAL_SECS, 42) self.assertEqual(config.REPORTING_TTL_SECS, 47)
def test_reporting_interval_and_ttl_zero(self): """ Test that zero reporting interval and ttl are passed correctly. """ with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "ReportingIntervalSecs": 0, "ReportingTTLSecs": 0} with mock.patch('calico.common.complete_logging'): config.report_etcd_config({}, cfg_dict) self.assertEqual(config.REPORTING_INTERVAL_SECS, 0) self.assertEqual(config.REPORTING_TTL_SECS, 0)
def test_reporting_float(self): """ Test that float reporting interval and ttl values are rounded down to integer. """ with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "ReportingIntervalSecs": 21.75, "ReportingTTLSecs": 63.248} with mock.patch('calico.common.complete_logging'): config.report_etcd_config({}, cfg_dict) self.assertEqual(config.REPORTING_INTERVAL_SECS, 21) self.assertEqual(config.REPORTING_TTL_SECS, 63)
def test_reporting_interval_and_ttl_zero(self): """ Test that zero reporting interval and ttl are passed correctly. """ with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "ReportingIntervalSecs": 0, "ReportingTTLSecs": 0 } with mock.patch('calico.common.complete_logging'): config.report_etcd_config({}, cfg_dict) self.assertEqual(config.REPORTING_INTERVAL_SECS, 0) self.assertEqual(config.REPORTING_TTL_SECS, 0)
def test_valid_interval_and_ttl(self): """ Test valid reporting parameters are not changed. """ with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "ReportingIntervalSecs": 42, "ReportingTTLSecs": 47 } with mock.patch('calico.common.complete_logging'): config.report_etcd_config({}, cfg_dict) self.assertEqual(config.REPORTING_INTERVAL_SECS, 42) self.assertEqual(config.REPORTING_TTL_SECS, 47)
def test_default_ttl(self): """ Test that ttl is defaulted to at least 2.5 times the reporting interval. """ with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "ReportingIntervalSecs": "21", "ReportingTTLSecs": "21", } with mock.patch('calico.common.complete_logging'): config.report_etcd_config({}, cfg_dict) self.assertEqual(config.REPORTING_TTL_SECS, 52)
def test_negative_reporting_interval(self): """ Test that status reporting is disabled if interval time is negative. """ with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "ReportingIntervalSecs": -42, "ReportingTTLSecs": 7 } with mock.patch('calico.common.complete_logging'): config.report_etcd_config({}, cfg_dict) self.assertEqual(config.REPORTING_INTERVAL_SECS, 0) self.assertEqual(config.REPORTING_TTL_SECS, 0)
def test_default_ttl(self): """ Test that ttl is defaulted to at least 2.5 times the reporting interval. """ with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "ReportingIntervalSecs": "21", "ReportingTTLSecs": "21", } with mock.patch('calico.common.complete_logging'): config.report_etcd_config({}, cfg_dict) self.assertEqual(config.REPORTING_TTL_SECS, 52)
def test_no_metadata(self): # Metadata can be excluded by explicitly saying "none" with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "MetadataAddr": "NoNe", "MetadataPort": 123 } with mock.patch('calico.common.complete_logging'): config.report_etcd_config({}, cfg_dict) # Test defaulting. self.assertEqual(config.METADATA_IP, None) self.assertEqual(config.METADATA_PORT, None)
def test_reporting_float(self): """ Test that float reporting interval and ttl values are rounded down to integer. """ with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "ReportingIntervalSecs": 21.75, "ReportingTTLSecs": 63.248 } with mock.patch('calico.common.complete_logging'): config.report_etcd_config({}, cfg_dict) self.assertEqual(config.REPORTING_INTERVAL_SECS, 21) self.assertEqual(config.REPORTING_TTL_SECS, 63)
def main(): try: # Initialise the logging with default parameters. common.default_logging() # Load config # FIXME: old felix used argparse but that's not in Python 2.6, so # hard-coded path. try: config = Config("/etc/calico/felix.cfg") except: # Attempt to open a log file, ignoring any errors it gets, before # we raise the exception. try: common.complete_logging("/var/log/calico/felix.log", logging.DEBUG, logging.DEBUG, logging.DEBUG) except: pass raise _log.info("Felix initializing") gevent.spawn(_main_greenlet, config).join() # Should never return except BaseException: # Make absolutely sure that we exit by asking the OS to terminate our # process. We don't want to let a stray background thread keep us # alive. _log.exception("Felix exiting due to exception") os._exit(1) raise # Unreachable but keeps the linter happy about the broad except.
def load_config(filename, path="calico/felix/test/data/", env_dict=None, host_dict=None, global_dict=None): if env_dict is None: env_dict = {} if host_dict is None: host_dict = {} if global_dict is None: global_dict = {} with mock.patch.dict("os.environ", env_dict): with mock.patch('calico.common.complete_logging'): config = Config(path+filename) with mock.patch('calico.common.complete_logging'): config.report_etcd_config(host_dict, global_dict) return config
def test_no_logfile(self): # Logging to file can be excluded by explicitly saying "none" host = socket.gethostname() host_path = "/calico/host/%s/config/" % host result = StubEtcdResult("/calico/config/") result.add_child("InterfacePrefix", "blah") result.add_child("LogFilePath", "NoNe") result = StubEtcdResult(host_path) config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = { "InterfacePrefix": "blah", "LogFilePath": "None", "ResyncIntervalSecs": "123" } config.update_config(cfg_dict) self.assertEqual(config.LOGFILE, None)
def load_config(filename, path="calico/felix/test/data/", env_dict=None, host_dict=None, global_dict=None): if env_dict is None: env_dict = {} if host_dict is None: host_dict = {} if global_dict is None: global_dict = {} with mock.patch.dict("os.environ", env_dict): with mock.patch('calico.common.complete_logging'): config = Config(path + filename) with mock.patch('calico.common.complete_logging'): config.report_etcd_config(host_dict, global_dict) return config
def test_invalid_port(self): data = { "felix_invalid_port.cfg": "Invalid port in field", "felix_invalid_addr.cfg": "Invalid or unresolvable", "felix_invalid_both.cfg": "Invalid or unresolvable", "felix_invalid_format.cfg": "Invalid format for field" } for filename in data: log.debug("Test filename : %s", filename) with self.assertRaisesRegexp(ConfigException, data[filename]): config = Config("calico/felix/test/data/%s" % filename)
def test_unreadable_etcd_key(self): """ Test that we throw an exception when the etcd key is unreadable """ with nested(mock.patch("os.path.isfile", autospec=True), mock.patch("os.access", autospec=True)) \ as (m_isfile, m_access): m_isfile.return_value = True m_access.return_value = False with self.assertRaisesRegexp(ConfigException, "Cannot read key file"): config = Config("calico/felix/test/data/felix_unreadable_key.cfg")
def test_unreadable_etcd_ca(self): """ Test that we throw an exception when the etcd CA cert is unreadable """ with nested(mock.patch("os.path.isfile", autospec=True), mock.patch("os.access", autospec=True)) \ as (m_isfile, m_access): m_isfile.return_value = True m_access.side_effect = iter([True, True, False]) with self.assertRaisesRegexp(ConfigException, "Missing CA certificate"): config = Config("calico/felix/test/data/felix_unreadable_ca.cfg")
def test_no_logfile(self): # Logging to file can be excluded by explicitly saying "none" - # but if in etcd config the file is still created. with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/felix_missing.cfg") cfg_dict = {"InterfacePrefix": "blah", "LogFilePath": "None"} with mock.patch('calico.common.complete_logging'): config.report_etcd_config({}, cfg_dict) self.assertEqual(config.LOGFILE, None) config = Config("calico/felix/test/data/felix_nolog.cfg") cfg_dict = {"InterfacePrefix": "blah"} config.report_etcd_config({}, cfg_dict) self.assertEqual(config.LOGFILE, None)
def test_invalid_etcd(self): """ Test that etcd validation works correctly. """ data = { "felix_invalid_scheme.cfg": "Invalid protocol scheme", "felix_missing_key.cfg": "Missing etcd key", "felix_missing_cert.cfg": "Missing etcd certificate" } for filename in data: log.debug("Test filename : %s", filename) with self.assertRaisesRegexp(ConfigException, data[filename]): config = Config("calico/felix/test/data/%s" % filename)
def main(): # Initialise the logging with default parameters. common.default_logging(gevent_in_use=True) # Create configuration, reading defaults from file if it exists. parser = optparse.OptionParser() parser.add_option('-c', '--config-file', dest='config_file', help="configuration file to use", default="/etc/calico/felix.cfg") options, args = parser.parse_args() try: config = Config(options.config_file) except Exception: # Config loading error, and not just invalid parameters (from optparse) # as they generate a SystemExit. Attempt to open a log file, ignoring # any errors it gets, before we raise the exception. try: common.complete_logging("/var/log/calico/felix.log", logging.DEBUG, logging.DEBUG, logging.DEBUG, gevent_in_use=True) except Exception: pass # Log the exception with logging in whatever state we managed to get it # to, then reraise it, taking Felix down. _log.exception("Exception loading configuration") raise _log.info("Felix initializing") try: gevent.spawn(_main_greenlet, config).join() # Should never return except Exception: # Make absolutely sure that we exit by asking the OS to terminate our # process. We don't want to let a stray background thread keep us # alive. _log.exception("Felix exiting due to exception") os._exit(1) raise # Unreachable but keeps the linter happy about the broad except.
def test_file_sections(self): """ Test various ways of defaulting config. """ files = [ "felix_section.cfg", # lots of sections ] for filename in files: with mock.patch('calico.common.complete_logging'): config = Config("calico/felix/test/data/%s" % filename) # Test that read ignoring sections. self.assertEqual(config.ETCD_ADDR, "localhost:4001") self.assertEqual(config.HOSTNAME, socket.gethostname()) self.assertEqual(config.LOGFILE, "/log/nowhere.log") self.assertEqual(config.IFACE_PREFIX, "whatever") self.assertEqual(config.METADATA_PORT, 246) self.assertEqual(config.METADATA_IP, "1.2.3.4")
def test_bad_localaddr(self): with self.assertRaisesRegexp(ConfigException, "Invalid or unresolvable LocalAddress"): config = Config("calico/felix/test/data/felix_bad_localaddr.cfg")