def test_env_var_in_include_2_levels_dont_set(self): settings.CONFIG_FILE = 'tests/fixtures/config_with_include_and_env_vars.yaml' settings.GET_ENVIRON_STRICT = True with self.assertRaises(RuntimeError): config.load_context_section('section-1') settings.GET_ENVIRON_STRICT = False
def test_config_is_empty(self): settings.CONFIG_FILE = 'tests/fixtures/empty_config.yaml' with self.assertRaises(RuntimeError) as context: config.load_context_section('section') self.assertTrue( 'Config file "tests/fixtures/empty_config.yaml" is empty' in str( context.exception))
def test_check_empty_var(self): settings.CONFIG_FILE = 'tests/fixtures/config.yaml' settings.GET_ENVIRON_STRICT = True with self.assertRaises(RuntimeError) as context: config.load_context_section('deployment') settings.GET_ENVIRON_STRICT = False self.assertTrue('Environment variable "EMPTY_ENV" is not set' in str( context.exception))
def test_dashes_in_var_names(self): settings.TEMPLATES_DIR = 'templates_tests' settings.CONFIG_FILE = 'tests/fixtures/dashes_config.yaml' with self.assertRaises(RuntimeError) as context: config.load_context_section('section') self.assertTrue( 'Variable names should never include dashes, ' 'check your vars, please: my-nested-var, my-var, your-var' in str(context.exception), context.exception)
def test_env_var_in_section2_dont_set(self): settings.CONFIG_FILE = 'tests/fixtures/config_with_env_vars.yaml' settings.GET_ENVIRON_STRICT = True with self.assertRaises(RuntimeError) as context: config.load_context_section('section-2') settings.GET_ENVIRON_STRICT = False self.assertTrue('Environment variable "SECTION2" is not set' in str( context.exception))
def test_generate_templates(self): r = templating.Renderer( os.path.join(os.path.dirname(__file__), 'templates_tests')) context = config.load_context_section('test_dirs') r.generate_by_context(context) file_path_1 = '{}/template1.yaml'.format(settings.TEMP_DIR) file_path_2 = '{}/template2.yaml'.format(settings.TEMP_DIR) file_path_3 = '{}/template3.yaml'.format(settings.TEMP_DIR) file_path_4 = '{}/innerdir/template1.yaml'.format(settings.TEMP_DIR) file_path_5 = '{}/template_include_file.yaml'.format(settings.TEMP_DIR) self.assertTrue(os.path.exists(file_path_1)) self.assertTrue(os.path.exists(file_path_2)) self.assertTrue(os.path.exists(file_path_3)) with open(file_path_1, 'r') as f: content = f.read() self.assertEqual(content, "{'ha_ha': 'included_var'}") with open(file_path_2, 'r') as f: content = f.read() self.assertEqual(content, 'TXkgdmFsdWU=') with open(file_path_3, 'r') as f: content = f.read() self.assertEqual(content, 'My value') with open(file_path_4, 'r') as f: content = f.read() self.assertEqual(content, "{'ha_ha': 'included_var'}") with open(file_path_5, 'r') as f: content = f.read() self.assertEqual( content, "test: |\n {{ hello world }}\n new\n line\n {{ hello world1 }}\n" )
def test_merge_section_options(self): settings.TEMPLATES_DIR = 'templates_tests' c = config.load_context_section('test_dirs') self.assertEqual(c['my_var'], 'my_value') self.assertEqual(c['my_env_var'], 'My value') self.assertEqual(c['my_file'], {'ha_ha': 'included_var'}) self.assertTrue(c['dirs'])
def test_no_templates_in_kubectl(self): r = templating.Renderer( os.path.join(os.path.dirname(__file__), 'templates_tests')) with self.assertRaises(RuntimeError) as context: r.generate_by_context(config.load_context_section('no_templates')) self.assertTrue('Templates section doesn\'t have any template items' in str(context.exception))
def test_io_2709(self): r = templating.Renderer( os.path.join(os.path.dirname(__file__), 'templates_tests')) with self.assertRaises(TemplateRenderingError) as context: c = config.load_context_section('io_2709') r.generate_by_context(c) self.assertTrue('due to: \'undefined_variable\' is undefined' in str( context.exception))
def test_recursive_vars(self): settings.TEMPLATES_DIR = 'templates_tests' c = config.load_context_section('test_recursive_vars') self.assertEqual({'router': { 'my': 'var', 'my1': 'var1', 'your': 2 }}, c['var'])
def test_render_not_existent_template(self): r = templating.Renderer( os.path.join(os.path.dirname(__file__), 'templates_tests')) with self.assertRaises(TemplateRenderingError) as context: r.generate_by_context( config.load_context_section('not_existent_template')) self.assertTrue('doesnotexist.yaml.j2' in str(context.exception), context.exception)
def test_check_k8s_settings(self): settings.CONFIG_FILE = 'tests/fixtures/config_without_k8s.yaml' c = config.load_context_section('deployment') with self.assertRaises(RuntimeError) as context: config.check_required_vars(c, [ 'k8s_master_uri', 'k8s_token', 'k8s_ca_base64', 'k8s_namespace' ]) self.assertTrue( 'Variables "k8s_token, k8s_ca_base64" not found ' '(or empty)' in str(context.exception), )
def test_concatination_with_env(self): settings.TEMPLATES_DIR = 'templates_tests' c = config.load_context_section('test_dirs') self.assertEqual(c['my_conc_env_var1'], 'prefix-My value-postfix') self.assertEqual(c['my_conc_env_var2'], 'prefix-My value') self.assertEqual(c['my_conc_env_var3'], 'My value-postfix')
def main(): # INFO furiousassault: backward compatibility rough attempt # must be removed later according to https://github.com/2gis/k8s-handle/issues/40 deprecation_warnings = 0 filtered_arguments = [] for argument in sys.argv[1:]: if argument in [ '--sync-mode=true', '--sync-mode=True', '--dry-run=true', '--dry-run=True' ]: deprecation_warnings += 1 filtered_arguments.append(argument.split('=')[0]) continue if argument in [ '--sync-mode=false', '--sync-mode=False', '--dry-run=false', '--dry-run=False' ]: deprecation_warnings += 1 continue filtered_arguments.append(argument) args, unrecognized_args = parser.parse_known_args(filtered_arguments) if deprecation_warnings or unrecognized_args: log.warning( "Explicit true/false arguments to --sync-mode and --dry-run keys are deprecated " "and will be discontinued in the future. Use these keys without arguments instead." ) args = vars(args) kubeconfig_namespace = None settings.CHECK_STATUS_TRIES = args.get('tries') settings.CHECK_DAEMONSET_STATUS_TRIES = args.get('tries') settings.CHECK_STATUS_TIMEOUT = args.get('retry_delay') settings.CHECK_DAEMONSET_STATUS_TIMEOUT = args.get('retry_delay') settings.GET_ENVIRON_STRICT = args.get('strict') settings.COUNT_LOG_LINES = args.get('tail_lines') settings.CONFIG_FILE = args.get('config') or settings.CONFIG_FILE try: context = config.load_context_section(args['section']) render = templating.Renderer(settings.TEMPLATES_DIR) resources = render.generate_by_context(context) evaluator = config.PriorityEvaluator(args, context, os.environ) if evaluator.environment_deprecated(): log.warning( "K8S_HOST and K8S_CA environment variables support is deprecated " "and will be discontinued in the future. Use K8S_MASTER_URI and K8S_CA_BASE64 instead." ) if args.get('dry_run'): return # INFO rvadim: https://github.com/kubernetes-client/python/issues/430#issuecomment-359483997 if args.get('use_kubeconfig'): try: load_kube_config() kubeconfig_namespace = list_kube_config_contexts()[1].get( 'context').get('namespace') except Exception as e: raise RuntimeError(e) else: client.Configuration.set_default( evaluator.k8s_client_configuration()) settings.K8S_NAMESPACE = evaluator.k8s_namespace_default( kubeconfig_namespace) log.info('Default namespace "{}"'.format(settings.K8S_NAMESPACE)) if not settings.K8S_NAMESPACE: log.info( "Default namespace is not set. " "This may lead to provisioning error, if namespace is not set for each resource." ) p = Provisioner(args['command'], args.get('sync_mode'), args.get('show_logs')) d = ApiDeprecationChecker( client.VersionApi().get_code().git_version[1:]) for resource in resources: d.run(resource) for resource in resources: p.run(resource) except templating.TemplateRenderingError as e: log.error('Template generation error: {}'.format(e)) sys.exit(1) except InvalidYamlError as e: log.error('{}'.format(e)) sys.exit(1) except DeprecationError as e: log.error('Deprecation warning: {}'.format(e)) sys.exit(1) except RuntimeError as e: log.error('RuntimeError: {}'.format(e)) sys.exit(1) except ProvisioningError: sys.exit(1) print(r''' _(_)_ wWWWw _ @@@@ (_)@(_) vVVVv _ @@@@ (___) _(_)_ @@()@@ wWWWw (_)\ (___) _(_)_ @@()@@ Y (_)@(_) @@@@ (___) `|/ Y (_)@(_) @@@@ \|/ (_) / Y \| \|/ /(_) \| |/ | \ | \ |/ | / \ | / \|/ |/ \| \|/ \|// \|/// \|// \|/// \|/// \|// |// \|// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^''')
def test_common_section(self): with self.assertRaises(RuntimeError) as context: config.load_context_section(settings.COMMON_SECTION_NAME) self.assertTrue('Section "{}" is not intended to deploy'.format( settings.COMMON_SECTION_NAME) in str(context.exception))
def test_no_templates(self): with self.assertRaises(RuntimeError) as context: config.load_context_section('no_templates_section') self.assertTrue( 'Section "templates" or "kubectl" not found in config file' in str( context.exception))
def test_not_existed_section(self): with self.assertRaises(RuntimeError) as context: config.load_context_section('absent_section') self.assertTrue( 'Section "absent_section" not found' in str(context.exception))
def test_config_incorrect(self): settings.CONFIG_FILE = 'tests/fixtures/incorrect_config.yaml' with self.assertRaises(InvalidYamlError): config.load_context_section('section')
def test_config_not_exist(self): settings.CONFIG_FILE = 'tests/config.yaml' with self.assertRaises(Exception) as context: config.load_context_section('section') self.assertTrue('No such file or directory: \'tests/config.yaml\'' in str(context.exception))
def main(): # INFO furiousassault: backward compatibility rough attempt # must be removed later according to https://github.com/2gis/k8s-handle/issues/40 deprecation_warnings = 0 filtered_arguments = [] for argument in sys.argv[1:]: if argument in ['--sync-mode=true', '--sync-mode=True', '--dry-run=true', '--dry-run=True']: deprecation_warnings += 1 filtered_arguments.append(argument.split('=')[0]) continue if argument in ['--sync-mode=false', '--sync-mode=False', '--dry-run=false', '--dry-run=False']: deprecation_warnings += 1 continue filtered_arguments.append(argument) args, unrecognized_args = parser.parse_known_args(filtered_arguments) if deprecation_warnings or unrecognized_args: log.warning("Explicit true/false arguments to --sync-mode and --dry-run keys are deprecated " "and will be removed in the future. Use these keys without arguments instead.") if 'config' in args and args.config: settings.CONFIG_FILE = args.config if 'tries' in args: settings.CHECK_STATUS_TRIES = args.tries settings.CHECK_DAEMONSET_STATUS_TRIES = args.tries if 'retry_delay' in args: settings.CHECK_STATUS_TIMEOUT = args.retry_delay settings.CHECK_DAEMONSET_STATUS_TIMEOUT = args.retry_delay if 'strict' in args: settings.GET_ENVIRON_STRICT = args.strict if 'tail_lines' in args: settings.COUNT_LOG_LINES = args.tail_lines show_logs = False if 'show_logs' in args: show_logs = args.show_logs try: context = config.load_context_section(args.section) render = templating.Renderer(settings.TEMPLATES_DIR) resources = render.generate_by_context(context) # INFO rvadim: https://github.com/kubernetes-client/python/issues/430#issuecomment-359483997 if args.dry_run: return if 'use_kubeconfig' in args and args.use_kubeconfig: load_kube_config() namespace = list_kube_config_contexts()[1].get('context').get('namespace') if not namespace: raise RuntimeError("Unable to determine namespace of current context") settings.K8S_NAMESPACE = namespace else: Configuration.set_default(get_client_config(context)) check_required_vars(context, ['k8s_master_uri', 'k8s_token', 'k8s_ca_base64', 'k8s_namespace']) if context.get('k8s_namespace'): settings.K8S_NAMESPACE = context.get('k8s_namespace') log.info('Default namespace "{}"'.format(settings.K8S_NAMESPACE)) p = Provisioner(args.command, args.sync_mode, show_logs) d = ApiDeprecationChecker(VersionApi().get_code().git_version[1:]) for resource in resources: d.run(resource) for resource in resources: p.run(resource) except templating.TemplateRenderingError as e: log.error('Template generation error: {}'.format(e)) sys.exit(1) except InvalidYamlError as e: log.error('{}'.format(e)) sys.exit(1) except DeprecationError as e: log.error('Deprecation warning: {}'.format(e)) sys.exit(1) except RuntimeError as e: log.error('RuntimeError: {}'.format(e)) sys.exit(1) except ProvisioningError: sys.exit(1) print(''' _(_)_ wWWWw _ @@@@ (_)@(_) vVVVv _ @@@@ (___) _(_)_ @@()@@ wWWWw (_)\ (___) _(_)_ @@()@@ Y (_)@(_) @@@@ (___) `|/ Y (_)@(_) @@@@ \|/ (_) / Y \| \|/ /(_) \| |/ | \ | \ |/ | / \ | / \|/ |/ \| \|/ \|// \|/// \|// \|/// \|/// \|// |// \|// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^''')
def test_infinite_recursion_loop(self): settings.CONFIG_FILE = 'tests/fixtures/config_with_include_and_env_vars.yaml' with self.assertRaises(RuntimeError): config.load_context_section('section-3')